EasyExcel读取Excel并存取数据库
配置文件
使用MyBatis-plus+SpringBoot
首先是pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hxr</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml文件
server:
port: 8080
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/attendance_excel?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
mapper-locations: classpath:mapping/*.xml
type-aliases-package: com.hxr.entity
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
level:
com:
example:
mapper: debug
监听器(核心)
AttendanceDataListener.java
package com.hxr.util;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.hxr.entity.AttendanceData;
import com.hxr.service.AttendanceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
// 有个很重要的点Listener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class AttendanceDataListener extends AnalysisEventListener<AttendanceData> {
private static final Logger LOGGER = LoggerFactory.getLogger(AttendanceDataListener.class);
/**
* 每隔10条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 10;
List<AttendanceData> list = new ArrayList<>();
/**
* 根据业务需求,可以是一个DAO,也可以是一个service。当然如果不用存储这个对象没用。
*/
private AttendanceService attendanceService;
/* public AttendanceDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
}*/
/**
*如果要存取数据库,service从监听器里面拿取list就需要有参构造,否则直接使用会报空指针异常
*/
public AttendanceDataListener(AttendanceService attendanceService) {
this.attendanceService = attendanceService;
}
/**
* 这里写自己的业务,没有可以不要
*/
private void calculateMealTimes(AttendanceData data){
//这里写自己的业务,没有可以不要
doSomething();
}
/**
* 这个每一条数据解析都会来调用
* @param data
* @param context
*/
@Override
public void invoke(AttendanceData data, AnalysisContext context) {
calculateMealTimes(data);
String result;
result="工号:"+data.getId()+",姓名:"+data.getName()+",打卡日期:"+data.getPunchDate()
+",打卡时间:"+data.getPunchTime()+",餐补次数:"+data.getMealSupplementTimes();
//System.out.println(result);
//如果数据少,这个也可以不要
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
LOGGER.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
System.out.println(list.size()+"条数据,开始存储数据库!");
System.out.println(list);
attendanceService.save(list);
}
}
然后正常搭业务框架就行了。
实体类
AttendanceData.java
package com.hxr.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Administrator
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AttendanceData {
/**
* 部门名称
*/
private String department;
/**
* 工号
*/
private String id;
/**
* 员工姓名
*/
private String name;
/**
* 员工类别,职等型
*/
private String category;
/**
* 打卡日期
*/
private String punchDate;
/**
* 当天的打卡次数
*/
private String frequency;
/**
* 打卡时间
*/
private String punchTime;
/**
* 时间,最早打卡和最晚打卡时间的间隔
*/
private String totalTime;
/**
* 餐补次数
*/
private String mealSupplementTimes;
}
Controller层
AttendanceController.java
package com.hxr.controller;
import com.alibaba.excel.EasyExcelFactory;
import com.hxr.entity.AttendanceData;
import com.hxr.service.AttendanceService;
import com.hxr.util.AttendanceDataListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Administrator
*/
@RestController
public class AttendanceController {
@Autowired
private AttendanceService attendanceService;
@PostMapping("/insert")
public String insertAttendance(){
String PATH="C:\\Users\\Administrator\\Desktop\\新建文件夹\\";
String fileName = PATH+"0081.xls";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcelFactory.read(fileName, AttendanceData.class, new AttendanceDataListener(attendanceService)).sheet().doRead();
return "添加成功!";
}
}
Service层
AttendanceService.java
package com.hxr.service;
import com.hxr.entity.AttendanceData;
import java.util.List;
/**
* @author Administrator
*/
public interface AttendanceService {
/**添加数据到数据库
* @param list
* @return
*/
Integer save(List<AttendanceData> list);
}
AttendanceServiceImpl.java
package com.hxr.service.impl;
import com.hxr.entity.AttendanceData;
import com.hxr.mapper.AttendanceMapper;
import com.hxr.service.AttendanceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author Administrator
*/
@Service
public class AttendanceServiceImpl implements AttendanceService {
@Autowired
private AttendanceMapper attendanceMapper;
@Override
public Integer save(List<AttendanceData> list){
return attendanceMapper.insertAttendance(list);
}
}
Mapper层
AttendanceMapper.java
package com.hxr.mapper;
import com.hxr.entity.AttendanceData;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。
*
* @author Administrator*/
@Repository
public interface AttendanceMapper{
/**将list存储到数据库中
* @param list
* @return
*/
Integer insertAttendance(List<AttendanceData> list);
}
AttendanceMapper.xml
<?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.hxr.mapper.AttendanceMapper">
<insert id="insertAttendance" parameterType="java.util.List">
insert into attendance(department,id,name,category,punch_date,frequency,punch_time,total_time,meal_supplement_times)
values
<foreach collection="list" item="item" separator=",">
(#{item.department}, #{item.id},#{item.name}, #{item.category}, #{item.punchDate},#{item.frequency},#{item.punchTime}, #{item.totalTime},#{item.mealSupplementTimes} )
</foreach>
</insert>
</mapper>
总结
其实读都很好读,关键是将读出来的数据存取到数据库中。
在监听器中,得到的list类型是不能被Service调用的,需要在监听器中定义有参Service,然后在Controller层里面去调用。直接拿监听器里面的list使用会报空指针异常。