1. 程式人生 > >Apache poi 複雜表頭匯出

Apache poi 複雜表頭匯出

本來公司是有一套自己的Excel匯出工具,他是基於EasyPoi,奈何整合的EasyPoi版本過低,不支援一些複雜表頭,只好用Apache poi 的這套框架來做,當然EasyPoi也是基於Apache poi 封裝的

我參考的是這篇文章

但是對於這篇博文有一些問題,自己又在上面按照自己的理解改了一下,也達到了與原博主相同的效果

修改後的程式碼如下:

public HSSFWorkbook export(List list) {

    // 宣告String陣列,並初始化元素(表頭名稱)
    //第一行表頭欄位,合併單元格時欄位跨幾列就將該欄位重複幾次
    String[] excelHeader0 = {
            "城市名稱",
            "監測點",
            "汙染物濃度及空氣質量分指數(AQI)", "汙染物濃度及空氣質量分指數(AQI)","汙染物濃度及空氣質量分指數(AQI)", "汙染物濃度及空氣質量分指數(AQI)",
            "汙染物濃度及空氣質量分指數(AQI)", "汙染物濃度及空氣質量分指數(AQI)","汙染物濃度及空氣質量分指數(AQI)", "汙染物濃度及空氣質量分指數(AQI)",
            "汙染物濃度及空氣質量分指數(AQI)", "汙染物濃度及空氣質量分指數(AQI)","汙染物濃度及空氣質量分指數(AQI)", "汙染物濃度及空氣質量分指數(AQI)",
            "空氣質量指數(AQI)",
            "首要汙染物",
            "空氣質量指數級別","空氣質量指數類別", "空氣質量指數類別"
    };
    //  “0,2,0,0”  ===>  “起始行,截止行,起始列,截止列”
    String[] headnum0 = {
            "0,2,0,0", //第0列跨3行
            "0,2,1,1", //第1列跨3行
            "0,0,2,13", //第2-13列跨1行
            "0,2,14,14",//第14列跨3行
            "0,2,15,15",//第15列跨3行
            "0,2,16,16",//第16列跨3行
            "0,1,17,18" //第17-18列跨2行
    };
    //第二行表頭欄位,其中的空的雙引號是為了補全表格邊框
    String[] excelHeader1 = {
            "二氧化硫(SO₂)24小時平均", "二氧化硫(SO₂)24小時平均",
            "二氧化氮(NO₂)24小時平均", "二氧化氮(NO₂)24小時平均",
            "顆粒物(粒徑小於等於10μm)24小時平均","顆粒物(粒徑小於等於10μm)24小時平均",
            "一氧化碳(CO)24小時平均", "一氧化碳(CO)24小時平均",
            "臭氧(O₃)最大8小時平均", "臭氧(O₃)最大8小時平均",
            "顆粒物(粒徑小於等於2.5μm)24小時平均", "顆粒物(粒徑小於等於2.5μm)24小時平均"
    };
    // 合併單元格
    String[] headnum1 = {
            "1,1,2,3", //第2-3列跨第1行
            "1,1,4,5", //第4-5列跨第1行
            "1,1,6,7",
            "1,1,8,9",
            "1,1,10,11",
            "1,1,12,13" };
    System.out.println(headnum1.length);

    //第三行表頭欄位
    String[] excelHeader2 = {
            "濃度/(μg/m3)",  "分指數",
            "濃度/(μg/m3)",  "分指數",
            "濃度/(μg/m3)",  "分指數",
            "濃度/(μg/m3)",  "分指數",
            "濃度/(μg/m3)",  "分指數",
            "濃度/(μg/m3)",  "分指數",
            "類別", "顏色"
    };

    String[] headnum2 = {
            "2,2,2,2",  //第2列跨第2行
            "2,2,3,3",
            "2,2,4,4",
            "2,2,5,5",
            "2,2,6,6",
            "2,2,7,7",
            "2,2,8,8",
            "2,2,9,9",
            "2,2,10,10",
            "2,2,11,11",
            "2,2,12,12",
            "2,2,13,13",
            "2,2,17,17",
            "2,2,18,18"
    };

    // 宣告一個工作簿
    HSSFWorkbook wb = new HSSFWorkbook();
    // 生成一個表格
    HSSFSheet sheet = wb.createSheet("競品收集彙總報表2");

    // 生成一種樣式style
    HSSFCellStyle style = wb.createCellStyle();
    // 設定樣式
    style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
    style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
    style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
    style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
    style.setBorderRight(HSSFCellStyle.BORDER_THIN);
    style.setBorderTop(HSSFCellStyle.BORDER_THIN);
    style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
    style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

    // 生成一種字型
    HSSFFont font = wb.createFont();
    // 設定字型
    font.setFontName("微軟雅黑");
    // 設定字型大小
    font.setFontHeightInPoints((short) 12);
    // 字型加粗
    font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
    // 在樣式中引用這種字型
    style.setFont(font);

    // 生成並設定另一個樣式style2
    HSSFCellStyle style2 = wb.createCellStyle();
    style2.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);
    style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
    style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
    style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
    style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
    style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
    style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);
    style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

    // 生成另一種字型2
    HSSFFont font2 = wb.createFont();
    // 設定字型
    font2.setFontName("微軟雅黑");
    // 設定字型大小
    font2.setFontHeightInPoints((short) 12);
    // 字型加粗
    // font2.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
    // 在樣式2中引用這種字型
    style2.setFont(font2);

    // 生成表格的第0行表頭
    HSSFRow row = sheet.createRow(0);
    for (int i = 0; i < excelHeader0.length; i++) {
        HSSFCell cell = row.createCell(i);
        cell.setCellValue(excelHeader0[i]);
        cell.setCellStyle(style);
        sheet.autoSizeColumn(i, true);// 根據欄位長度自動調整列的寬度
    }
    // 動態合併單元格
    for (int i = 0; i < headnum0.length; i++) {
        sheet.autoSizeColumn(i, true);
        String[] temp = headnum0[i].split(",");
        Integer startrow = Integer.parseInt(temp[0]);
        Integer overrow = Integer.parseInt(temp[1]);
        Integer startcol = Integer.parseInt(temp[2]);
        Integer overcol = Integer.parseInt(temp[3]);
        sheet.addMergedRegion(new CellRangeAddress(startrow, overrow, startcol, overcol));
    }

    // 第二行表頭
    row = sheet.createRow(1);
    for (int i = 0; i < excelHeader1.length; i++) {
        HSSFCell cell = row.createCell(i+2);
        cell.setCellValue(excelHeader1[i]);
        cell.setCellStyle(style);
        sheet.autoSizeColumn(i+2, true);// 自動調整寬度
    }
    // 動態合併單元格
    for (int i = 0; i < headnum1.length; i++) {

        sheet.autoSizeColumn(i, true);
        String[] temp = headnum1[i].split(",");
        Integer startrow = Integer.parseInt(temp[0]);
        Integer overrow = Integer.parseInt(temp[1]);
        Integer startcol = Integer.parseInt(temp[2]);
        Integer overcol = Integer.parseInt(temp[3]);
        sheet.addMergedRegion(new CellRangeAddress(startrow, overrow, startcol, overcol));
    }

    // 第三行表頭
      row = sheet.createRow(2);
      for (int i = 0; i < excelHeader2.length; i++) {
          if(i>=12){
              HSSFCell cell = row.createCell(i + 2 + 3);
              cell.setCellValue(excelHeader2[i]);
              cell.setCellStyle(style);
              sheet.autoSizeColumn(i + 2 + 3, true);// 自動調整寬度
          }else {
              HSSFCell cell = row.createCell(i + 2);
              cell.setCellValue(excelHeader2[i]);
              cell.setCellStyle(style);
              sheet.autoSizeColumn(i + 2, true);// 自動調整寬度
          }

    }
    // 動態合併單元格
    for (int i = 0; i < headnum2.length; i++) {
        sheet.autoSizeColumn(i, true);
        String[] temp = headnum2[i].split(",");
        Integer startrow = Integer.parseInt(temp[0]);
        Integer overrow = Integer.parseInt(temp[1]);
        Integer startcol = Integer.parseInt(temp[2]);
        Integer overcol = Integer.parseInt(temp[3]);
        sheet.addMergedRegion(new CellRangeAddress(startrow, overrow, startcol, overcol));
    }
    //這個至此只是輸出了表頭,對於表格內容應當遍歷list,迴圈填充每一個單元格
    return wb;
}

