EasyPoi导出复杂Excel

简介

还是关于毕设的,现在有个导出复杂 Excel 的需求,与前面的文章关系很大,感兴趣的看一下哈

wnhyang.github.io/artic

问题

前面不是解决了,属性列表展示问题吗?

随之而来,便是导出 Excel 的问题了

看了前面都知道了,我需要能导出这样的 Excel

然而 ruoyi 最原生的基于 org.apache.poi 实现的一种简单的导出,只支持简单的数据,就是一行一行非常规范的那种,不支持复杂类型的 Excel 导出

解决

查了很多资料后,确定了使用 EasyPoi ,如果确实是想深入学习,下面有链接,不过这里就说一下我的应用

@Excel

这个是必须使用的注解,如果需求简单只使用这一个注解也是可以的,涵盖了常用的Excel需求,需要大家熟悉这个功能,主要分为基础,图片处理,时间处理,合并处理几块,name_id是上面讲的id用法,这里就不累言了

属性 类型 默认值 功能
name String null 列名,支持name_id
needMerge boolean fasle 是否需要纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row)
orderNum String "0" 列的排序,支持name_id
replace String[] {} 值得替换 导出是{a_id,b_id} 导入反过来
type int 1 导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本
width double 10 列宽
exportFormat String "" 导出的时间格式,以这个是否为空来判断是否需要格式化日期
importFormat String "" 导入的时间格式,以这个是否为空来判断是否需要格式化日期
format String "" 时间格式,相当于同时设置了exportFormat 和 importFormat
databaseFormat String "yyyyMMddHHmmss" 导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出
suffix String "" 文字后缀,如% 90 变成90%
isWrap boolean true 是否换行 即支持\n

上面的表格已经省略了很多属性了

下面直接看应用吧

1、导出类标记注解

 public class Workload extends BaseEntity {
     private static final long serialVersionUID = 1L;
      * 工作量id
     private Long id;
     @Excel(name = "类型", needMerge = true, dict = "workload_type", width = 10)
     private String type;
      * 任务信息
     @ExcelCollection(name = "任务")
     private List<Task> taskList;
      * 工作量
     @Excel(name = "工作量", needMerge = true, width = 10)
     private BigDecimal workload;
 }

这里注意

  • @ExcelCollection(name = "任务") 就是用来标记列表属性的,记得标注了这个,那么对应的类也要加上必要的注解
  • needMerge = true 表示需要合并

2、列表属性标记

 public class Task extends BaseEntity {
     private static final long serialVersionUID = 1L;
     @Excel(name = "人数")
     @Excel(name = "人数", orderNum = "10", width = 10)
     private Integer headcount;
      * 人数系数
     @Excel(name = "人数系数", orderNum = "11", width = 10)
     private BigDecimal headcountCoefficient;    
      * 难度系数
     @Excel(name = "难度系数", orderNum = "12", width = 10)
     private BigDecimal degreeCoefficient;
      * 单工作量
     @Excel(name = "单工作量", orderNum = "13", width = 10)
     private BigDecimal workload;
 }

EasyPoi 使用非常简单,到这里基本工作已经完成了

3、导出

关于导出,要做的就是在 Controller 中用 EasyPoi 处理一下查到的数据,我这里用的封装的工具类(为了配合 ruoyi 使用 )

     /**
      * 导出工作量列表
     @Log(title = "工作量", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(Workload workload) {
         List<Workload> list = workloadService.selectWorkloadList(workload);
         return ExcelExportUtil.exportExcel("教师工作量数据", Workload.class, list);
     }

导出工具类

 public class ExcelExportUtil {
     private static final Logger log = LoggerFactory.getLogger(ExcelExportUtil.class);
     private static final IExcelDictHandler EXCEL_DICT_HANDLER = new ExcelDictHandlerImpl();
     private ExcelExportUtil() {
     public static AjaxResult exportExcel(String sheetName, Class<?> pojoClass,
                                          Collection<?> dataSet) {
         OutputStream out = null;
         Workbook wb = null;
         try {
             String filename = ExcelUtil.encodingFilename(sheetName);
             ExportParams exportParams = new ExportParams(sheetName, sheetName);
             exportParams.setDictHandler(EXCEL_DICT_HANDLER);
             out = new FileOutputStream(ExcelUtil.getAbsoluteFile(filename));
             wb = cn.afterturn.easypoi.excel.ExcelExportUtil.exportExcel(exportParams, pojoClass, dataSet);
             wb.write(out);
             return AjaxResult.success(filename);
         } catch (Exception e) {
             log.error("导出Excel异常{}", e.getMessage());
             throw new UtilException("导出Excel失败,请联系网站管理员!");
         } finally {
             IOUtils.closeQuietly(wb);
             IOUtils.closeQuietly(out);
 }

不知道我故意遗漏了 dict = "workload_type" 没说,有注意到没

这是 EasyPoi 提供的一个关于字典转换的,简单说就是

我们导入输入“小明”,会通过字典查询对应的值,生成对应类属性,(小明)->(0)

导出也是同样,只要有对应的字典数据,都是可以完成的

字典使用

只需实现 IExcelDictHandler 接口即可,再

 public class ExcelDictHandlerImpl implements IExcelDictHandler {
     private static final Logger log = LoggerFactory.getLogger(ExcelDictHandlerImpl.class);
      * 从值翻译到名称
      * @param dict  字典Key
      * @param obj   对象
      * @param name  属性名称
      * @param value 属性值
      * @return
     @Override
     public String toName(String dict, Object obj, String name, Object value) {
         log.debug(dict, obj, name, value);
         return DictUtils.getDictLabel(dict, String.valueOf(value));
      * 从名称翻译到值
      * @param dict  字典Key
      * @param obj   对象
      * @param name  属性名称
      * @param value 属性值
      * @return