javaWeb中使用Excel模板导出业务数据(包含复杂单元格动态合并操作)+附源码

摘要:在javaWeb开发中,会经常遇到导出业务数据的业务需求,导出Excel最常用的技术就是poi,对于简单的业务,我们可以动态的生成一个Excel文件,但对于复杂的业务,我们可以通过使用读取Excel模板的,然后往里面填充数据的方式,下载文件。
最终下载的Excel截图如下图所示(部分截图),数据均为测试数据:
javaWeb中使用Excel模板导出业务数据(包含复杂单元格动态合并操作)+附源码
文章图片

1.准备Excel模板文件文件 根据导出业务需求,创建Excel模板文件,并将文件放入到webapp中的resources目录下,如下图所示 (部分截图)。
javaWeb中使用Excel模板导出业务数据(包含复杂单元格动态合并操作)+附源码
文章图片


javaWeb中使用Excel模板导出业务数据(包含复杂单元格动态合并操作)+附源码
文章图片

2.获取Excel导出的fileName和业务数据 在导出数据前,需要设置Excel下载后的文件名称以及业务数据,然后将数据写入到Excel模板中。

try { JSONObject excelNameAndData = https://www.it610.com/article/service.getExcelNameAndData(); fileName = excelNameAndData.getString("fileName"); dataList = excelNameAndData.getObject("dataList", List.class); } catch (Exception e) { logger.error("message {}","Excel数据获取失败:" + e.getMessage()); return; }

3.设置response相关属性
response.setContentType("application/vnd.ms-excel"); response.setHeader("content-disposition", "attachment; filename=" + fileName + ".xls");

4.获取Excel模板的HSSFWorkbook对象 【javaWeb中使用Excel模板导出业务数据(包含复杂单元格动态合并操作)+附源码】在使用Excel模板的时候,需要获取到模板的输入流,然后根据此输入流,创建出HSSFWorkbook对象,在数据插入到模板文件后,在刷到浏览器上。
// 拿到模板文件 String tplPath = request.getSession().getServletContext().getRealPath("resources/template/"); String filePath = tplPath + "/prepareRankTemplate.xls"; try (FileInputStream fIn = new FileInputStream(new File(filePath)); OutputStream fOut = response.getOutputStream()) { HSSFWorkbook tpWorkbook = new HSSFWorkbook(fIn); workbook = ExcelExportUtil.exportExcel(tpWorkbook, dataList); if (workbook != null) { workbook.write(fOut); } } catch (Exception e) { logger.error(e.getMessage()); return; }

5.将数据插入到Excel中 由于模板文件的标题占用了2行,因此我们在插入数据时,从第三行开始。在循环数据时,首先获取到这个用户下面数据条目(假如有3条),然后将序号、姓名列的单元格进行合并,插入序号、年级等值,然后在遍历这个用户下的数据条目,分别插入年级学科、应备等数据
/** * 获取Workbook对象 * */ private static HSSFWorkbook getPrepareTopExcel(HSSFWorkbook tempWorkbook, List list) { // 创建一个workbook 对应一个excel应用文件 HSSFWorkbook workBook = tempWorkbook; HSSFSheet sheet = workBook.getSheetAt(0); ExcelInternalUtil exportUtil = new ExcelInternalUtil(workBook, sheet); HSSFCellStyle bodyStyle = exportUtil.getBodyStyle(); HSSFCell cell = null; CellRangeAddress regionIndex = null; CellRangeAddress regionName = null; //纵向合并序号、姓名等单元格的起始行数 int startRegionRowNum = 2; PersonPrepareRanNewVo personPrepareRanNewVo = null; List prepareRankVos = null; // 构建表体数据 for (int i = 0; i < list.size(); i++) { // 创建行 HSSFRow bodyRow = sheet.getRow(startRegionRowNum); if (bodyRow == null) { bodyRow = sheet.createRow(startRegionRowNum); } personPrepareRanNewVo = (PersonPrepareRanNewVo) list.get(i); prepareRankVos = personPrepareRanNewVo.getPrepareRankVos(); //单元格合并 regionIndex = new CellRangeAddress(startRegionRowNum, startRegionRowNum + prepareRankVos.size() - 1, 0, 0); regionName = new CellRangeAddress(startRegionRowNum, startRegionRowNum + prepareRankVos.size() - 1, 1, 1); sheet.addMergedRegion(regionIndex); sheet.addMergedRegion(regionName); //序号 cell = bodyRow.createCell(0); cell.setCellValue(String.valueOf(i + 1)); //姓名 cell = bodyRow.createCell(1); cell.setCellValue(personPrepareRanNewVo.getUserName()); //设置合并后的单元格样式 exportUtil.setRegionStyle(regionIndex, bodyStyle); exportUtil.setRegionStyle(regionName, bodyStyle); initPrepareRankTopData(sheet, prepareRankVos, startRegionRowNum, bodyStyle); startRegionRowNum += prepareRankVos.size(); } return workBook; }

填充年级学科、备课信息等数据
/** * 向Excel中填充个人备课数据 * * @param sheet Excel sheet * @param prepareRankVos 个人备课数据 * @param startRowNum 数据插入起始行 * @param bodyStyle 单元格样式 */ private static void initPrepareRankTopData(HSSFSheet sheet, List prepareRankVos, int startRowNum, HSSFCellStyle bodyStyle) { HSSFCell cell = null; HSSFRow bodyRow = null; for (PersonPrepareRankVo prepareRankVo : prepareRankVos) { bodyRow = sheet.getRow(startRowNum); if (bodyRow == null) { bodyRow = sheet.createRow(startRowNum); } startRowNum++; for (int j = 0; j < 10; j++) { cell = bodyRow.createCell(j + 2); Object val = getCellValues(j, prepareRankVo); if (val == null) { val = ""; } cell.setCellStyle(bodyStyle); cell.setCellValue(val.toString()); } } }

获取并处理年级学科、备课信息数据
/** *从个人备课本中取出各个类型的数据 * @param index * @param prepareRankVo * @return */ private static Object getCellValues(int index, PersonPrepareRankVo prepareRankVo) { Object val = null; if (index == 0) { //年级学科 val = prepareRankVo.getGradeStr() + prepareRankVo.getSubjectStr(); } else if (index == 1) { //应备 val = prepareRankVo.getMustCount(); } else if (index == 2) { //实备 val = prepareRankVo.getPrepareNum(); } else if (index == 3) { //备课完成率 val = prepareRankVo.getFinishRate(); try { val = NumUtils.percent(val.toString()); } catch (Exception e) { logger.error("message {}", "备课完成率转换异常:" + e); val = ""; } } else if (index == 4) { //导学案 val = prepareRankVo.getDaoxueNum(); } else if (index == 5) { //教案 val = prepareRankVo.getJiaoAnNum(); } else if (index == 6) { //课件 val = prepareRankVo.getKejianNum(); } else if (index == 7) { //微课 val = prepareRankVo.getWeikeNum(); } else if (index == 8) { //习题 val = prepareRankVo.getXitiNum(); } else { //其他 val = prepareRankVo.getQitaNum(); } return val; }

6.附件源码 https://download.csdn.net/download/qq_34976024/10835811
备注:附件的代码中并不包含博客中的代码片段,也没有实现单元格动态合并操作,属于一个简化版,只演示了模板的用法,如果需要实现动态合并,可在附件的基础上阅读博客中第5部分的内容,自行实现。动态合并的demo源码后续补充。
附件源码运行后,下载Excel的文件截图如下图所示,数据均为测试数据。
javaWeb中使用Excel模板导出业务数据(包含复杂单元格动态合并操作)+附源码
文章图片


    推荐阅读