呼叫這個方法

  protected  <T> void doExportXls(HttpServletResponse response, HttpServletRequest request,  List<TsReportVo> dataSet, Class<?> pojoClass, String title) {
        response.setContentType("application/vnd.ms-excel");
        ServletOutputStream fOut = null;
        try {
                workbookname = new String(title.getBytes("UTF-8"), "ISO8859-1");
                response.setHeader("Content-Disposition", "attachment;filename=" + workbookname + ".xls");
            }
          /**
            Workbook workbook = new HSSFWorkbook();
            //如果沒有sheet匯出來的表格內容異常
            Sheet sheet = workbook.createSheet("new sheet");
            // Create a row and put some cells in it. Rows are 0 based.
            Row row = sheet.createRow(0);
            // Create a cell and put a value in it.
            Cell cell = row.createCell(0);
            cell.setCellValue("我是123");
            Cell cell2 = row.createCell(9);
            cell2.setCellValue("我是row.createCell(9)建立,9代表這一行第9個單元格,從0開始");

            fOut = response.getOutputStream();
           workbook.write(fOut);
          **/
            ExportUtil exportUtil = new ExportUtil();
            HSSFWorkbook wb = exportUtil.export(dataSet);//這一句呼叫我們上面寫的方法
            wb.write(fOut);
        } catch (Exception var15) {
            var15.printStackTrace();
            throw new Exception("匯出失敗!");
        } finally {
            try {
                fOut.flush();
                fOut.close();
            } catch (IOException var14) {
                var14.printStackTrace();
            }
        }
    }

 

 上面一一共渲染了三個表頭,我們分解一下

