动态的复杂表头导入及导出记录,实习实战,

1有俩种方法进行表的导入和导出,俩种各有千秋

       一、Java POI  由于功能丰富,POI的学习曲线相对较陡峭,对于新手来说可能不太友好。且填充时是按照单元格一个一个填充,设置表头时不友好,填充数据时可以自定义较为简单

      二、EasyExcel 对于数据量较大的填充。EasyExcel提供了更优的性能,因为它采用了基于SAX的读写方式,减少了内存的占用和垃圾回收的压力。如复杂的数据结构转换、自定义公式等,EasyExcel可能不如POI灵活。  由于是动态的表头,所以说本文采用EasyExcel进行动态表头的转化比较简单,但对于数据的灵活性没有POI好,

ps:总结,POI设置表头复杂,数据填充简单,EasyExcel表头简单,数据填充较为复杂,且easyExcel对新手稍微友好一些,刚实习,使用easyexcel。

2EasyExcel 官网文档设置动态列表还是较为简单的,参考easy官方文档,设置表头,

1 设置固定的表头,一般情况下会有些固定的表头,匹配dto中的一些固定的字段,例如,部门,系统,和一些动态的表头,如何生成?

2导出的表头如图,设置表头时,需要进行的就是创建一个List<List<String>> 创建时,需要在上面进行,
  List<List<String>> headList = Lists.newArrayList();
        List<String> head0 = Lists.newArrayList();
        head0.add("体系");
        List<String> head1 = Lists.newArrayList();
        head1.add("系统");
        List<String> head2 = Lists.newArrayList();
        head2.add("标工编码");
        List<String> head5 = Lists.newArrayList();
        head3.add("工序名称");
//       根据 接口返回值生产表头,
        modelList.forEach(x->{
            x.getColumnList().forEach(y->{
                List<String> head = Lists.newArrayList();
                //设置动态表头的内容,easyExcel会根据其内容进行生成
                head.add(x.getMclassifyName());
                head.add(y.getModelName());
                head.add(y.getModelCode());
                headList.add(head);
            });
        });你撤回了一条消息重新编辑
3设置数据集,采用最原始的方法进行,根据表头对应的特定值,对其进行遍历,生成一个List<OrderData> list中每个值就是其中的一行,会根据表头进行寻找,我的比较复杂原因是中间有一个我的dto里面有一个list,需要对list进行转列。主要这个toMap,转化成map类型
ps:第4步发我需要转换的dto字段
private List<List<Object>> setPrimariyDataList(List<Dto> Dtos,List<List<String>> headList) {
        List<Map<String, Object>> result = null;
        //将需要导出的字段转换成map
        result = Dtos.stream().map(Dto::toMap).collect(Collectors.toList());
        //根据表头进行填充,对应的是表头上面的字段
        List<List<Object>> orderedData = new ArrayList<>();
        for (Map<String, Object> map : result) {
            List<Object> rowData = new ArrayList<>();
            for (List<String> header : headList) {
                for (String key : header) {
                    if (map.containsKey(key)) {
                        Object value = map.get(key);
                        if (value ==null) {
                            rowData.add(" ");
                        }else {
                            if (map.get(key).equals(true)){
                                rowData.add("\u2713");
                            }else if (map.get(key).equals(false)){
                                rowData.add(" ");
                            }else {
                                rowData.add(map.get(key));
                            }
                        }
                    }
                }
            }
            orderedData.add(rowData);
        }
        return orderedData;
    }
4对于我需要导出的dto进行解析 搞清楚他的数据结构,才能知道你需要的数据在哪里
public Class Dto{
        private String setupName;
        private String productCode;
        private String processCode;
        private String processName;
        // modelLibraryList 可以根据接口去动态的设置,导致表头是动态的
        privat List<modelDtos> modelLibraryList;


 /**
     * 研发固定表头
     * @return
     */
    public Map<String, Object> toMap(){
        Map<String, Object> map = Maps.newHashMap();
        map.put("体系", this.setupName);
        map.put("系统", this.productCode);
        map.put("标工编码",this.processCode);
        map.put("工序名称",this.processName);
        List<Map<String, Object>> collectedMaps = modelLibraryList.stream()
                .map(dto -> {
                    Map<String, Object> map1 = new HashMap<>();
                    map1.put(dto.getModelName(), dto.getSelectFlag());
                    return map1;
                })
                .collect(Collectors.toList());
        collectedMaps.forEach(item ->{
            map.putAll(item);
        });
        return map;
    }



}

 5 对于数据进行导出时,直接将做好的list<list<String>>headlist和list<list<String>>dataList 用controller层导出即可

 //设置响应内容类型
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");//编码
        // 设置文件名, ps:把字符串中所有的'+'替换成'%20',在URL中%20代表空格
        String fileName = URLEncoder.encode("标模库导出", "UTF-8").replaceAll("\\+", "%20");
        //设置响应头
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        response.setHeader("fileName", fileName + ".xlsx");//设置响应头
        EasyExcel.write(response.getOutputStream()).sheet("标模数据").head(headList).doWrite(dataList);

