SpringStarter快速实现Excel导入导出的方法
自我介绍IT 果果
一个普通的技术宅,欢迎点赞、关注和转发,请多关照。入门和安装简介
为了满足项目中快速实现 excel 导入导出的功能,将 excel 开源工具 easypoi 整合成 spring-boot-starter 的方式,在做到对 easypoi 无侵入的同时减少了一些重复代码。例如: 增强了 easypoi 对于字段值重复校验的功能; 提升了字典转换的便捷性和效率; 增加了字段之间联动转换的功能;
这些场景也是我在平时项目上经常会用到的功能点,为了避免重复造轮子,减少冗余代码,所以写了一个 easypoix-spring-boot-starter 扩展 jar 包。 安装在你的 maven 项目中引用 maven 依赖 com.itguoguo easypoix-spring-boot-starter 1.0.0.RELEASE 在你的 spring boot 项目配置文件中加入字典前缀(可选) itguoguo.easypoix.dictPrefix=basic:dict:工具spring-boot-starter
SpringBoot 核心就是几个注解:SpringBootConfiguration、EnableAutoConfiguration、ComponentScan ,依赖这几个注解完成了所谓自动装配的功能,这个自动装配说简单点就是把你需要的 Bean 注入到 Spring 容器里面。(SpringBootApplication 启动类上的注解,只是简单的组合了 SpringBootConfiguration、EnableAutoConfiguration、ComponentScan 几个注解,避免开发者一个一个的去加)。
SpringBoot 程序在启动过程中会解析 SpringBootConfiguration、EnableAutoConfiguration、ComponentScan 三个注解 : SpringBootConfiguration:包含了 Configuration 注解,实现配置文件 ComponentScan:指定扫描范围 EnableAutoConfiguration:通过源码可以知道,该注解使用 Import 引入了 AutoConfigurationImportSelector 类,而 AutoConfigurationImportSelector 类通过 SpringFactortisLoader 加载了所有 jar 包的 MATE-INF 文件夹下面的 spring.factories 文件,spring.factories 包含了所有需要装配的 XXXConfiguration 类的全限定名。XXXConfiguration 类包含了实例化该类需要的信息,比如说如果这是个数据源 Configuration 类,那么就应该有数据库驱动、用户名、密码等等信息。
Spring Boot 在启动的时候会干这几件事情 : Spring Boot 在启动时会去依赖的 Starter 包中寻找 resources/META-INF/spring.factories 文件,然后根据文件中配置的 Jar 包去扫描项目所依赖的 Jar 包。 根据 spring.factories 配置加载 AutoConfigure 类 根据 @Conditional 注解的条件,进行自动配置并将 Bean 注入 Spring Context
总结 : SpringBoot 并没有想象那么神秘,就是这么几件事情:
1.提供了一个配置类,该配置类定义了我们需要的对象的实例化过程;
2.提供了一个 spring.factories 文件,包含了配置类的全限定名;
3.将配置类和 spring.factories 文件打包为一个启动器 starter;
4.程序启动时通过加载 starter.jar 包的 spring.factories 文件信息,然后通过反射实例化文件里面的类。easypoi
独特的功能 基于注解的导入导出,修改注解就可以修改 Excel 支持常用的样式自定义 基于 map 可以灵活定义的表头字段 支持一对多的导出,导入 支持模板的导出,一些常见的标签,自定义标签 支持 HTML/Excel 转换,如果模板还不能满足用户的变态需求,请用这个功能 支持 word 的导出,支持图片,Excel
使用 1.easypoi 父包–作用大家都懂得 2.easypoi-annotation 基础注解包,作用于实体对象上,拆分后方便 maven 多工程的依赖管理 3.easypoi-base 导入导出的工具包,可以完成 Excel 导出,导入,Word 的导出,Excel 的导出功能 4.easypoi-web 耦合了 spring-mvc 基于 AbstractView,极大的简化 spring-mvc 下的导出功能 5.sax 导入使用 xercesImpl 这个包(这个包可能造成奇怪的问题哈),word 导出使用 poi-scratchpad,都作为可选包了
Maven 坐标 cn.afterturn easypoi-base 4.1.0 cn.afterturn easypoi-web 4.1.0 cn.afterturn easypoi-annotation 4.1.0
使用场景
我们的目标是尽可能使用一个工具类方法就能实现简单的导出和导入 Excel 的功能,以下列出了几个常见的场景供参考。 简单导出 Excel实现步骤
新建一个导出实体模型,@ExcelFileAttr 注解提供导出 Excel 的文件名,@Excel 注解提供表头的字段,其中 name 属性是字段名称,dict 属性是字典的关键字常量 @Data @ExcelFileAttr(fileName = "导出.xls") public class ExportPersonExcelModal implements Serializable { @Excel(name = "姓名") private String name; @Excel(name = "性别", dict = DICT_XB) private String sex; @Excel(name = "民族", dict = DICT_MZ) private String mz; }
使用工具类 EasyPoiUtil 的 exportExcel 方法即可实现 excel 导出功能,只需要传递两个参数 。 Excel 数据列表 HttpServletResponse 输出流 EasyPoiUtil.exportExcel(list, response);比较 EasyPoi 和 EasyPoiX
相对于 EasyPoi 官方的导出方式,EasyPoiX 对于导出时字典的处理更加方便,不需要额外提供
IExcelDictHandler 实现,EasyPoi 的 IExcelDictHandler 接口两个实现方法如下: /** * 从值翻译到名称 * @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);
toName 方法用于导出时字典值到字典名称的转换;toValue 方法用于导入时字典名称到字典值的转换。如果使用 EasyPoi,则多个字典公用一个 IExcelDictHandler 接口时需要多个 if-else 判断,并且在 Excel 导入导出时重复查询同一个字典时会有效率问题,另外在项目中多个字典的查询接口往往是同一个方法,所以显得代码重复不美观。
为了解决以上问题,EasyPoiX 在导出时提供了字典转换的默认字典转换接口,且不需要在工具类中传参指定(如果有特殊要求也可以指定自定义的字典转换接口)。那么问题来了,字典的取值方法在哪里定义呢?EasyPoiX 提供了一个@ExcelDictDataType 注解和一个 ExcelDictDataService 接口,代码示例如下: @ExcelDictDataType({DICT_XB, DICT_MZ, DICT_COMMUNITY}) @Component public class BasicDictDataService implements ExcelDictDataService { public static final String DICT_XB = "XB"; public static final String DICT_MZ = "MZ"; @Override public Map getData(DataParam params) { // 获取字典值的实现代码 // 不论是字典的名称转值还是值转名称,都会从这里取值 // 返回的 Map 类型,key 是字典值,value 是字典名称 return map; } }IExcelDictHandler 接口,要在导出方法里显示的传参;ExcelDictDataService 接口不需要显示传参,因为@ExcelDictDataType 注解已经标注当前类就是字典取值的实现类,注解的 value()属性里配置的是字典的 key,可以提供多个字典的 key,所以 ExcelDictDataService 接口可以满足多个字典的取值。 IExcelDictHandler 接口需要正反向两个转换方法;ExcelDictDataService 接口只需要实现一个字典取值方法。 IExcelDictHandler 接口需要在实现方法中加入多个 if-else,并且在 Excel 导入导出时频繁调用 toName 和 toValue 方法会导致效率问题;ExcelDictDataService 接口不需要通过 if-else 判断,且每次取值都会先从本地缓存中查询,如果缓存没有才会进行真正的查询调用。在一次请求结束之后,会清除这些缓存以免造成内存不足。 大数据导出 Excel实现步骤
使用工具类 EasyPoiUtil 的 exportBigExcel 方法即可实现 excel 大数据导出功能,传参: 实体模型 Class IExcelExportServer 接口。可以使用默认接口实现类 DefaultBigExcelExportServer,构造方法需要提供一个分页查询的 lamda 表达式 分页查询的条件参数,Object 类型 HttpServletResponse 输出流 DefaultBigExcelExportServer ser = new DefaultBigExcelExportServer((queryParams, page) -> findPage(queryParams, page)); EasyPoiUtil.exportBigExcel(ExportPersonExcelModal.class, ser, param, response);比较 EasyPoi 和 EasyPoiX
EasyPoi 需要实现 IExcelExportServer 接口,EasyPoiX 不需要实现,而是传递一个 DefaultBigExcelExportServer 对象,构造对象时提供一个分页查询的 lamda 表达式
或者叫分页查询方法。这样的好处是不需要为每一个 Excel 都单独新建一个 IExcelExportServer 接口实现类。 /** * 导出数据接口 */ public interface IExcelExportServer { /** * 查询数据接口 * @param queryParams 查询条件 * @param page 当前页数从 1 开始 * @return */ public List