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; } }