Springboot+poi導出Excel

Springboot+poi導出Excel數據庫

1、引入jar包apache

注意須要引入3.8版本,POI3.8提供了SXSSFWorkbook類,來處理大數據內存溢出的問題.可設置默認內存大小,多出的部分可存入硬盤中,不會內存溢出.

<!-- poi依賴 -->
<dependency>    
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.8</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.8</version>
</dependency>

2、編寫poi工具類json

工具類的核心在於,將從數據庫查詢出來的bean對象,轉化成json對象,而後經過bean中的字段去獲取出json對象的值,

再依次寫入每一個單元格.本工具類兼容中文,對中文亂碼等問題單獨處理.導出所對應的字段key可保存在數據庫中.瀏覽器

/**
     * Description: 一、將list中的data寫入表格中
     * 
     * @param messageService
     *            國際化對象
     * @param keyName
     *            導出文件的key值
     * @param list
     *            數據庫查詢出的Bean集合
     * @param fieldNames
     *            查詢出的字段list
     * @return
     * @author: yizl
     * @date: Oct 30, 2018 1:08:08 PM
     */
    public static <T, S> SXSSFWorkbook export(LocaleMessageSourceService messageService,
                                              String keyName, List<T> list,
                                              List<String> fieldNames)
    {
        // 內存中保留 10000 條數據,以避免內存溢出,其他寫入 硬盤
        SXSSFWorkbook wb = new SXSSFWorkbook(2000);
        // 建立一個Excel的sheet
        Sheet sheet = wb.createSheet(messageService.getMessage(keyName));
        for (int j = 0; j <= list.size(); j++ )
        {
            Row row = sheet.createRow(j);// 第j行
            JSONObject jsonObj = null;
            if (j != 0)
            {

                jsonObj = (JSONObject)JSON.toJSON(list.get(j - 1));
            }
            for (int k = 0; k < fieldNames.size(); k++ )
            {
                // 第一列單元格
                Cell cell = row.createCell(k);
                // 第一行
                if (j == 0)
                {
                    CellStyle style = getColumnTopStyle(wb);
                    cell.setCellStyle(style);
                    // 第一列數據
                    cell.setCellValue(
                        //將表頭國際化
                        messageService.getMessage(keyName + "." + fieldNames.get(k)));
                }
                else
                {
                    // 將bean對象轉換成JSON對象
                    String content = jsonObj.getString(fieldNames.get(k));
                    if (content == null)
                    {
                        content = "";
                    }
                    CellStyle style = getBodyStyle(wb);
                    cell.setCellStyle(style);
                    cell.setCellValue(content);
                }
            }

        }

        /*
         * for (int k = 0; k < fieldNames.size(); k++ ) { 
         * // poi提供的自動調整每列的寬度,可是不兼容中文調整
         * sheet.autoSizeColumn(k); }
         */
        setSizeColumn(sheet, fieldNames.size());
        return wb;
    }

    /**
     * Description: 一、調整列寬,兼容中文
     * 
     * @param sheet
     * @param size
     * @author: yizl
     * @date: Nov 1, 2018 11:31:56 AM
     */
    private static void setSizeColumn(Sheet sheet, int size)
    {
        for (int columnNum = 0; columnNum < size; columnNum++ )
        {
            int columnWidth = sheet.getColumnWidth(columnNum) / 256;
            for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++ )
            {
                Row currentRow;
                // 當前行未被使用過
                if (sheet.getRow(rowNum) == null)
                {
                    currentRow = sheet.createRow(rowNum);
                }
                else
                {
                    currentRow = sheet.getRow(rowNum);
                }

                if (currentRow.getCell(columnNum) != null)
                {
                    Cell currentCell = currentRow.getCell(columnNum);
                    if (currentCell.getCellType() == Cell.CELL_TYPE_STRING)
                    {
                        int length = currentCell.getStringCellValue().getBytes().length;
                        if (columnWidth < length)
                        {
                            columnWidth = length;
                        }
                    }
                }
            }

            // Excel的長度爲字節碼長度*256,*1.3爲了處理數字格式
            columnWidth = (int)Math.floor(columnWidth * 256 * 1.3);
            //單元格長度大於20000的話也不美觀,設置個最大長度
            columnWidth = columnWidth >= 20000 ? 20000 : columnWidth;
            //設置每列長度
            sheet.setColumnWidth(columnNum, columnWidth);
        }
    }

    /**
     * Description: 一、經過瀏覽器workbook以流的形式輸出,爲了處理中文表名路是你嗎問題.
     * 
     * @param workbook
     *            文件對象
     * @param request
     * @param response
     * @param fileName
     *            文件名
     * @author: yizl
     * @date: Oct 30, 2018 1:06:27 PM
     */
    public static void writeToResponse(SXSSFWorkbook workbook, HttpServletRequest request,
                                       HttpServletResponse response, String fileName)
    {
        try
        {
            String userAgent = request.getHeader("User-Agent");
            // 解決中文亂碼問題
            String fileName1 = "Excel-" + fileName + ".xlsx";
            String newFilename = URLEncoder.encode(fileName1, "UTF8");
            // 若是沒有userAgent,則默認使用IE的方式進行編碼,由於畢竟IE仍是佔多數的
            String rtn = "filename=\"" + newFilename + "\"";
            if (userAgent != null)
            {
                userAgent = userAgent.toLowerCase();
                // IE瀏覽器,只能採用URLEncoder編碼
                if (userAgent.indexOf(IE) != -1)
                {
                    rtn = "filename=\"" + newFilename + "\"";
                }
                // Opera瀏覽器只能採用filename*
                else if (userAgent.indexOf(OPERA) != -1)
                {
                    rtn = "filename*=UTF-8''" + newFilename;
                }
                // Safari瀏覽器,只能採用ISO編碼的中文輸出
                else if (userAgent.indexOf(SAFARI) != -1)
                {
                    rtn = "filename=\"" + new String(fileName1.getBytes("UTF-8"), "ISO8859-1")
                          + "\"";
                }
                // FireFox瀏覽器,可使用MimeUtility或filename*或ISO編碼的中文輸出
                else if (userAgent.indexOf(FIREFOX) != -1)
                {
                    rtn = "filename*=UTF-8''" + newFilename;
                }
            }

            String headStr = "attachment;  " + rtn;
            response.setContentType("APPLICATION/ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", headStr);
            // 響應到客戶端
            OutputStream os = response.getOutputStream();
            workbook.write(os);
        }
        catch (UnsupportedEncodingException e)
        {

            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    /**
     * Description: 一、列頭單元格樣式
     * 
     * @param workbook
     * @return
     * @author: yizl
     * @date: Oct 30, 2018 1:22:44 PM
     */
    public static CellStyle getColumnTopStyle(SXSSFWorkbook workbook)
    {

        // 設置字體
        Font font = workbook.createFont();
        // 設置字體大小
        font.setFontHeightInPoints((short)11);
        // 字體加粗
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 設置字體名字
        font.setFontName("Courier New");
        // 設置樣式;
        CellStyle style = workbook.createCellStyle();
        // 設置底邊框;
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        // 設置底邊框顏色;
        style.setBottomBorderColor(HSSFColor.BLACK.index);
        // 設置左邊框;
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        // 設置左邊框顏色;
        style.setLeftBorderColor(HSSFColor.BLACK.index);
        // 設置右邊框;
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        // 設置右邊框顏色;
        style.setRightBorderColor(HSSFColor.BLACK.index);
        // 設置頂邊框;
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 設置頂邊框顏色;
        style.setTopBorderColor(HSSFColor.BLACK.index);
        // 在樣式用應用設置的字體;
        style.setFont(font);
        // 設置自動換行;
        style.setWrapText(false);
        // 設置水平對齊的樣式爲居中對齊;
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 設置垂直對齊的樣式爲居中對齊;
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        return style;
    }

    /**
     * Description: 一、設置表體的單元格樣式
     * 
     * @param workbook
     * @return
     * @author: yizl
     * @date: Oct 30, 2018 1:18:42 PM
     */
    private static CellStyle getBodyStyle(SXSSFWorkbook workbook)
    {
        // 建立單元格樣式
        CellStyle cellStyle = workbook.createCellStyle();
        // 設置單元格居中對齊
        cellStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
        // 設置單元格居中對齊
        cellStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
        // 建立單元格內容不顯示自動換行
        cellStyle.setWrapText(false);
        // 設置單元格字體樣式
        XSSFFont font = (XSSFFont)workbook.createFont();
        font.setFontName("Courier New");// 設置字體
        font.setFontHeight(11);// 設置字體的大小
        cellStyle.setFont(font);// 將字體添加到表格中去
        // 設置單元格邊框爲細線條
        cellStyle.setBorderLeft(XSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderBottom(XSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderRight(XSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderTop(XSSFCellStyle.BORDER_THIN);
        return cellStyle;
    }

3、編寫controller層app

獲取SXSSFWorkbook對象,在進行輸出。request獲取用戶使用的瀏覽器內核類型。經過這個字段設置表名的編碼格式,從而兼容不一樣瀏覽器。

     @GetMapping("/getCameraListExcel")
    public void getCameraListExcel(Camera camera)
    {
        long startTime = System.currentTimeMillis();
        ServletRequestAttributes servletRequestAttributes =                                 
        (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        SXSSFWorkbook workbook = service.getCameraListExcel(camera);
       //以流輸出到瀏覽器
       POIUtil.writeToResponse(workbook, request, response,
            messageService.getMessage(ExcelConstant.EXPORTCAMERA));
        long endTime = System.currentTimeMillis();
        System.out.println("運行時間:" + (endTime - startTime) + "ms");
    }

4、編寫service層工具

字段的key集合,保存在數據庫中,每列對應一個key,表頭經過這個key可獲取出來(實現導出Excel國際化),表體的內容經過這個key獲取出json對象。

    /**
     * Description: 一、獲取Camera對象放入excel中
     * 
     * @param camera
     * @return
     * @author: yizl
     * @date: Nov 3, 2018 1:33:05 PM
     */
    public SXSSFWorkbook getCameraListExcel(Camera camera)
    {
        // 字段名Key
        List<String> fieldNames = mapper.getExcelConfig();
        List<Camera> cameraList= mapper.getCameraListExcel(camera);
        SXSSFWorkbook workbook = POIUtil.export(messageService, ExcelConstant.EXPORTCAMERA,
            cameraList, fieldNames);
        return workbook;
    }

5、總結字體

設置樣式的話可根據需求進行調整,這個過程比較費時,導出7000條數據,無樣式在2s左右,有樣式須要3分鐘。
相關文章
相關標籤/搜索