3需要设置一些样式,对特定的行和列设置样式,比如一些符合某些条件的dto ,鼠鼠的感同身受是,

类似于这种,可以使用一个List<TargetCell> 记录下当前的行号和 表头中需要修改的单元格,在后续中 自定义一个MyCellWriterHandler ,实现CellWriterHandler 即可,重写其中的,afterCellDispose ,先判断是否为表头,如果不是表头就可以继续了

public void afterCellDispose(CellWriteHandlerContext context) {
    if (BooleanUtils.isNotTrue(context.getHead())) {
        Cell cell = context.getCell();
        int curRowIndex = cell.getRowIndex();
        int curColIndex = cell.getColumnIndex();

        Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();

        // 根据目标单元格列表进行匹配并设置样式
        for (TargetCell targetCell : targetCells) {
            if (targetCell.getRowIndex() == curRowIndex && 
                getColumnName(context).equals(targetCell.getColumnName())) {
                CellStyle cellStyle = workbook.createCellStyle();
                // 根据目标单元格配置相应颜色
                byte[] rgb = decideRgbColor(targetCell);
                XSSFCellStyle xssfCellColorStyle = (XSSFCellStyle) cellStyle;
                xssfCellColorStyle.setFillForegroundColor(new XSSFColor(rgb, null));
                cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

                cell.setCellStyle(cellStyle);
                context.getFirstCellData().setWriteCellStyle(null);
                break;  // 找到匹配的目标单元格后,无需再遍历
            }
        }
    }
}

当然对于上面的targetCell的条件判断,这里有不准的地方,后面自定义调整,如果你想在自定义的Handler中传参数,则,可在其中定义构造方法,这样可以获得你需要的参数,。

public class StyleHandler implements CellWriteHandler {

    // 目标单元格信息列表
    private final List<TargetCell> targetCells;  

    private final List<List<String>> headList;
   

    public StyleHandler(List<TargetCell> targetCells ,List<List<String>> headList) {
        this.targetCells = targetCells;
        this.headList = headList;
    }

    @Override
    public void afterCellDispose(CellWriteHandlerContext context) {
      //在填充数据之后,对于特定的地方进行样式填充

      if(条件 和当前行和列有关){
           cell.setCellStyle(new CellStyle)    
          }
      //  还可以设置一些单元格和并信息    
      if(条件 和当前行和列有关){
            // 创建区域对象并设置合并区域
            CellRangeAddress range = new CellRangeAddress(startRowIndex, endRowIndex, colIndex, colIndex);
            sheet.addMergedRegion(range);
          }
    }

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于复杂动态表头导出,你可以使用 EasyExcel 来实现。EasyExcel 是一个基于 Java 的 Excel 操作工具,可以用于读取、写入和操作 Excel 文件。 下面是一个示例代码,演示如何使用 EasyExcel 导出带有复杂动态表头的 Excel 文件: ```java // 创建 ExcelWriter 对象 ExcelWriter excelWriter = EasyExcel.write("output.xlsx").build(); // 定义表头数据 List<List<String>> header = new ArrayList<>(); header.add(Arrays.asList("姓名", "年龄", "性别")); header.add(Arrays.asList("科目", "语文", "数学", "英语")); // 导出数据 List<List<Object>> data = new ArrayList<>(); data.add(Arrays.asList("张三", 20, "男", 80, 90, 85)); data.add(Arrays.asList("李四", 22, "女", 75, 85, 90)); // 动态合并表头单元格 int firstRow = 0; int lastRow = firstRow + header.size() - 1; int firstCol = 0; int lastCol = firstCol + header.get(header.size() - 1).size() - 1; excelWriter.getOrCreateSheet("Sheet1") .head(header) .relativeMerge(firstRow, lastRow, firstCol, lastCol) .doWrite(data); // 关闭 ExcelWriter 对象 excelWriter.finish(); ``` 在上面的示例中,我们创建了一个 ExcelWriter 对象,并指定输出文件为 "output.xlsx"。然后,我们定义了表头数据和导出数据,并调用 EasyExcel 提供的方法来动态合并表头单元格。最后,我们调用 `doWrite` 方法将数据写入到 Excel 文件中。 需要注意的是,上面的示例仅演示了如何导出简单的动态表头,如果你的表头更加复杂,你可能需要自行进行逻辑处理来生成动态表头数据。 希望这个示例能对你有所帮助!如果还有其他问题,请继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值