alibaba / easyexcel

快速、简洁、解决大文件内存溢出的java处理Excel工具
https://easyexcel.opensource.alibaba.com
Apache License 2.0
32.29k stars 7.51k forks source link

能不能出一个和easyPOI中类似@ExcelCollection来解决一对多的问题 #3788

Open PhysicalOptics opened 5 months ago

PhysicalOptics commented 5 months ago

能不能出一个和easyPOI中类似@ExcelCollection来解决一对多的问题

在easyPOI 中导入和导出可以用@ExcelCollection 来解决一对多导出时主数据一行已经自动合并,子数据多行正常导出

sx19970123 commented 4 months ago

同求

far310 commented 3 months ago

+1

psxjoy commented 3 months ago

LGTM

lolkt commented 2 months ago

@Test public void listFill() { // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"{","}"代替 // 填充list 的时候还要注意 模板中{.} 多了个点 表示list // 如果填充list的对象是map,必须包涵所有list的key,哪怕数据为null,必须使用map.put(key,null) File templateFileName = new File("D:\不加密\simple.xlsx"); File exportFile = FileUtils.createNewFile("D:\不加密\simple" + System.currentTimeMillis() + ".xlsx");

    Map<Integer, Integer> mergeMap=new HashMap<>();
    mergeMap.put(3,1);
    mergeMap.put(10,5);
    MergeRowWriteHandler mergeRowWriteHandler = new MergeRowWriteHandler(mergeMap);
    // 方案2 分多次 填充 会使用文件缓存(省内存)
    try (ExcelWriter excelWriter = EasyExcel.write(exportFile).withTemplate(templateFileName)
            .registerWriteHandler(mergeRowWriteHandler)
            .build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        excelWriter.fill(data(), writeSheet);
    }
}

private List<FillData> data() {
    List<FillData> list = ListUtils.newArrayList();
    for (int i = 0; i < 20; i++) {
        FillData fillData = new FillData();
        fillData.setName("张三");
        fillData.setNumber(5.2);
        fillData.setDate(new Date());
        list.add(fillData);
        if (i< 3) {
            fillData.setId(6L);
        }else {
            fillData.setId(7L);
        }

    }
    return list;
}

import com.alibaba.excel.write.handler.RowWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress;

import java.util.HashMap; import java.util.Map;

public class MergeRowWriteHandler implements RowWriteHandler { // 假设这是你在写入数据之前构建的映射,key是行号(从0开始),value表示该行与上几行合并 private final Map<Integer, Integer> mergeMap = new HashMap<>();

// 构造器,你可以在这里传入合并逻辑或合并映射
public MergeRowWriteHandler(Map<Integer, Integer> mergeMap) {
    this.mergeMap.putAll(mergeMap);
}

@Override
public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
    if (isHead) {
        return;
    }
    // 获取当前行的行号(注意:这里的行号是从0开始的,但在Excel中通常是从1开始的)
    int rowIndex = relativeRowIndex;
    // 注意:我们实际上是在决定当前行与“之前的”已写入行是否应该合并,但在这里我们假设mergeMap已经根据业务逻辑设置好了
    if (mergeMap.containsKey(rowIndex)) {
        Integer lineNumber = mergeMap.get(rowIndex);

        Sheet sheet = writeSheetHolder.getSheet();
        int boforeRowNum = rowIndex - lineNumber;
        System.out.println("需要合并行:" + boforeRowNum + " 到 " + rowIndex);
        // 合并单元格,注意:Excel中的行和列都是从0开始的
        CellRangeAddress addressList = new CellRangeAddress(
                boforeRowNum, relativeRowIndex, 0, 0); // 合并1列
        sheet.addMergedRegion(addressList);
        CellRangeAddress addressList2 = new CellRangeAddress(
                boforeRowNum, relativeRowIndex, 1, 1); // 合并2列
        sheet.addMergedRegion(addressList2);
        // 注意:在实际应用中,你可能需要存储这些合并信息,并在写入完成后应用它们
    }

    // 注意:上面的逻辑并不实际合并单元格,因为当afterRowDispose被调用时,下一行可能还没有被写入
}

}

临时解决方案,提前计算要合并的行,和向上合并几行。

zzg19901210 commented 1 month ago

同求