第一個表頭

第一二個表頭

 可以看到這個表頭的表格中的字比較擁擠,主要是因為這個方法

https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/Sheet.html#autoSizeColumn autoSizeColumn void autoSizeColumn(int column) 調整列寬以適合內容。 在大型工作表上,此過程可能相對較慢,因此通常只應在處理結束時每列呼叫一次。 您可以指定是否應考慮或忽略合併單元格的內容。預設是忽略合併的單元格。 引數: column - 列索引

autoSizeColumn void autoSizeColumn(int column, boolean useMergedCells) 調整列寬以適合內容。 在大型工作表上,此過程可能相對較慢,因此通常只應在處理結束時每列呼叫一次。 您可以指定是否應考慮或忽略合併單元格的內容。預設是忽略合併的單元格。 引數: column - 列索引 useMergedCells - 在計算列的寬度時是否使用合併單元格的內容

 

 需要注意的是要理解Excel的表格資料的渲染是從左往右,從上往下,逐個單元格渲染的

單個單元格

Workbook workbook = new HSSFWorkbook();  //如果沒有sheet匯出來的表格內容異常  Sheet sheet = workbook.createSheet("new sheet");  // Create a row and put some cells in it. Rows are 0 based.  Row row = sheet.createRow(0);  // Create a cell and put a value in it. Cell cell = row.createCell(0);   cell.setCellValue("我是123");  Cell cell2 = row.createCell(9);   cell2.setCellValue("我是row.createCell(9)建立,9代表這一行第9個單元格,從0開始");  fOut = response.getOutputStream(); workbook.write(fOut);

 

最後貼上我實際寫的程式碼

    @RequestMapping(params = "exportExcel2")
    public void ExportExcel2(TsCGCReportVo vo, HttpServletRequest request, HttpServletResponse response){
        List<TsCGCReportVo> collection = tsCompGoodsCollectionReportService.findGoodsCollection2(vo, null);
        this.doExportXls(response, request, collection, TsCGCReportVo.class, "競品收集彙總表");
    }

    protected  <T> void doExportXls(HttpServletResponse response, HttpServletRequest request,  List<TsCGCReportVo> dataSet, Class<?> pojoClass, String title) {
        response.setContentType("application/vnd.ms-excel");
        ServletOutputStream fOut = null;

        try {
            String workbookname;
            if (BrowserUtils.isIE(request)) {
                response.reset();
                response.setHeader("Cache-Control", "private");
                response.setHeader("Pragma", "private");
                response.setContentType("application/vnd.ms-excel;charset=UTF-8");
                response.setHeader("Content-Type", "application/force-download");
                workbookname = URLEncoder.encode(title + ".xls", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" + workbookname);
            } else {
                workbookname = new String(title.getBytes("UTF-8"), "ISO8859-1");
                response.setHeader("Content-Disposition", "attachment;filename=" + workbookname + ".xls");
            }
            ExportUtil exportUtil = new ExportUtil();
            HSSFWorkbook wb = exportUtil.exportGoods(dataSet);
            wb.write(fOut);
        } catch (Exception var15) {
            var15.printStackTrace();
            throw new BusinessException("匯出失敗!");
        } finally {
            try {
                fOut.flush();
                fOut.close();
            } catch (IOException var14) {
                var14.printStackTrace();
            }
        }
    }
}
public class ExportUtil {

