Alibaba EasyExcel用于导入Excel表
参考:https://www.yuque.com/easyexcel/doc/fill 官网
一、前言
书接上文(EasyExcel的导出),这里用代码案例讲下EasyExcel导入的用法。
二、使用步骤
1.涉及数据表
这里我们使用员工表
2.表对应的实体类
@Data
@ApiModel("员工")
public class Employe {
@ExcelIgnore
private Integer id;
@ExcelProperty(value = "姓名", index = 0)
private String name;
@ExcelProperty(value = "年龄", index = 1)
private Integer age;
@ExcelProperty(value = "生日", index = 2)
@DateTimeFormat(value = "yyyy-MM-dd")
private Date birth;
}
这里使用的是EasyExcel中@DateTimeFormat(value = "yyyy-MM-dd")
注解。可以对Excel表中日期数据,进行格式处理。
在此处有个小坑,“private Date birth;”这里birth是Date类型,所以数据库连接驱动要改成中国时间,如:“?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC”
要改为“?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai”
,不然下面测试数据,1997年10月1日到数据库后会变成1997-09-30;也可以将birth改为String类型,这样就不用改数据库连接驱动。
3.Controller层
@RestController
@RequestMapping("/employe")
@Api(tags = "EmployeController", description = "员工管理")
public class EmployeController {
@Autowired
private EmployeService employeService;
@PostMapping("/importEmployeExcel")
@ApiOperation("导入员工信息")
public String importEmployeExcel(@ApiParam("导入的文件") @RequestBody MultipartFile file) {
try {
employeService.importEmployeExcel(file);
} catch (Exception e) {
e.printStackTrace();
return "导入失败";
}
return "导入成功";
}
}
其中使用到spring boot注解加swagger2注解,稍后使用swagger2进行测试
4.Service层(重点)
@Service
public class EmployeServiceImpl implements EmployeService {
@Autowired
private EmployeDao employeDao;
@Override
public void importEmployeExcel(MultipartFile file) throws Exception {
EasyExcel.read(file.getInputStream(), Employe.class, new AnalysisEventListener<Employe>() {
/**
* 批处理阈值,作用:减轻数据库的压力
*/
private static final int BATCH_COUNT = 2;
/**
* 存储员工对象
*/
List<Employe> list = new ArrayList<Employe>(BATCH_COUNT);
//easyExcel每次从Excel中读取一行数据就会调用一次invoke方法
@Override
public void invoke(Employe employe, AnalysisContext analysisContext) {
list.add(employe);
if (list.size() >= BATCH_COUNT) {
employeDao.addBatch(list);
list.clear();
}
}
//easyExcel在将Excel表中数据读取完毕后,最终执行此方法
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
//最后,如果size<BATCH_COUNT就在这里进行数据的处理
if (list.size() > 0) {
employeDao.addBatch(list);
}
}
// 在此匿名内部类的方法里,throw new ExcelAnalysisStopException()就会终止easyExcel的运行。
/**
*
* @param exception
* @param context
* @throws Exception
*/
@Override
public void onException(Exception exception, AnalysisContext context) {
// 此方法能接住,在此匿名内部类的方法里抛出的异常,并进行处理,然后继续invoke方法。
}
}).sheet().doRead();//sheet()参数指定,默认读取第一张工作表
}
}
5.Dao层
public interface EmployeDao {
int addBatch(List<Employe> employes);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.expect.easyexcel.user.dao.EmployeDao">
<insert id="addBatch" parameterType="com.expect.easyexcel.user.domain.Employe">
insert into employe values
<foreach collection="list" item="employe" separator=",">
(null,#{employe.name},#{employe.age},#{employe.birth})
</foreach>
</insert>
</mapper>
注意:dao接口需要被扫描到才能完成映射
6.准备数据
注意:表头必须加,EasyExcel是从第二行开始读取数据的,亲测过。
7.数据库结果
至此,我们导入数据的目的达到了,可是有个小小的问题,Service层使用了匿名内部内,造成程序略显臃肿,如果是大家,大家会用什么方法呢?
下面我使用工作代码中看到的,再通过查找资料学到的一种方法。
1.首先,定义一个获取AnalysisEventListener对象的工具类
public class EasyExcelUtils {
/**
* @param consumer 传入一个消费者接口对象,作用:业务逻辑处理
* @param thresshold 批处理阈值,作用:减轻数据库的压力
* @param <T> 实体类
* @return
*/
public static <T> AnalysisEventListener<T> getListener(Consumer<List<T>> consumer, int thresshold) {
return new AnalysisEventListener<T>() {
/**
* 存储员工对象
*/
List<T> list = new ArrayList<T>(thresshold);
//easyExcel每次从Excel中读取一行数据就会调用一次invoke方法
@Override
public void invoke(T t, AnalysisContext analysisContext) {
list.add(t);
if (list.size() >= thresshold) {
consumer.accept(list);
list.clear();
}
}
//easyExcel在将Excel表中数据读取完毕后,最终执行此方法
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
//最后,如果size<thresshold就在这里进行数据的处理
if (list.size() > 0) {
consumer.accept(list);
}
}
};
}
}
2.把Service层改写
@Service
public class EmployeServiceImpl implements EmployeService {
@Autowired
private EmployeDao employeDao;
@Override
public void importEmployeExcel(MultipartFile file) throws Exception {
EasyExcel.read(file.getInputStream(),Employe.class, EasyExcelUtils.getListener(this.process(),2)).sheet().doRead();
}
public Consumer<List<Employe>> process(){
return employes -> employeDao.addBatch(employes);
}
小结:这样做就是将AnalysisEventListener中的invoke方法和doAfterAllAnalysed方法代码格式固定后,不同的业务逻辑代码都在Consumer中的accept方法中完成,达到了解耦,代码也不会显得臃肿。
8.最后附上依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--MySQL数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!--MyBatis Plus 依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--Swagger-UI API文档生产工具-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--解决Swagger 2.9.2版本NumberFormatException-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.0</version>
</dependency>
<!--excel文件处理-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
三、结尾
欢迎留言。