1. 程式人生 > 實用技巧 >Spring Boot專案基於POI框架匯出Excel表格

Spring Boot專案基於POI框架匯出Excel表格

1. 依賴

我的專案是基於Spring Boot的,這裡只貼出POI框架需要依賴的兩個包,其他的都無所謂,只要能提供Controller讓瀏覽器訪問即可。在pom.xml配置檔案中增加如下兩個包:

       <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>
        <!-- https://
mvnrepository.com/artifact/org.apache.poi/poi-ooxml --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency>

2. 程式碼實現

package com.eg.wiener.controller;

import com.eg.wiener.dto.User; import com.eg.wiener.utils.ExcelUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Stream; /** * @author Wiener * @date 2020/9/5 */ @Slf4j @RestController @RequestMapping("/excel") public class ExcelExportController { private static HSSFWorkbook workbook = null; // 代表一行記錄 private static HSSFCell cell = null; private static HSSFRow row = null; @RequestMapping(value = "/exportExcel") public Object exportExcel(HttpServletRequest request, HttpServletResponse response) throws Exception { String fileSuffix = ".xls"; String fileName = "匯出資料至Excel示例"+ "_" + (int) (Math.random() * 9000 + 1000) + ".xls"; //【1】建立excel workbook = new HSSFWorkbook(); // 設定表頭的型別 HSSFCellStyle style = setCellStyle(workbook); // 建立一個sheet HSSFSheet sheet = workbook.createSheet("sheet1"); try { List<User> dataList = getUsers(); if (CollectionUtils.isNotEmpty(dataList)) { //【2】 設定表頭:對Excel每列命名 String[] tableHeader = Stream.of("編號", "姓名", "年齡").toArray(String[]::new); // 設定Excel表頭 row = ExcelUtils.getExcelRow(workbook, sheet, tableHeader); //通過反射,獲取POJO物件。由於同一個dataList中,POJO相同,故定義在for迴圈外部,提高遍歷效能 Class cl = dataList.get(0).getClass(); //獲取類的所有欄位 Field[] fields = cl.getDeclaredFields(); //寫入每一行的記錄 for (int i = 0; i < dataList.size(); i++) { //建立新的一行,遞增 row = sheet.createRow(i + 1); // 設定行高 row.setHeight((short) 400); for (int j = 0; j < fields.length; j++) { //設定欄位可見,否則會報錯,禁止訪問 fields[j].setAccessible(true); //建立單元格 cell = row.createCell(j); cell.setCellValue(Objects.toString(fields[j].get(dataList.get(i)), "")); cell.setCellStyle(style); } } } else { // 沒有查到資料提示行 row = ExcelUtils.getNotResultInfoRow(workbook, sheet, "記錄為空"); } } catch (Exception e) { log.error("匯出資料失敗:", e); // 寫入Excel失敗原因 row = ExcelUtils.getNotResultInfoRow(workbook, sheet, "匯出資料失敗"); fileName = "匯出資料失敗"; } fileName = fileName + "_" + (int) (Math.random() * 9000 + 1000) + fileSuffix; //下載檔案 ExcelUtils.outputExcelStream(request, response, workbook, fileName); return "匯出成功"; } private List<User> getUsers() { List<User> list = new ArrayList<>(); User aUser = new User(); aUser.setAge(18); aUser.setId(1); aUser.setName("Tony"); list.add(aUser); aUser = new User(); aUser.setAge(21); aUser.setId(2); aUser.setName("Tom"); list.add(aUser); aUser = new User(); aUser.setAge(20); aUser.setId(3); aUser.setName("店小二"); list.add(aUser); return list; } private HSSFCellStyle setCellStyle(HSSFWorkbook myWorkbook) { HSSFCellStyle style = myWorkbook.createCellStyle(); //設定自動換行 style.setWrapText(true); style.setAlignment(HorizontalAlignment.CENTER); //設定邊框樣式 style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.THIN); //設定邊框顏色 style.setTopBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex()); style.setBottomBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex()); style.setLeftBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex()); style.setRightBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex()); HSSFDataFormat format = workbook.createDataFormat(); // 設定文字格式 style.setDataFormat(format.getFormat("@")); // 設定字型 HSSFFont font = workbook.createFont(); font.setColor(Font.COLOR_RED); font.setFontName("宋體"); font.setFontHeightInPoints((short) 12);// 12號字型 style.setFont(font); return style; } }

通過反射獲取POJO物件,故傳入不同型別的POJO物件的dataList就可以了。下面是依賴的一個工具類:

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

/**
 * 匯出Excel工具類
 *
 * @author Wiener
 * @date 2020/9/5
 */
@Slf4j
public class ExcelUtils {

    /**
     * 設定Excel表頭
     *
     * @param workbook
     * @param sheet
     * @param tableHeader
     * @return
     */
    public static HSSFRow getExcelRow(HSSFWorkbook workbook, HSSFSheet sheet, String[] tableHeader) {
        short cellNumber = (short) tableHeader.length;
        // Excel的第一行表頭
        HSSFRow row = sheet.createRow(0);
        // 設定行高
        row.setHeight((short) 560);
        // Excel的列
        HSSFCell cell = null;
        HSSFFont font = workbook.createFont();
        // 粗體顯示
        font.setBold(Boolean.TRUE);
        font.setFontHeightInPoints((short) 15);
        // 設定單元格字型的顏色
        font.setColor(HSSFFont.COLOR_NORMAL);
        // 樣式
        HSSFCellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        //設定邊框樣式
        style.setBorderTop(BorderStyle.DOTTED);
        style.setBorderBottom(BorderStyle.DOTTED);
        style.setBorderLeft(BorderStyle.DOTTED);
        style.setBorderRight(BorderStyle.DOTTED);
        //設定邊框顏色
        style.setTopBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
        style.setBottomBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
        style.setLeftBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
        style.setRightBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());

        for (int k = 0; k < cellNumber; k++) {
            int i = 0;
            i += k;
            short b = 6000;
            cell = row.createCell(i);                       // 建立第0行第k列
            cell.setCellValue(tableHeader[k]);              // 設定第0行第k列的值
            sheet.setColumnWidth(i, b);                     // 設定列的寬度
            style.setFont(font);                           // 設定字型風格
            cell.setCellStyle(style);
        }
        return row;
    }

    /**
     * 設定Excel未獲取資料提示行
     *
     * @param workbook
     * @param sheet
     * @return
     */
    public static HSSFRow getNotResultInfoRow(HSSFWorkbook workbook, HSSFSheet sheet, String message) {
        // Excel的第一行表頭
        HSSFRow row = sheet.createRow(0);
        // Excel的列
        HSSFCell cell = null;
        // 設定表頭的型別
        HSSFCellStyle style = workbook.createCellStyle();
        //設定自動換行
        style.setWrapText(true);
        style.setAlignment(HorizontalAlignment.CENTER);

        // 沒有查到資料
        row = sheet.createRow((short) (0));             // 建立第j+1行
        row.setHeight((short) 1000);                    // 設定行高
        sheet.setColumnWidth(0, 10000);
        cell = row.createCell(0);                       // 建立第i+1行第1列
        cell.setCellValue(message);//
        cell.setCellStyle(style);                       // 設定風格

        return row;
    }

    /**
     * 下載EXCEL,對不同瀏覽器做中文名稱相容<br/>
     * 如果不對檔名進行編碼處理,那麼有些瀏覽器無法識別下載檔案
     *
     * @param request
     * @param response
     * @param workbook
     * @param fileName
     */
    public static void outputExcelStream(HttpServletRequest request, HttpServletResponse response, HSSFWorkbook workbook, String fileName) {
        OutputStream out = null;
        try {
            String excelFileName = fileName + "_" + (int) (Math.random() * 9000 + 1000) + ".xls";
            if (isMsBrowser(request)) {
                // ie,edge 瀏覽器
                excelFileName = URLEncoder.encode(excelFileName, "UTF-8");
            } else {
                //其他的瀏覽器
                excelFileName = new String(excelFileName.getBytes("UTF-8"), "iso-8859-1");
            }
            //輸出流物件
            out = response.getOutputStream();
            // 設定檔案頭編碼方式和檔名
            response.setHeader("Content-Disposition", "attachment;filename=" + excelFileName);
            // 設定型別
            response.setContentType("application/msexcel;charset=UTF-8");
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            workbook.write(out);
            out.flush();
            workbook.write(out);
        } catch (IOException e) {
            log.error("下載EXCEL失敗,", e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                log.error("下載EXCEL關閉檔案流失敗,", e);
            }
        }
    }

    //判斷是否是IE瀏覽器
    private static boolean isMsBrowser(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        if (StringUtils.isBlank(userAgent)) {
            return false;
        }
        String[] IEBrowserSignals = {"msie", "trident", "edge"};
        for (String signal : IEBrowserSignals) {
            if (userAgent.toLowerCase().contains(signal)) {
                return true;
            }
        }
        return false;
    }

}

在使用的時候,僅僅需要傳入不同的表頭集合、實體類集合,就能實現需求,這就是封裝的魅力所在。