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

摘要:在javaWeb开发中,会经常遇到导出业务数据的业务需求,导出Excel最常用的技术就是poi,对于简单的业务,我们可以动态的生成一个Excel文件,但对于复杂的业务,我们可以通过使用读取Excel模板的,然后往里面填充数据的方式,下载文件。

最终下载的Excel截图如下图所示(部分截图),数据均为测试数据: 

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

1.准备Excel模板文件文件

根据导出业务需求,创建Excel模板文件,并将文件放入到webapp中的resources目录下,如下图所示 (部分截图)。

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

 

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

2.获取Excel导出的fileName和业务数据

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

try {
     JSONObject excelNameAndData = 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对象

在使用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模板导出业务数据(包含复杂单元格动态合并操作)+附源码_第4张图片

 

你可能感兴趣的:(javaWeb)