• 常用Excel工具小结


      这段时期的工作涉及了不少报表类的开发,其中用到了主流的Excel处理工具EasyPoiEasyExcel,下面是关于这两个工具用法小结。

    一.Excel的填充(导出的一种)

      关于Excel的导出主要分为两种形式,一种是事先给出一个确定的excel文件作为导出模板,然后将生成的数据写入到这个Excel文件中(即excel模板的填充);另一种就是不需要事先给定好excel文件,而是在生成数据的过程中动态的生成导出模板的格式,相当于把数据和模板样式一起动态的生成。

      首先是实体类(实体类不用加单独的注解,就是普通的业务实体类):

    public class tcExcelDTO {
        /**
         *  ID
         */
        private Long orderNum;
        /**
         *  单位编号
         */
        private String deptCode;
        /**
         *  单位名称
         */
        private String deptName;
        /**
         *  管理类数量
         */
        private Integer manageNum;
        /**
         *  管理类分值
         */
        private BigDecimal manageScore;
        /**
         *  技术质量类数量
         */
        private Integer technicalQualityNum;
        /**
         *  技术质量类分值
         */
        private BigDecimal technicalQualityScore;
        /**
         *  生产类数量
         */
    
        private Integer productionNum;
        /**
         *  生产类分值
         */
        private BigDecimal productionScore;
    }
    

      

      1.EasyPoi的填充

      (1)Excel模板设置格式:参考EasyPoi教程_V1.0 (mydoc.io),具体位置如下:

      

         本文使用的例子如下

          

      (2)参考实现代码:

    public void applyResyltExport(HttpServletResponse response, HrIsProjectApplysBusiBo hrIsProjectApplysBusiBo)
            throws Exception{
        List<tcExcelDTO> exportTemplateListJiTuan = buildJiTuanData(hrIsProjectApplysBusiBo);//sheet1中的数据
        List<tcExcelDTO> exportTemplateListCompany = buildCompanyData(hrIsProjectApplysBusiBo);//sheet2中的数据
        String fileName = hrIsProjectApplysBusiBo.getYear() +"年"+
                hrIsProjectApplysBusiBo.getQuarter() + "季度" + EXCEL_NAME;
        TemplateExportParams params=new TemplateExportParams("templates/import/finalApplyResult.xlsx",true);//需要填充的模板的路径
        Map<String, Object> map = new HashMap<>();
    
        map.put("list",exportTemplateListCompany);//sheet1,list和模板中的list名称相对应
        map.put("list2",exportTemplateListJiTuan);//sheet2,list1和模板中的list1名称相对应
        Workbook workbook = ExcelExportUtil.exportExcel(params,map);//easypoi的依赖
        try {
            response.setHeader("Content-disposition", "attachment;filename=" + new String(fileName.getBytes("utf-8"),"ISO-8859-1" )+".xlsx");
            workbook.write(response.getOutputStream());
            response.getOutputStream().flush();
        } catch (IOException e) {
            log.error("导出失败,请检查", e);
            throw new BaseException(ErrorEnum.SYSTEM_ERROR, "导出失败,请检查");
        } finally {
            try {
                response.getOutputStream().close();
            } catch (IOException e) {
                log.error("导出失败,请检查", e);
                throw new BaseException(ErrorEnum.SYSTEM_ERROR, "导出失败,请检查");
            }
        }
    
    }
    

      

       此处主要使用了语法:{{fe:list t.age t.secondList.name}},需要注意的是使用指令fe 循坏数据,如果使用$fe 嵌套列表第一个字段为空时,第二行后面的数据显示不出来了。

      2.EasyExcel的填充

      (1)Excel模板设置格式:参考填充Excel | Easy Excel (alibaba.com),由于官方例子讲述的很详细,此处不在赘述。

    二.Excel的导出(动态生成模板)

      1.EasyPoi的导出

      (1)首先设置相应的实体类:

    public class testExcelDTO {
        /**
         *  ID
         */
        private Long id;
        /**
         *  项目编号
         */
        @Excel(name = "项目编号", orderNum = "1", width = 25)
        private String projectCode;
        /**
         *  项目名称
         */
        @Excel(name = "项目名称", orderNum = "2", width = 25)
        private String projectName;
        /**
         *  主持人工号
         */
        @Excel(name = "工号", orderNum = "3", width = 25)
        private String empNo;
        /**
         *  主持人姓名
         */
        @Excel(name = "姓名", orderNum = "4", width = 25)
        private String empName;
        /**
         *  角色
         */
        @Excel(name = "角色", replace = { "主持人_100001", "主要参与人_100002", "一般参与人_100003", "辅助参与人_100004" },orderNum = "5", width = 25)
        private Integer role;
        /**
         *  年度
         */
        private String year;
        /**
         *  季度
         */
        private String quarter;
        /**
         *  项目来源
         */
        private String source;
    public static HrIsProjectPitemExcelDTO generateBean() {
        return new HrIsProjectPitemExcelDTO();
    }
    }
    

      (2)代码实现:

     public void testExport(HttpServletResponse response, HrIsProjectPitemBusiBo hrIsProjectPitemBusiBo)
                throws Exception{
            // 设置导出数据
            List<testExcelDTO> exportTemplateList = buildEmportTemplateData(hrIsProjectPitemBusiBo);//生成需要导出的数据
            log.info("exportTemplateList : {}", exportTemplateList);
            if (!org.apache.commons.collections4.CollectionUtils.isEmpty(exportTemplateList)) {
                List<Map<String, Object>> excelParamList = new ArrayList<>();
                excelParamList.add(ExportExcelUtil.getExcelSheetParam(SHEET_NAME ,
                        exportTemplateList, testExcelDTO.class));
                StringBuffer fileName = new StringBuffer(hrIsProjectPitemBusiBo.getYear() +"年"+
                        hrIsProjectPitemBusiBo.getQuarter() + "季度" + EXCEL_NAME);
                fileName.append(".xlsx");
                ExportExcelUtil.exportExcel(excelParamList, ExcelType.XSSF, fileName.toString(), response);
            } else {
                throw new BaseException(ErrorEnum.SYSTEM_ERROR, "导出数据为空!");
            }

      其中ExportExcel的定义如下:

    public class ExportExcelUtil {
      
        /**
         * 导出到workbook并输出到response
         * @param list   数据集
         * @param excelType  文件类型ExcelType.HSSF/XSSF
         * @return
         * @throws
         */
        public static void exportExcel(List<Map<String, Object>> list, ExcelType excelType, String fileName, HttpServletResponse response) throws IOException {
            try {
                Workbook workbook = ExcelExportUtil.exportExcel(list, excelType);
                if (workbook != null) {
                    response.setHeader("content-Type", "application/vnd.ms-excel");
                    response.setHeader("Content-disposition", "attachment;filename=" + new String(fileName.getBytes("utf-8"),"iso-8859-1" ));
                    workbook.write(response.getOutputStream());
                    response.getOutputStream().flush();
                    // 关闭流
                    response.getOutputStream().close();
                }
            }catch (IOException e){
                throw new IOException("导出表格数据失败");
            }
        }
    
        // 流导出
        private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException {
            try {
                response.reset();
                response.setContentType("application/x-download");
                response.setHeader("Content-Disposition",
                        "attachment; filename=" + new String(fileName.getBytes("utf-8"), "ISO-8859-1"));
                workbook.write(response.getOutputStream());
            }catch (IOException e){
                throw new IOException("导出表格数据失败");
            }
        }
    
        // 生成预选值的sheet页
        private static XSSFDataValidationHelper createXSSFDataValidationHelper(Workbook workbook, String name, String[] strList) {
            Sheet sheet = workbook.createSheet(name);
            // 循环往该sheet中设置添加下拉列表的值
            for (int i = 0; i < strList.length; i++) {
                Row row = sheet.createRow(i);
                Cell cell = row.createCell((int) 0);
                cell.setCellValue(strList[i]);
            }
            workbook.setSheetHidden(workbook.getSheetIndex(name), true);//隐藏用于生成下拉框的sheet
            XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper((XSSFSheet) workbook.getSheet(name));
            dvHelper.createFormulaListConstraint(name + "!$A$1:$A$" + strList.length);
            return dvHelper;
        }
        /**
         * 生成含有下拉框的模板
         * firstRow 开始行号(默认为1,下标0开始)
         * lastRow  根据此项目,默认为最大65535
         * firstCol 区域中第一个单元格的列号 (下标0开始)
         * lastCol 区域中最后一个单元格的列号
         * strings 下拉内容
         * */
        public static void exportContainDownVlue(Workbook workbook, HttpServletResponse response,String mySheetNmme,String fileName,String[]dropDownValue,
        int firstCol,int lastCol ) throws IOException {
    
            String  dropDownSheetName= "隐藏sheet";
            XSSFDataValidationHelper dropDownValidationHelper = createXSSFDataValidationHelper(workbook, dropDownSheetName, dropDownValue);
            DataValidationConstraint dropDOwnValidationConstraint = dropDownValidationHelper.createFormulaListConstraint(dropDownSheetName + "!$A$1:$A$" + dropDownValue.length);
            Sheet firstSheet = workbook.getSheet(mySheetNmme);
            CellRangeAddressList drowDownValueCoveringRowsAndCloumns = new CellRangeAddressList(1, firstSheet.getLastRowNum(), firstCol, lastCol);
            XSSFDataValidation dropDownValidation =(XSSFDataValidation)dropDownValidationHelper.createValidation(dropDOwnValidationConstraint, drowDownValueCoveringRowsAndCloumns);
            firstSheet.addValidationData(dropDownValidation);
            downLoadExcel(fileName, response, workbook);
        }
    
    }
    

     (3)导出结果示例:

     2.EasyExcel的导出

      官方文档的Demo写的很清晰,此处不在赘述写Excel | Easy Excel (alibaba.com)

    三.Excel的导入

      1.EasyPoi

      (1)实体类如下:

    public class testExcelDTO {
        /**
         *  ID
         */
        private Long id;
        /**
         *  项目编号
         */
        @Excel(name = "项目编号", orderNum = "1", width = 25)
        private String projectCode;
        /**
         *  项目名称
         */
        @Excel(name = "项目名称", orderNum = "2", width = 25)
        private String projectName;
        /**
         *  主持人工号
         */
        @Excel(name = "工号", orderNum = "3", width = 25)
        private String empNo;
        /**
         *  主持人姓名
         */
        @Excel(name = "姓名", orderNum = "4", width = 25)
        private String empName;
        /**
         *  角色
         */
        @Excel(name = "角色", replace = { "主持人_100001", "主要参与人_100002", "一般参与人_100003", "辅助参与人_100004" },orderNum = "5", width = 25)
        private Integer role;
        /**
         *  年度
         */
        private String year;
        /**
         *  季度
         */
        private String quarter;
        /**
         *  项目来源
         */
        private String source;
    
    }
    

      这个实体类和导入的时候类似的,需要通过注解@Excel对应好数据的映射关系

     (2)代码实现如下:

    public DataImportResultBO testExcelImport(@NotNull @RequestParam("file") MultipartFile file,
                                                             @RequestParam(value = "id") @Number(min=1,message = "ID必须大于0")  Long id) throws Exception {
            String intekeyUrl = NacosGlobalConfiguration.getByKey("intekey-url");
            String appCode = NacosGlobalConfiguration.getByKey("intekey-appCode");
            String secretKey = NacosGlobalConfiguration.getByKey("intekey-secretKey");
            InputStream inputStream = IntekeyUtils.DecryptFile(intekeyUrl,appCode,secretKey,file);//由于导入的wxcel文件是加密的,此处需要解密
            ImportParams importParams = new ImportParams();
    //        importParams.setKeyIndex(0);
            importParams.setNeedVerify(true);
            ExcelImportResult<testExcelDTO> excelImportResult = ExcelImportUtil
                    .importExcelMore(inputStream, testExcelDTO.class, importParams);//easypoi提供的接口
            List<testExcelDTO> list = excelImportResult.getList();
            DataImportResultBO resultBO = new DataImportResultBO();
            List<testExcelDTO> failList = excelImportResult.getFailList();
            if (failList != null && failList.size() > 0) {//打印错误信息
                int count = failList.size();
                StringBuilder stringBuilder = new StringBuilder();
                for (testExcelDTO dto : failList) {
                    stringBuilder
                            .append("第")
                            .append(dto.getRowNum())
                            .append("行,")
                            .append(dto.getErrorMsg())
                            .append(";");
                }
                resultBO.setMsg(stringBuilder.toString());
                resultBO.setErrorNumber(count);
                resultBO.setIsSuccess(false);
            } else {
                resultBO.setErrorNumber(0);
            }
            if(list.size()==0 && CollectionUtils.isEmpty(failList)){//对应解析excel失败的处理
                final boolean[] isSuccess = {true};
                isSuccess[0] = false;
                resultBO.setIsSuccess(isSuccess[0]);
                resultBO.setSuccessNumber(0);
                resultBO.setMsg("批量导入excel未解析到数据");
                log.error("批量导入excel未解析到数据!");
                return resultBO;
            }else {//业务逻辑处理 
                int successNum = 0;
                for (testExcelDTO hrIsCashSpecialApplyExcelBusiDTO : list) {
                    testExcelDTO hrIsCashSpecialApplyBusiDTO = new HrIsCashSpecialApplyBusiDTO();
                    XXXXXXXX //业务逻辑
                    successNum++;
                }
                resultBO.setSuccessNumber(successNum);
                resultBO.setErrorNumber(list.size() - successNum);
                resultBO.setIsSuccess(true);
                return resultBO;
            }
        }
    

      其中返回的信息类定义如下:

    public class DataImportResultBO<E> implements Serializable {
    
        /**
         * 本次导入编码
         */
        private String importCode;
    
        /**
         * 导入成功条数
         */
        private Integer successNumber;
    
        /**
         * 失败条数
         */
        private Integer errorNumber;
    
        /**
         * 导入结果
         */
        private Boolean isSuccess;
    
        /**
         * 错误信息
         */
        private String msg;
    
        /**
         * 导入数据
         */
        List<E> result;
    }
    

      2.EasyExcel

      参考官方文档:读Excel | Easy Excel (alibaba.com)

    四.其他

      1.EasyPoi导入、导出时不支持三级以上表头,但是也可以实现,只是相对复杂些,关于EasyPoi的多级表头的导入、导出可以参考:

      (1) (35条消息) excel导入基于Easypoi一对多导入(实现合并单元格)_秃头老程序员的博客-CSDN博客_easypoi导入excel一对多

      (2) (35条消息) 使用easypoi或者easyexcel多表头导出_山里的小蝌蚪的博客-CSDN博客_easypoi 导出表头

      (3) easyExcel简单excel导出以及多sheet页导出 - 简书 (jianshu.com)

      2.关于带下拉框的Excel的导出

      参考代码:

     /**
         * 自定义excel下拉框内容
         * @param workbook
         * @param firstCol 需要设置下拉框的开始行
         * @param lastCol 需要设置下拉框的开始列
         * @param strings,下拉框选项
         */
        private static void selectList(Workbook workbook,int firstCol,int lastCol,String[] strings) {
            Sheet sheet = workbook.getSheetAt(0);
            //  生成下拉列表
            //  只对(x,x)单元格有效
            CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 65535, firstCol, lastCol);
            //  生成下拉框内容
            DVConstraint dvConstraint = DVConstraint.createExplicitListConstraint(strings);
            HSSFDataValidation dataValidation = new HSSFDataValidation(cellRangeAddressList, dvConstraint);
            //  对sheet页生效
            sheet.addValidationData(dataValidation);
        }
    

      

  • 相关阅读:
    SQL Server数据库读写分离提高并发性
    静态方法与实例化方法区别
    消息队列MQ对比
    【Python】socket模块应用
    【Matplotlib】利用Python进行绘图
    【Git】简单使用
    【HTTPS】自签CA证书 && nginx配置https服务
    【HTTP】 认证和单点登录 【瞎写的…】
    【Linux】防火墙与CentOS中的iptables
    【Ansible】的python api
  • 原文地址:https://www.cnblogs.com/wangkundentisy/p/16443473.html
Copyright © 2020-2023  润新知