- EasyExcel
EasyExcel导入的用法
实体类(员工表)
@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类型,这样就不用改数据库连接驱动。
**/
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 "导入成功";
}
}
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);
}
}
}).sheet().doRead();//sheet()参数指定,默认读取第一张工作表
}
}
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>
准备数据
注意:表头必须加,EasyExcel是从第二行开始读取数据的,亲测过。
数据库结果
问题
至此,我们导入数据的目的达到了,可是有个小小的问题,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);
}
}