easyexcel icon indicating copy to clipboard operation
easyexcel copied to clipboard

对于一个动态字段数量的实体,即一个实体类中存在以 Map 动态的存储字段的情况,如何优雅的实现导出?

Open LanXiu0523 opened this issue 1 year ago • 5 comments

比如对于实体类

public class scoreTable {
    private String studentName;
    private String score;
    private Map<String, Long> subScore;
}

对于每次查询,subScore 的项不一定一样,但可以保证一次查询中每一个实体中的 Map 的 key 都是一样的 如查询某次数学成绩,我的显示:

| 姓名 | 分数 | 选择 | 填空 | 
-------------------------
| 小明 | 90  | 40  |  50  | 

再如查询某次英语成绩,我的显示:

| 姓名 | 分数 | 完形 | 阅读 | 作文 | 
--------------------------------
| 小明 | 70  |  20  | 20  | 30  | 

目前,对于 easyexcel 我并未找到这种通过 Map 实现动态列的表格的导出方式,因此我自定义了工具类,读取表头和每一行数据,然后用以下的方式导出:

List<List<String>> headers = (List<List<String>>) excelExportData.get("headers");
List<List<Object>> rows = (List<List<Object>>) excelExportData.get("rows");

EasyExcel.write(filePath)
        .head(headers)
        .sheet(sheetName)
        .doWrite(rows);

现在的问题是,以上方式没法拿到 scoreTable.class 的信息,因此 转换器注解、格式化注解等注解就无法识别,我只能在 excelExportData.get("rows") 的方法中手动实现 转换器注解、格式化注解的生效,比较麻烦且不能复用 easyexcel 的注解解析能力。 如果以 EasyExcel.write(filePath, scoreTable.class) 的方式 拿到 scoreTable.class 的信息,就又会覆盖掉 head(headers) 设置的表头。

是否有更优雅的方式解决这个问题呢?

LanXiu0523 avatar Aug 02 '24 05:08 LanXiu0523

同问

Cu1ii avatar Sep 19 '24 19:09 Cu1ii

同问, 我目前是实现的RowWriteHandler做的,自己传头部,也需要自己判断标题、数据重复写的问题,功能实现了 代码写的很抽象

qiuhuanhen avatar Nov 12 '24 01:11 qiuhuanhen

没有,只能自己操作XSSFSheet

i-guyue avatar Nov 22 '24 03:11 i-guyue

动态表头不建议使用创建对象的导出,应该使用不创建对象的导出,文档里有说明 https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write#%E5%8A%A8%E6%80%81%E5%A4%B4%E5%AE%9E%E6%97%B6%E7%94%9F%E6%88%90%E5%A4%B4%E5%86%99%E5%85%A5

LSL1618 avatar Nov 28 '24 02:11 LSL1618

我倒有方式能导出,如下: 1、自定义注解如下


/**
     * 扩展信息
     */
    @ExcelProperty(value = "扩展信息",converter = ExcelDynamicConvert.class)
    @ExcelDynamicColumns(targetType = SysExtField.TargetType.user)
    private Map<String ,Object > extMap;
}

2、实现CellWriteHandler,在afterCellDispose中做如下处理:


@Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        // 只有在写入数据行时才处理动态列(忽略表头行)
        if (isHead != null && isHead) {
            return;  // 跳过表头
        }

        // 计算当前列是否是动态列
        int colIndex = cell.getColumnIndex();
        if (colIndex == dynamicColumnStartIndex) {
            Row row = cell.getRow();
            String jsonStr = cell.getStringCellValue();
            Map<String, Object> jsonObject = JSONUtil.toBean(jsonStr, HashMap.class);
            cell.setCellValue(jsonObject.getOrDefault(dynamicColumns.get(0), "").toString());

            for (int i = 1; i < dynamicColumns.size(); i++) {
                Cell rowCell = row.createCell(colIndex + i);
                Object value = jsonObject.get(dynamicColumns.get(i));
                rowCell.setCellValue(value != null ? value.toString() : "");
            }
        }
    }

表头就按照你当前的方式处理即可,但是这个也有个问题我至今未解决,比如固定列+动态列用户偶尔又想只导出部门,此时对象数据传递进去数据就会错位,各位可以看看怎么能改

liangxp avatar Mar 30 '25 13:03 liangxp