灵活运用easyexcel进行导出(自定义导出表头与表身数据)

我的需求有些怪, 导出的excel的头某些是不固定的, 使用原生poi导出, 其中有很多循环数据库, 效率慢且数据量大容易宕机,之前的接口代码如下

public String export1(Long templateId, Date beginTime, Date endTime, Integer state, String examineNumber, Long createUserId) {
        Cnd cnd = Cnd.where("templateId", "=", templateId);
        cnd.andEX("createTime", ">=", beginTime);
        cnd.andEX("createTime", "<=", endTime);
        cnd.andEX("examineNumber", "like", examineNumber);
        cnd.andEX("createUserId", "=", createUserId);
        if (state != null && state != 0) {
            switch (state) {
                case 1:	//已完成(包含已通过和已拒绝)
                    int[] states = new int[]{ExamineState.AGREE.key(), ExamineState.REFUSE.key()};
                    cnd.and("examineState", "in", states);
                    break;
                case 2:	//审批中
                    cnd.and("examineState", "=", ExamineState.UNDER_APPROVAL.key());
                    break;
                case 3:	//已撤销
                    cnd.and("examineState", "=", ExamineState.REVOKE.key());
                    break;
                default:
                    break;
            }
        }
        cnd.groupBy("templateVersion");
        List<ExamineExport> versions = super._query(cnd, null, FieldMatcher.simple("templateVersion"));
        XSSFWorkbook wb = new XSSFWorkbook();
        XSSFCellStyle cellStyle = wb.createCellStyle();
        cellStyle.setWrapText(true);	//数据格强制换行
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中;
        XSSFCellStyle titleStyle = wb.createCellStyle();
        titleStyle.setFillForegroundColor(IndexedColors.AQUA.getIndex());
        titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        titleStyle.setBorderBottom(BorderStyle.THIN); //下边框
        titleStyle.setBorderLeft(BorderStyle.THIN);//左边框
        titleStyle.setBorderTop(BorderStyle.THIN);//上边框
        titleStyle.setBorderRight(BorderStyle.THIN);//右边框
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
        for (ExamineExport version : versions) {
            Cnd versionCnd = Cnd.where("templateId", "=", templateId);
            versionCnd.and("templateVersion", "=", version.getTemplateVersion());
            versionCnd.andEX("createTime", ">=", beginTime);
            versionCnd.andEX("createTime", "<=", endTime);
            versionCnd.andEX("examineNumber", "like", examineNumber);
            versionCnd.andEX("createUserId", "=", createUserId);
            if (state != null && state != 0) {
                switch (state) {
                    case 1:	//已完成(包含已通过和已拒绝)
                        int[] states = new int[]{ExamineState.AGREE.key(), ExamineState.REFUSE.key()};
                        versionCnd.and("examineState", "in", states);
                        break;
                    case 2:	//审批中
                        versionCnd.and("examineState", "=", ExamineState.UNDER_APPROVAL.key());
                        break;
                    case 3:	//已撤销
                        versionCnd.and("examineState", "=", ExamineState.REVOKE.key());
                        break;
                    default:
                        break;
                }
            }
            List<ExamineExport> exports = super.query(versionCnd);
            JSONObject formMap = JSONObject.parseObject(exports.get(0).getExamineForms());
            XSSFSheet sheet = wb.createSheet(version.getTemplateVersion() == null ? "1" : version.getTemplateVersion());
            //第一次需要设置表头, 根据提交的表单设置
            int rowNum = 0;
            int titleIndex = 0;
            XSSFRow title = sheet.createRow(rowNum++);
            short height = 20*30;
            title.setHeight(height);
            sheet.setColumnWidth(titleIndex, 21*256+184);
            XSSFCell number = title.createCell(titleIndex);
            number.setCellStyle(titleStyle);
            number.setCellValue("审批编号");
            titleIndex++;
            sheet.setColumnWidth(titleIndex, 30*256+184);
            XSSFCell name = title.createCell(titleIndex);
            name.setCellStyle(titleStyle);
            name.setCellValue("标题");
            titleIndex++;
            sheet.setColumnWidth(titleIndex, 10*256+184);
            XSSFCell createUser = title.createCell(titleIndex);
            createUser.setCellStyle(titleStyle);
            createUser.setCellValue("提交人");
            titleIndex++;
            sheet.setColumnWidth(titleIndex, 21*256+184);
            XSSFCell createTime = title.createCell(titleIndex);
            createTime.setCellStyle(titleStyle);
            createTime.setCellValue("发起时间");
            titleIndex++;
            sheet.setColumnWidth(titleIndex, 21*256+184);
            XSSFCell completeTime = title.createCell(titleIndex);
            completeTime.setCellStyle(titleStyle);
            completeTime.setCellValue("完成时间");
            titleIndex++;
            sheet.setColumnWidth(titleIndex, 10*256+184);
            XSSFCell stateCell = title.createCell(titleIndex);
            stateCell.setCellStyle(titleStyle);
            stateCell.setCellValue("审批状态");
            titleIndex++;

            for (String examineTitle : formMap.keySet()) {
                XSSFCell formTitle = title.createCell(titleIndex);
                formTitle.setCellStyle(titleStyle);
                formTitle.setCellValue(examineTitle);
                titleIndex++;
            }
            //设置结尾的历史审批人
            sheet.setColumnWidth(titleIndex, 30*256+184);
            XSSFCell processUser = title.createCell(titleIndex);
            processUser.setCellStyle(titleStyle);
            processUser.setCellValue("历史审批人");

            //从第二行开始循环放置具体内容
            for (ExamineExport export : exports) {
                XSSFRow value = sheet.createRow(rowNum++);
                int valueIndex = 0;
                value.createCell(valueIndex++).setCellValue(export.getExamineNumber());
                value.createCell(valueIndex++).setCellValue(export.getExamineTitle());
                value.createCell(valueIndex++).setCellValue(export.getCreateUser());
                value.createCell(valueIndex++).setCellValue(export.getCreateTime());

                //此处存在实际数据中没有完成时间的情况,所以不需要这样判断,不然表格数据会左移一格
//                if (StringUtils.isNotBlank(export.getCompleteTime())) {
                value.createCell(valueIndex++).setCellValue(export.getCompleteTime());
//                }
                value.createCell(valueIndex++).setCellValue(export.getExamineStateDesc());
                //放置表单
                JSONObject jo = JSONObject.parseObject(export.getExamineForms());
                for (String examineTitle : formMap.keySet()) {
                    value.createCell(valueIndex++).setCellValue(String.valueOf(jo.get(examineTitle)));
                }
                value.createCell(valueIndex++).setCellValue(export.getProcessUsers());
            }
        }
        //导出Excel
        String fileName = Moment.now().format("yyyyMMddHHmmssSSS")+ ".xlsx";
        String fileUrl = "examine/report/" + fileName;
        try {
            File file = new File(fileLocalPath + fileUrl);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            FileOutputStream out = new FileOutputStream(file);
            wb.write(out);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileUrl;
    }

后来我接手后利用easyexcel重写了这个接口, 效果一样, 但是提高了效率, 最重要的是避免循环调数据库!!!

重写后的接口:

public String export(Long templateId, Date beginTime, Date endTime, Integer state, String examineNumber, Long createUserId) {
        String fileName = Moment.now().format("yyyyMMddHHmmssSSS")+ ".xlsx";
        String fileUrl = "examine/report/" + fileName;
        File file = new File(fileLocalPath + fileUrl);
        List<ExamineExport> list = getExportListNoPage(templateId, beginTime, endTime, state, examineNumber, createUserId);
        if (CollectionUtils.isNotEmpty(list)) {
            String examineForms = list.get(0).getExamineForms();
            JSONObject jsonObject = JSONObject.parseObject(examineForms);
            Set<String> strings = jsonObject.keySet();
            List<String> keys = new ArrayList<>(strings);

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            //将excel文件写入byteArrayOutputStream中
            EasyExcel.write(byteArrayOutputStream)
                    .head(head(keys))
                    .sheet("sheet1")
                    .doWrite(dataList(list, keys));
            //创建inputStream流
            InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            FileUtils.writeToFile(file, inputStream, true);
            return fileUrl;
        } else {
            List<List<String>> keys = new ArrayList<>();
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            //将excel文件写入byteArrayOutputStream中
            EasyExcel.write(byteArrayOutputStream)
                    .head(keys)
                    .sheet("sheet1")
                    .doWrite(new ArrayList<>());
            //创建inputStream流
            InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            FileUtils.writeToFile(file, inputStream, true);
            return fileUrl;
        }
    }

    /**
     * 无分页(为导出准备) // 此接口查回你需要的数据
     * @param templateId
     * @param beginTime
     * @param endTime
     * @param state
     * @param examineNumber
     * @param createUserId
     * @return
     */
    public List<ExamineExport> getExportListNoPage(Long templateId,
                                                   Date beginTime,
                                                   Date endTime,
                                                   Integer state,
                                                   String examineNumber,
                                                   Long createUserId) {
        Cnd cnd = Cnd.where("templateId", "=", templateId);
        cnd.andEX("createTime", ">=", beginTime);
        cnd.andEX("createTime", "<=", endTime);
        cnd.andEX("examineNumber", "like", examineNumber);
        cnd.andEX("createUserId", "=", createUserId);
        if (state != null && state != 0) {
            switch (state) {
                case 1:	//已完成(包含已通过和已拒绝)
                    int[] states = new int[]{ExamineState.AGREE.key(), ExamineState.REFUSE.key()};
                    cnd.and("examineState", "in", states);
                    break;
                case 2:	//审批中
                    cnd.and("examineState", "=", ExamineState.UNDER_APPROVAL.key());
                    break;
                case 3:	//已撤销
                    cnd.and("examineState", "=", ExamineState.REVOKE.key());
                    break;
                default:
                    break;
            }
        }
        cnd.desc("createTime");
        return this.query(cnd);
    }

    private List<List<String>> head(List<String> keys) {
        List<List<String>> list = new ArrayList<List<String>>();
        list.add(Collections.singletonList("审批编号"));
        list.add(Collections.singletonList("标题"));
        list.add(Collections.singletonList("提交人"));
        list.add(Collections.singletonList("发起时间"));
        list.add(Collections.singletonList("完成时间"));
        list.add(Collections.singletonList("审批状态"));
        keys.forEach(s -> {
            List<String> head0 = new ArrayList<String>();
            head0.add(s);
            list.add(head0);
        });
        list.add(Collections.singletonList("历史审批人"));
        return list;
    }

    private List<List<Object>> dataList(List<ExamineExport> realData, List<String> realKeys) {
        List<List<Object>> list = ListUtils.newArrayList();
        for (ExamineExport realDatum : realData) {
            List<Object> data = ListUtils.newArrayList();
            data.add(realDatum.getExamineNumber());
            data.add(realDatum.getExamineTitle());
            data.add(realDatum.getCreateUser());
            data.add(realDatum.getCreateTime());
            data.add(realDatum.getCompleteTime());
            data.add(realDatum.getExamineStateDesc());
            String examineForms = realDatum.getExamineForms();
            JSONObject jsonObject = JSONObject.parseObject(examineForms);
            realKeys.forEach(key -> data.add(jsonObject.get(key)));
            data.add(realDatum.getProcessUsers());
            list.add(data);
        }
        return list;
    }

这段代码需要一起拷贝下来, 有些例如cnd可能会报错(查数据库的), 此代码仅做思路, 非工具类, 勿喷

查阅很多资料发现这块内容较少, 所以写此贴给有同样需求的人提供思路

easyexcel官方文档地址: 关于Easyexcel | Easy Excel

另外可能会poi版本和easyexcel版本冲突, 这是因为easyexcel内置了poi, 两个poi版本冲突了

我easyexcel版本3.1.1, poi版本4.1.2, 可用, 仅供参考

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于复杂自定义表头导出,可以使用EasyExcel的注解`@ExcelProperty`来实现。具体步骤如下: 1. 创建表头实体类,使用`@ExcelProperty`注解来定义表头名称和对应的字段。 ```java public class ComplexHeadData { @ExcelProperty({"主标题", "名称"}) private String name; @ExcelProperty({"主标题", "数量"}) private Integer number; @ExcelProperty({"主标题", "价格"}) private Double price; @ExcelProperty({"次标题", "子名称"}) private String subName; @ExcelProperty({"次标题", "子数量"}) private Integer subNumber; @ExcelProperty({"次标题", "子价格"}) private Double subPrice; // 省略getter和setter方法 } ``` 2. 创建导出数据集合,并将数据集合和表头实体类传入`EasyExcel.write()`方法中,使用`Sheet`对象来设置表头。 ```java List<ComplexHeadData> data = ... Sheet sheet = new Sheet(1, 0, ComplexHeadData.class); // 设置主标题行 List<List<String>> head = new ArrayList<>(); head.add(Arrays.asList("主标题", "名称", "数量", "价格")); // 设置次标题行 head.add(Arrays.asList("次标题", "子名称", "子数量", "子价格")); // 设置表头样式 WriteCellStyle headStyle = new WriteCellStyle(); // ... 设置样式 // 设置主标题行的样式 WriteCellStyle mainHeadStyle = new WriteCellStyle(headStyle); mainHeadStyle.setFillForegroundColor(IndexedColors.BLUE_GREY.getIndex()); // 设置次标题行的样式 WriteCellStyle subHeadStyle = new WriteCellStyle(headStyle); subHeadStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); // 设置主标题行和次标题行的样式 WriteCellStyle headCellStyle = new WriteCellStyle(); headCellStyle.setWrapped(true); headCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); headCellStyle.setMainHeadStyle(mainHeadStyle); headCellStyle.setSubHeadStyle(subHeadStyle); // 设置表头 sheet.setHead(head); sheet.setHeadStyle(headCellStyle); // 写入数据到Excel EasyExcel.write(outputStream, ComplexHeadData.class).sheet().doWrite(data); ``` 通过以上步骤,即可实现复杂自定义表头导出。需要注意的是,`@ExcelProperty`注解中的数组参数表示表头的层级关系,数组的第一个元素为主标题,第二个元素为次标题,以此类推。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值