【SpringBoot】三十七、SpringBoot整合EasyPoi自定义字典导出Excel

前面我们介绍了 SpringBoot 中使用 JeecgBoot 的 Autopoi 导出 Excel,其实 Autopoi 的底层也是 EasyPoi,对于 Excel 的导入/导出也是非常方便的。那 EasyPoi 也是基于 POI 的,如果对这方面想要深究的,可以先看看原生 POI 的导入/导出方式,你会回来选择 EasyPoi 的

一、简介

EasyPoi 功能如同名字 easy,主打的功能就是容易,让一个没见接触过poi的人员就可以方便的写出 Excel 导出,Excel 模板导出,Excel 导入,Word 模板导出,通过简单的注解和模板语言(熟悉的表达式语法),完成以前复杂的写法

如果想了解 JeecgBoot 的 Autopoi,可以参考我的另一篇博客,SpringBoot 中使用 JeecgBoot 的 Autopoi 导出 Excel

https://blog.csdn.net/qq_40065776/article/details/107824221

二、引入 EasyPoi

EasyPoi 在 SpringBoot 中也是做了很好的封装,让我们能够在 SpringBoot 快速地使用 EasyPoi 进行开发

<!-- easypoi -->
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-spring-boot-starter</artifactId>
    <version>4.2.0</version>
</dependency>

我们只需要引入这一个依赖即可,这是对 SpringBoot 做了很好的支持

三、源码解读

1、@Excel 源码解读

通过查阅源码,我们不难从 cn.afterturn.easypoi.excel.annotation.Excel 注解中发现

/**
 * Copyright 2013-2015 JueYue (qrb.jueyue@gmail.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.afterturn.easypoi.excel.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Excel 导出基本注释
 * @author JueYue
 *  2014年6月20日 下午10:25:12
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel {

    /**
     * 导出时,对应数据库的字段 主要是用户区分每个字段, 不能有annocation重名的 导出时的列名
     * 导出排序跟定义了annotation的字段的顺序有关 可以使用a_id,b_id来确实是否使用
     */
    public String name();

    /**
     * 展示到第几个可以使用a_id,b_id来确定不同排序
     */
    public String orderNum() default "0";

    /**
     * 值得替换  导出是{a_id,b_id} 导入反过来,所以只用写一个
     */
    public String[] replace() default {};
    /**
     *  字典名称
     */
    public String dict() default  "";
}

以上是 @Excel 注解的代码片段,我们可以看出该注解中支持两种字典替换方式

  • 1、replace,该方式支持直接写入注解参数中,如:
@Excel(name = "性别", width = 15, replace = "男_1,女_2")
@TableField("sex")
private Integer sex;

我们用 1 表示 男性,2 表示 女性,这样我们在导出的时候,就能够自动替换掉数据中的魔法值,但是这样我们往往要在注解参数中写入过多的代码,而且我们的字典往往是动态变化的,这样的局限性太大

  • 2、dict,字典方式,传入字典参数中,如:
@Excel(name = "性别", width = 15, dict = "sex")
@TableField("sex")
private Integer sex;

这里我们只传入的字典的 key,这样我们在查询出数据的时候,写入 Excel 文件时,在进行动态替换,即可替换掉数据中的魔法值,增加数据的可读性

2、IExcelDictHandler 源码解读

上一步,我们已经知道了在 EasyPoi 中是支持自定义字典查询导出的,那么我们该如何实现它呢?通过阅读 cn.afterturn.easypoi.handler.inter.IExcelDictHandler 接口中的代码,代码如下:

package cn.afterturn.easypoi.handler.inter;

import java.util.List;
import java.util.Map;

/**
 * @author jueyue on 18-2-2.
 * @version 3.0.4
 */
public interface IExcelDictHandler {

    /**
     * 返回字典所有值
     * key: dictKey
     * value: dictValue
     * @param dict  字典Key
     * @return
     */
    default public List<Map> getList(String dict) {
        return null;
    }

    /**
     * 从值翻译到名称
     *
     * @param dict  字典Key
     * @param obj   对象
     * @param name  属性名称
     * @param value 属性值
     * @return
     */
    public String toName(String dict, Object obj, String name, Object value);

    /**
     * 从名称翻译到值
     *
     * @param dict  字典Key
     * @param obj   对象
     * @param name  属性名称
     * @param value 属性值
     * @return
     */
    public String toValue(String dict, Object obj, String name, Object value);
}

接口中提供了三个方法:

  • 1、getList,通过字典 key 查询该 key 下的所有字典数据,例如:sex 下的 {“1”:“男”, “2”:“女”}
  • 2、toName,字典的翻译功能,从值翻译到名称,例如:sex: 1 --> “男”,一般导出的时候使用
  • 3、toValue,与 toName 相反,从名称翻译到值,例如:sex: “男” --> 1,一般导入的时候使用

