[alibaba/easyexcel]当 复杂头写入 和 合并单元格 同时使用的情况下,复杂表头失效,变成一个单元格。

2024-05-21 753 views
7

当 复杂头写入 和 合并单元格 同时使用的情况下,复杂表头失效,变成一个单元格。 异常代码

//方法一
            // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String tempFileName = URLEncoder.encode(fileName, "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + tempFileName + ".xlsx");
            Object d = redisUtil.get("sxschool:study:cache:time:" + groupId);
            String date = d == null ? DateUtil.now() : d.toString();
            List<UserStudyrecordsResponse> userStudyrecordsResponseList = userService.exportUserStudyRecord(groupId);
            //合并策略map
            Map<String, List<RowRangeVo>> strategyMap = ExcelUtil.addMerStrategy(userStudyrecordsResponseList);
            EasyExcel.write(response.getOutputStream(), UserStudyrecordsResponse.class)
                    .registerWriteHandler(new ExportUserStudyRecordHandler(date))
                    .registerWriteHandler(new BizMergeStrategy(strategyMap))
                    .sheet("sheet1").doWrite(userStudyrecordsResponseList);

//ExportUserStudyRecordHandler 类
public class ExportUserStudyRecordHandler implements CellWriteHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExportUserStudyRecordHandler.class);

    private String date;

    public ExportUserStudyRecordHandler(String date) {
        this.date = date;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
                                 Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
                                Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                 List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        // 这里可以对cell进行任何操作
        //LOGGER.info("第{}行,第{}列写入完成。", cell.getRowIndex(), cell.getColumnIndex());
        if (isHead && cell.getColumnIndex() == 0 && cell.getRowIndex() == 0) {
//            CreationHelper createHelper = writeSheetHolder.getSheet().getWorkbook().getCreationHelper();
//            Hyperlink hyperlink = createHelper.createHyperlink(HyperlinkType.URL);
//            hyperlink.setAddress("https://github.com/alibaba/easyexcel");
            cell.setCellValue("数据刷新时间:" + this.date);
        }

    }
}
///////////////////////////////////////////////////////////////////////////////////////
//BizMergeStrategy 类
public class BizMergeStrategy extends AbstractMergeStrategy {
    private Map<String, List<RowRangeVo>> strategyMap;
    private Sheet sheet;

    public BizMergeStrategy(Map<String, List<RowRangeVo>> strategyMap) {
        this.strategyMap = strategyMap;
    }

