使用EasyExcel生成动态表头

前言

最近项目有导出excel报表的需求,以前接触过的excel 报表需求都是使用 原生 poi 和hutool 工具类实现的,项目中 要求使用easyExcel 实现。附上 官网链接:EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel

1  动态表头的需求

1.1  固定项中的动态表头

虽然表头项是动态的,但是表头均出自同一张表或者同一实体类。诸如:有学生类,有 姓名、年龄、性别 、年级、班级 等信息。但是只需要 姓名、年龄 和 年级信息。

这一类情况是最简单的 。可以直接 参照使用 官网上的栗子 来解决@ExcelProperty(value = "字符串标题", index = 0)

实体类配置

package com.example.demo.easyexcelquickstart.entity;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Builder;
import lombok.Data;

/**
 * <p>
 * Title: Student
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: Copyright (c) 2022
 * </p>
 *
 * @author: cw
 * @Date: 2023-07-17 11:35
 */
@Data
@Builder
public class Student1 {
  @ExcelProperty(value = "姓名", index = 0)
  private String name;
  @ExcelProperty(value = "年龄", index = 1)
  private Integer age;
  // 忽略这个字段
  @ExcelIgnore
  private String sex;
  @ExcelProperty(value = "年级", index = 2)
  private String grade;
  // 忽略这个字段
  @ExcelIgnore
  private String stuClass;

}

写excel 代码配置

@PostMapping(value = "/test1")
  public JsonResponse test1() {
    String fileName = filePath + File.separator + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
    // 这里 需要指定写用哪个class去写
    try (ExcelWriter excelWriter = EasyExcel.write(fileName, Student1.class).build()) {
      WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
      excelWriter.write(data(), writeSheet);
    }
    return JsonResponseFactory.success();
  }

效果如下: 只导出了 姓名 年龄和年级信息

 1.2  表头不固定需要从数据库中动态获取

此处的数据库的动态获取,指的是 表头可能会有包含多张表(实体类的)信息,诸如:学校信息,课程信息 等。实现无法确定需要导出哪些列(需求中,经常会有此类问题

例如:我们的excel 报表有3部分组成 :学校信息:学校名称、学校地址、学校电话,学生信息:学生名称、学生年龄、学生年级、学生班级信息和 课程信息 :课程名称、课程类型和课程编码

 因为表头的组成来源于 不同的表,实体类(表)无法用一个某一个类来表示。

此问题的解决思路大体分为2步:

第一: 生成表头 模版 (中文表头 以及 模版对应的模版字段)

private void buildTempLate(String templateFileName) {

    try (ExcelWriter excelWriter = EasyExcel.write(templateFileName).needHead(false).build()) {
      WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
      // 模版表头
      final List<List<String>> headNameList = getHeadNameList();
      // 模版 占位符
      final List<List<String>> tempKeyList = getTempKeyList();
      excelWriter.write(headNameList, writeSheet);
      excelWriter.write(tempKeyList, writeSheet);
      excelWriter.finish();
    }

  }


// 生成动态表头中文名
  private List<List<String>> getHeadNameList() {
    // 模拟从数据库中加载配置信息
    final List<List<String>> headList = new ArrayList<>();
    // 加载学校表头
    final List<String> schList = new ArrayList<>(List.of("学校名称","学校地址","学校电话"));

    // 加载学生表头
    final List<String> stdList = new ArrayList<>(List.of("学生名称","学生年龄","学生年级","学生班级"));

    // 加载课程表头
    final List<String> courseList = new ArrayList<>(List.of("课程名称","课程类型","课程编码"));

    schList.addAll(stdList);
    schList.addAll(courseList);

    headList.add(schList);

    return headList;
  }

  // 生成动态表头占位符
  private List<List<String>> getTempKeyList() {
    // 模拟从数据库中加载配置信息
    final List<List<String>> headList = new ArrayList<>();
    // 加载学校表头
    final List<String> schList = new ArrayList<>(List.of("{.schName}", "{.schAddr}", "{.schTel}"));

    // 加载学生表头
    final List<String> stdList = new ArrayList<>(List.of("{.stdName}", "{.stdAge}", "{.stdGrade}", "{.stdStuClass}"));

    // 加载课程表头
    final List<String> courseList = new ArrayList<>(List.of("{.couName}", "{.couType}", "{.couCode}"));

    schList.addAll(stdList);
    schList.addAll(courseList);

    headList.add(schList);

    return headList;
  }

最终生成的效果如下:

第二: 用easyExcel的fill 方法 ,对 模版数据进行填充

// 用easyExcel的fill 方法 ,对 模版数据进行填充
    try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
      WriteSheet writeSheet = EasyExcel.writerSheet().build();
      // 模拟从DB中查询数据
      final List<Map<String, Object>> dataList = dyNamicData();
      excelWriter.fill(dataList, writeSheet);
      excelWriter.finish();
    }

最终生成的文件效果如下:

 PS:对于表头来源于多张表且每张表的属性的情况下,其实也通过建立一个大而全的 BO 对象来实现,但如果某张表表中的属性是动态扩展的,比如课程表的属性不固定:如不同学校 的课程 表 可能会有 课程积分,是否必修等不同属性时,如果此时课程表的属性根据配置需要进行动态扩展,且属性名不可预知,建立一个大二全的BO 是不可行的)。

如果需要源码:https://github.com/shao139772/easyExcelQuickStart/tree/master

附录:使用easyExcel 导出遇到的一些问题

1  wps 正常打开,office 打开提示 发现 XX.xlsx中的部分内容有问题,是否让我们尽量尝试修复?如果您信任 次工作薄的源,请打击“是”。

 

此问题是由于,表格设置边框样式,且模版表头中 有 N个属性,  但是用于填充的list 集合中存储对象的属性 不足N个,就会给出此提示。

例如:模版中 有{.stdName}、{.stdAge}、{.stdSex} 3个 属性,但是从数据库中查询出来的对象属性 只有 {.stdName}、{.stdSex} 2个属性,就会有此问题。 

2  莫名的合并了单元格

此问题是由于,用于填充的list 集合中存储对象的属性为null ,就会出现此效果。

例如:模版中 表头有{.stdName}、{.stdAge}、{.stdSex}、{.stdGrade} 4个 属性,但是从数据库中查询出来的对象属性 中 stdage 为 10,stdSex 为null。 就会有此问题。

总结: 模版中定义了的属性一定要出现在数据库中查询后的对象属性,不能没有,且不要为null

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值