既然我们知道在 EasyPoi 中提供了字典翻译的接口,那我们只需要提供一个实现类,重写接口中的方法即可,IExcelDictHandlerImpl.java 实现 IExcelDictHandler 接口,代码如下:

package com.zyxx.common.excel;

import cn.afterturn.easypoi.handler.inter.IExcelDictHandler;
import com.zyxx.sys.service.SysDictDetailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 支持字典参数设置
 * 举例: @Excel(name = "性别", width = 15, dicCode = "sex")
 * 1、导出的时候会根据字典配置,把值1,2翻译成:男、女;
 * 2、导入的时候,会把男、女翻译成1,2存进数据库;
 *
 * @Author lizhou
 */
@Slf4j
@Component
public class IExcelDictHandlerImpl implements IExcelDictHandler {

    @Autowired
    private SysDictDetailMapper testSysDictDetailMapper;
    private static SysDictDetailMapper sysDictDetailMapper;

    @PostConstruct
    public void init() {
        sysDictDetailMapper = this.testSysDictDetailMapper;
    }

    /**
     * 从值翻译到名称
     *
     * @param dict  字典Key
     * @param obj   对象
     * @param name  属性名称
     * @param value 属性值
     * @return
     */
    @Override
    public String toName(String dict, Object obj, String name, Object value) {
        return sysDictDetailMapper.getTextByDictAndValue(dict, String.valueOf(value));
    }

    /**
     * 从名称翻译到值
     *
     * @param dict  字典Key
     * @param obj   对象
     * @param name  属性名称
     * @param value 属性值
     * @return
     */
    @Override
    public String toValue(String dict, Object obj, String name, Object value) {
        return null;
    }
}
  • 1、这里我们导出,只使用了 toName(从值翻译到名称)这个方法,所以,只写了一个方法
  • 2、我们需要使用 @Component 注解将它加载到 Spring 容器中
  • 3、@PostConstruct 该注解被用来修饰一个非静态的 void() 方法。被 @PostConstruct 修饰的方法会在服务器加载 Servlet 的时候运行,并且只会被服务器执行一次。PostConstruct 在构造函数之后执行,init() 方法之前执行

四、开始导出

1、定义实体类

package com.zyxx.sys.entity;

import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.zyxx.common.annotation.Dict;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 * 用户信息表
 * </p>
 *
 * @author lizhou
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("sys_user_info")
@ApiModel(value = "SysUserInfo对象", description = "用户信息表")
public class SysUserInfo extends Model<SysUserInfo> {


    @ApiModelProperty(value = "ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @Excel(name = "姓名", width = 15)
    @ApiModelProperty(value = "姓名")
    @TableField("name")
    private String name;

    @Excel(name = "电话", width = 15)
    @ApiModelProperty(value = "电话")
    @TableField("phone")
    private String phone;

    @Excel(name = "性别", width = 15, dict = "sex")
    @TableField("sex")
    @Dict(dictCode = "user_sex")
    private Integer sex;

    @Excel(name = "状态", width = 15, dict = "status")
    @TableField("status")
    private Integer status;
}

@Excel 注解解释如下:

  • name,表头名称
  • width,列宽
  • dict,字典 key

2、导出 API 接口

controller 层提供导出 API

@ApiOperation(value = "导出用户信息", notes = "导出用户信息")
@GetMapping(value = "/export")
public void exportXls(HttpServletResponse response) {
	// 查询数据
    List<SysUserInfo> list = sysUserInfoService.list(1, Integer.MAX_VALUE);
    // 导出数据,数据,数据类型,文件名称,表名,响应对象
    ExportExcelUtil.exportExcel(list, SysUserInfo.class, "用户信息表", "用户信息统计", response);
}

3、导出工具类

/**
* 导出excel
*
* @param list 数据集合
* @param pojoClass 数据类型
* @param fileName 文件名称
* @param title 表明
* @param response 响应对象
*/
public static void exportExcel(List<?> list, Class<?> pojoClass, String fileName, String title, HttpServletResponse response) {
   ExportParams exportParams = new ExportParams(title, null);
   // 自定义字典查询规则
   exportParams.setDictHandler(new IExcelDictHandlerImpl());
   Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
   if (workbook != null) {
       try {
           response.setCharacterEncoding("UTF-8");
           response.setHeader("content-Type", "application/vnd.ms-excel");
           response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
           workbook.write(response.getOutputStream());
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

exportParams.setDictHandler(new IExcelDictHandlerImpl());,我们传入了自定义的字典查询规则

五、测试导出

我们调取导出数据的 API 接口,即可导出文件,导出效果如下:

导出文件

导出结果

六、总结

可以看出,自定义字典查询导出方式,其实和 JeecgBoot 的 Autopoi 方式都大同小异,后面是发现了 JeecgBoot 的 Autopoi 和 hutool 的读取文件 ExcelReader 有冲突,放弃了 JeecgBoot 的 Autopoi,EasyPoi 确实是一款强大的 Excel 操作产品!!!

如您在阅读中发现不足,欢迎留言!!!

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页