    @Override
    protected void merge(org.apache.poi.ss.usermodel.Sheet sheet, Cell cell, Head head, Integer integer) {
        this.sheet = sheet;
        if (cell.getRowIndex() == 1 && cell.getColumnIndex() == 0) {
            /**
             * 保证每个cell被合并一次,如果不加上面的判断,因为是一个cell一个cell操作的,
             * 例如合并A2:A3,当cell为A2时,合并A2,A3,但是当cell为A3时,又是合并A2,A3,
             * 但此时A2,A3已经是合并的单元格了
             */
            for (Map.Entry<String, List<RowRangeVo>> entry : strategyMap.entrySet()) {
                Integer columnIndex = Integer.valueOf(entry.getKey());
                entry.getValue().forEach(rowRange -> {
                    //添加一个合并请求
                    sheet.addMergedRegionUnsafe(new CellRangeAddress(rowRange.getStart(),
                            rowRange.getEnd(), columnIndex, columnIndex));
                });
            }
        }
    }
}
////////////////////////////////////////////////////////////////////////////////////////
//ExcelUtil 类
public class ExcelUtil {
    /**
     * @Author: TheBigBlue
     * @Description: 添加合并策略
     * @Date: 2020/3/16
     * @Param:
     * @return:
     **/
    public static Map<String, List<RowRangeVo>> addMerStrategy(List<UserStudyrecordsResponse> excelDtoList) {
        Map<String, List<RowRangeVo>> strategyMap = new HashMap<>();
        UserStudyrecordsResponse preExcelDto = null;
        for (int i = 0; i < excelDtoList.size(); i++) {
            UserStudyrecordsResponse currDto = excelDtoList.get(i);
            if (preExcelDto != null) {
                //从第二行开始判断是否需要合并
                if (currDto.getUserName().equals(preExcelDto.getUserName())) {
                    //如果用户名一样,则可合并用户名一列
                    fillStrategyMap(strategyMap, "0", i + 1);
                    //如果用户名一样,并且账号一样,则可合并账号一列
                    if (currDto.getMobile().equals(preExcelDto.getMobile())) {
                        fillStrategyMap(strategyMap, "1", i + 1);
                        //如果用户名、账号一样,并且用户组也一样,则可合并用户组一列
                        if (currDto.getGroupName().equals(preExcelDto.getGroupName())) {
                            fillStrategyMap(strategyMap, "2", i + 1);
                            //如果用户名、账号、用户组一样,并且总完成率也一样,则可合并总完成率一列
                            if (currDto.getSumPercentage().equals(preExcelDto.getSumPercentage())) {
                                fillStrategyMap(strategyMap, "3", i + 1);
                                //如果用户名、账号、用户组、总完成率一样,并且总课程时长也一样,则可合并总课程时长一列
                                if (currDto.getSumVideoSeconds().equals(preExcelDto.getSumVideoSeconds())) {
                                    fillStrategyMap(strategyMap, "4", i + 1);
                                    //如果用户名、账号、用户组、总完成率、总课程时长一样,并且总学习时长也一样,则可合并总学习时长一列
                                    if (currDto.getSumStudyVideoSeconds().equals(preExcelDto.getSumStudyVideoSeconds())) {
                                        fillStrategyMap(strategyMap, "5", i + 1);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            preExcelDto = currDto;
        }
        return strategyMap;
    }

    /**
     * @Author: TheBigBlue
     * @Description: 新增或修改合并策略map
     * @Date: 2020/3/16
     * @Param:
     * @return:
     **/
    private static void fillStrategyMap(Map<String, List<RowRangeVo>> strategyMap, String key, int index) {
        List<RowRangeVo> rowRangeDtoList = strategyMap.get(key) == null ? new ArrayList<>() : strategyMap.get(key);
        boolean flag = false;
        for (RowRangeVo dto : rowRangeDtoList) {
            //分段list中是否有end索引是上一行索引的,如果有,则索引+1
            if (dto.getEnd() == index) {
                dto.setEnd(index + 1);
                flag = true;
            }
        }
        //如果没有,则新增分段
        if (!flag) {
            rowRangeDtoList.add(new RowRangeVo(index, index + 1));
        }
        strategyMap.put(key, rowRangeDtoList);
    }

}
/////////////////////////////////////////////////////////////////////////////////
//UserStudyrecordsResponse 实体类
//导出学员学习记录分析表实体
    //姓名
    @ExcelProperty(value = {"主标题", "姓名"}, index = 0)
    private String userName;
    //账号
    @ExcelProperty(value = {"主标题", "账号"}, index = 1)
    private String mobile;
    //用户组名称
    @ExcelProperty(value = {"主标题", "用户组"}, index = 2)
    private String groupName;
    //总完成率
    @ExcelProperty(value = {"主标题", "总完成率"}, index = 3)
    private String sumPercentage;
    //所有推送 总课程时长
    @ExcelProperty(value = {"主标题", "总课程时长"}, index = 4)
    private String sumVideoSeconds;
    //所有推送课程已经观看的总时长
    @ExcelProperty(value = {"主标题", "总学习时长"}, index = 5)
    private String sumStudyVideoSeconds;
    //开始学习时间
    @ExcelProperty(value = {"主标题", "开始学习时间"}, index = 6)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date startStudyTime;
    //完成时间
    @ExcelProperty(value = {"主标题", "完成时间"}, index = 7)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date finishTime;
    //完成率(百分比)
    @ExcelProperty(value = {"主标题", "完成率"}, index = 8)
    private String percentage;
    //课程名字(任务名称)
    @ExcelProperty(value = {"主标题", "任务名称"}, index = 9)
    private String courseName;
    //单个课程的时长
    @ExcelProperty(value = {"主标题", "该课程时长"}, index = 10)
    private String courseVideoSeconds;
    //单个课程的学习时长
    @ExcelProperty(value = {"主标题", "该课程的学习时长"}, index = 11)
    private String courseStudyVideoSeconds;
    //进度
    @ExcelProperty(value = {"主标题", "进度"}, index = 12)
    private String speedOfProgress;

异常提示 当 复杂头写入 和 合并单元格 同时使用的情况下,复杂表头失效,变成一个单元格。 建议描述

回答

8

能否描述的简单一点。然后把期望和结果贴一下。

5

感谢帮助,麻烦看一下我提交的 工单.doxc 文件,上面有我描述的具体情况。

1

能否描述的简单一点。然后把期望和结果贴一下。 七层嵌套if, 哎,可恶的PM

8

感谢帮助,麻烦看一下我提交的 期望结果.docx 文件,上面有我描述的具体情况。

4

参照文档 合并单元格 复杂头用table