    public HSSFWorkbook exportGoods(List<TsCGCReportVo> list) {
        //int titleRow = 6;//表頭標題及副標題佔6行
        //int tableBody = titleRow+1;//表頭開始
        // 宣告String陣列,並初始化元素(表頭名稱)
        //第一行表頭欄位,合併單元格時欄位跨幾列就將該欄位重複幾次
        String[] excelHeader0 = {
                "組織",
                "職位",
                "姓名",
                "終端編碼",
                "終端名稱",
                "終端地址",
                "拜訪時間",
                "競品編碼",
                "競品名稱",
                "當月銷量",
                "競品渠道促銷","競品渠道促銷","競品渠道促銷","競品渠道促銷","競品渠道促銷",
                "競品消費者促銷","競品消費者促銷","競品消費者促銷"

        };//length=12
        //  “0,2,0,0”  ===>  “起始行,截止行,起始列,截止列”
        String[] headnum0 = {
                "7,9,0,0",
                "7,9,1,1",
                "7,9,2,2",
                "7,9,3,3",
                "7,9,4,4",
                "7,9,5,5",
                "7,9,6,6",
                "7,9,7,7",
                "7,9,8,8",
                "7,9,9,9",
                "7,7,10,14",
                "7,7,15,17"
        };
        //第二行表頭欄位,其中的空的雙引號是為了補全表格邊框
        String[] excelHeader1 = {
               "渠道促銷",
               "陳列獎勵","陳列獎勵",
               "促銷效果打分",
               "文字描述",
               "消費者活動",
               "促銷效果打分",
               "文字描述"
        };
        // 合併單元格
        String[] headnum1 = {
                "8,9,10,10",
                "8,8,11,12",
                "8,9,13,13",
                "8,9,14,14",
                "8,9,15,15",
                "8,9,16,16",
                "8,9,17,17"
        };
        System.out.println(headnum1.length);

        //第三行表頭欄位
        String[] excelHeader2 = {
              "天",
              "瓶"
        };

        String[] headnum2 = {
                "9,9,11,11",
                "9,9,12,12",

        };

        // 宣告一個工作簿
        HSSFWorkbook wb = new HSSFWorkbook();
        // 生成一個表格
        HSSFSheet sheet = wb.createSheet("競品收集彙總報表2");

        // 生成一種樣式style
        HSSFCellStyle style = wb.createCellStyle();
        // 設定樣式
        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

        // 生成一種字型
        HSSFFont font = wb.createFont();
        // 設定字型
        font.setFontName("微軟雅黑");
        // 設定字型大小
        font.setFontHeightInPoints((short) 12);
        // 在樣式中引用這種字型
        style.setFont(font);

        // 生成標題樣式style1
        HSSFCellStyle style1 = wb.createCellStyle();
        // 設定樣式
        style1.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style1.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

        // 生成標題字型1
        HSSFFont font1 = wb.createFont();
        // 設定字型
        font1.setFontName("微軟雅黑");
        // 設定字型大小
        font1.setFontHeightInPoints((short) 25);
        // 字型加粗
        font1.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 在樣式中引用這種字型
        style1.setFont(font1);


        HSSFRow titleRow = sheet.createRow(0);
        HSSFCell titleCell = titleRow.createCell(0);
        titleCell.setCellValue("競品收集報表");
        titleCell.setCellStyle(style1);
        sheet.autoSizeColumn(0, true);
        sheet.addMergedRegion(new CellRangeAddress(0, 4, 0, 17));

        // 生成標題樣式style2
        HSSFCellStyle style2 = wb.createCellStyle();
        // 設定樣式
        style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

        HSSFRow titleRow2 = sheet.createRow(5);
        HSSFCell titleCell2 = titleRow2.createCell(14);
        titleCell2.setCellValue("匯出人:超級管理員");
        titleCell2.setCellStyle(style2);
        sheet.autoSizeColumn(14, true);
        sheet.addMergedRegion(new CellRangeAddress(5, 6, 14, 17));

        HSSFRow row = sheet.createRow(7);
        for (int i = 0; i < excelHeader0.length; i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellValue(excelHeader0[i]);
            cell.setCellStyle(style);
            sheet.autoSizeColumn(i, true);// 根據欄位長度自動調整列的寬度
        }
        // 動態合併單元格
        for (int i = 0; i < headnum0.length; i++) {
            sheet.autoSizeColumn(i, true);
            String[] temp = headnum0[i].split(",");
            Integer startrow = Integer.parseInt(temp[0]);
            Integer overrow = Integer.parseInt(temp[1]);
            Integer startcol = Integer.parseInt(temp[2]);
            Integer overcol = Integer.parseInt(temp[3]);
            sheet.addMergedRegion(new CellRangeAddress(startrow, overrow, startcol, overcol));
        }

        // 第二行表頭
        row = sheet.createRow(8);
        for (int i = 0; i < excelHeader1.length; i++) {
            HSSFCell cell = row.createCell(i+10);
            cell.setCellValue(excelHeader1[i]);
            cell.setCellStyle(style);
            sheet.autoSizeColumn(i+10, true);// 自動調整寬度
        }
        // 動態合併單元格
        for (int i = 0; i < headnum1.length; i++) {

            sheet.autoSizeColumn(i, true);
            String[] temp = headnum1[i].split(",");
            Integer startrow = Integer.parseInt(temp[0]);
            Integer overrow = Integer.parseInt(temp[1]);
            Integer startcol = Integer.parseInt(temp[2]);
            Integer overcol = Integer.parseInt(temp[3]);
            sheet.addMergedRegion(new CellRangeAddress(startrow, overrow, startcol, overcol));
        }

        // 第三行表頭
        row = sheet.createRow(9);
        for (int i = 0; i < excelHeader2.length; i++) {
            HSSFCell cell = row.createCell(i + 11);
            cell.setCellValue(excelHeader2[i]);
            cell.setCellStyle(style);
            sheet.autoSizeColumn(i + 11, true);// 自動調整寬度
        }
        // 動態合併單元格
        for (int i = 0; i < headnum2.length; i++) {
            sheet.autoSizeColumn(i, true);
            String[] temp = headnum2[i].split(",");
            Integer startrow = Integer.parseInt(temp[0]);
            Integer overrow = Integer.parseInt(temp[1]);
            Integer startcol = Integer.parseInt(temp[2]);
            Integer overcol = Integer.parseInt(temp[3]);
            sheet.addMergedRegion(new CellRangeAddress(startrow, overrow, startcol, overcol));
        }

        for(int i =0;i<list.size();i++){
            TsCGCReportVo vo = list.get(i);
            row = sheet.createRow(i+10);

            HSSFCell cell0 = row.createCell(0);
            cell0.setCellValue(vo.getOrgName());

            HSSFCell cell1 = row.createCell(1);
            cell1.setCellValue(vo.getPositionName());

            HSSFCell cell2 = row.createCell(2);
            cell2.setCellValue(vo.getUserName());

            HSSFCell cell3 = row.createCell(3);
            cell3.setCellValue(vo.getTerminalCode());

            HSSFCell cell4 = row.createCell(4);
            cell4.setCellValue(vo.getTerminalName());

            HSSFCell cell5 = row.createCell(5);
            cell5.setCellValue(vo.getTerminalAddress());

            HSSFCell cell6 = row.createCell(6);
            cell6.setCellValue(vo.getCreateDate());

            HSSFCell cell7 = row.createCell(7);
            cell7.setCellValue(vo.getComGoodsName());

            HSSFCell cell8 = row.createCell(8);
            cell8.setCellValue(vo.getTheMonthSale());

            HSSFCell cell9 = row.createCell(9);
            cell9.setCellValue(vo.getChannelGiftName());

            HSSFCell cell10 = row.createCell(10);
            cell10.setCellValue(vo.getColumnDay());

            HSSFCell cell11 = row.createCell(11);
            cell11.setCellValue(vo.getColumnReward());

            HSSFCell cell12 = row.createCell(12);
            cell12.setCellValue(vo.getChannelAnalPromEff());

            HSSFCell cell13 = row.createCell(13);
            cell13.setCellValue(vo.getChannelSaleRemark());

            HSSFCell cell14 = row.createCell(14);
            cell14.setCellValue(vo.getConsumerActivitiesName());

            HSSFCell cell15 = row.createCell(15);
            cell15.setCellValue(vo.getConsumerActivitiesName());

            HSSFCell cell16 = row.createCell(16);
            cell16.setCellValue(vo.getConAnalPromEff());

            HSSFCell cell17 = row.createCell(17);
            cell17.setCellValue(vo.getConSaleRemark());
        }
        return wb;
    }
}