文章目录
- SpringBoot整合EasyExcel
- 1.EasyExcel简介
- 2.使用EasyExcel实现写
- 2.1 创建实体类
- 2.2 测试写Excel
- 3.使用EasyExcel实现读
- 3.1 创建读取操作的监听器
- 3.2 测试读Excel
- 4.springboot项目实践EasyExcel
- 4.1 pom中引入相关依赖
- 4.2 创建数据库表及添加数据
- 4.3 实体类
- 4.4 Controller层
- 4.5 Service层
- 4.6 创建监听器(核心部分)
- 4.7 结果展示
SpringBoot整合EasyExcel
1.EasyExcel简介
- Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或 者JVM频繁的full gc。
- EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一 行行读取数据,逐个解析。
- EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理 (AnalysisEventListener)
2.使用EasyExcel实现写
2.1 创建实体类
创建与
Excel
对应的实体类
/**
* @author xppll
* @date 2021/12/3 10:05
*/
@Data
public class DemoData {
//设置excel表头名称,index表示对应的第几列
@ExcelProperty(value = "学生编号",index = 0)
private Integer sno;
@ExcelProperty(value = "学生姓名",index = 1)
private String sname;
}
ExcelProperty
:指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。
2.2 测试写Excel
/**
* @author xppll
* @date 2021/12/3 10:08
*/
public class TestWriteExcel {
public static void main(String[] args) {
//实现excel写的操作
//1.设置写入文件夹的地址和excel文件名称
String fileName = "D:\\write.xlsx";
//2.调用easyexcel里面方法实现写操作
//传入:文件存放的路径+对应的实体类class
EasyExcel.write(fileName, DemoData.class).sheet("学生列表").doWrite(getData());
}
//创建方法返回list集合(测试数据)
private static List<DemoData> getData() {
List<DemoData> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();
data.setSno(i);
data.setSname("lucy" + i);
list.add(data);
}
return list;
}
}
结果如下
3.使用EasyExcel实现读
3.1 创建读取操作的监听器
/**
* @author xppll
* @date 2021/12/3 10:29
*/
public class ExcelListener extends AnalysisEventListener<DemoData> {
/**
* 一行一行读取Excel中的内容
*
* @param data
* @param analysisContext
*/
@Override
public void invoke(DemoData data, AnalysisContext analysisContext) {
System.out.println("****" + data);
}
/**
* 读取表头
* @param headMap
* @param context
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
System.out.println("表头:"+headMap);
}
/**
* 读取完成之后做的事
*
* @param analysisContext
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
3.2 测试读Excel
/**
* @author xppll
* @date 2021/12/3 10:35
*/
public class TestReadExcel {
public static void main(String[] args) {
//读取文件的路径
String fileName = "D:\\write.xlsx";
//传入三个参数:文件路径+封装的类的class+监听器
EasyExcel.read(fileName, DemoData.class,new ExcelListener())
.sheet()
.doRead();
}
}
控制台输出如下
4.springboot项目实践EasyExcel
通过在后台管理上传excel文件添加课程分类(一共两级分类)
4.1 pom中引入相关依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
4.2 创建数据库表及添加数据
这里创建一个课程表用
EasyExcel
实现课程的分类
CREATE TABLE `edu_subject` (
`id` char(19) NOT NULL COMMENT '课程类别ID',
`title` varchar(10) NOT NULL COMMENT '类别名称',
`parent_id` char(19) NOT NULL DEFAULT '0' COMMENT '父ID',
`sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序字段',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程科目';
INSERT INTO `edu_subject` VALUES ('1178214681118568449','后端开发','0',1,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681139539969','Java','1178214681118568449',1,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681181483010','前端开发','0',3,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681210843137','JavaScript','1178214681181483010',4,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681231814658','云计算','0',5,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681252786178','Docker','1178214681231814658',5,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681294729217','Linux','1178214681231814658',6,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681324089345','系统/运维','0',7,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681353449473','Linux','1178214681324089345',7,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681382809602','Windows','1178214681324089345',8,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681399586817','数据库','0',9,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681428946945','MySQL','1178214681399586817',9,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681454112770','MongoDB','1178214681399586817',10,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681483472898','大数据','0',11,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681504444418','Hadoop','1178214681483472898',11,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681529610242','Spark','1178214681483472898',12,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681554776066','人工智能','0',13,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681584136193','Python','1178214681554776066',13,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681613496321','编程语言','0',14,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681626079234','Java','1178214681613496321',14,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178585108407984130','Python','1178214681118568449',2,'2019-09-30 16:19:22','2019-09-30 16:19:22'),('1178585108454121473','HTML/CSS','1178214681181483010',3,'2019-09-30 16:19:22','2019-09-30 16:19:22');
4.3 实体类
@Data
public class SubjectData {
@ExcelProperty(index = 0)
private String oneSubjectName;
@ExcelProperty(index = 1)
private String twoSubjectName;
}
/**
* 课程科目
* @author xppll
* @since 2021-12-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="EduSubject对象", description="课程科目")
public class EduSubject implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "课程类别ID")
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
@ApiModelProperty(value = "类别名称")
private String title;
@ApiModelProperty(value = "父ID")
private String parentId;
@ApiModelProperty(value = "排序字段")
private Integer sort;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
}
4.4 Controller层
@Autowired
private EduSubjectService subjectService;
//添加课程分类
//获取前端上传过来的excel文件,把文件内容读取出来保存到数据库
@PostMapping("addSubject")
public R addSubject(MultipartFile file){
subjectService.saveSubject(file,subjectService);
return R.ok();
}
4.5 Service层
//添加课程分类
@Override
public void saveSubject(MultipartFile file, EduSubjectService subjectService) {
try {
//得到文件的输入流
InputStream in = file.getInputStream();
//调用方法进行读取
EasyExcel.read(in, SubjectData.class, new SubjectExcelListener(subjectService)).sheet().doRead();
} catch (Exception e) {
e.printStackTrace();
}
}
4.6 创建监听器(核心部分)
/**
* @author xppll
* @date 2021/12/3 12:02
*/
@Component
public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {
public EduSubjectService subjectService;
public SubjectExcelListener(EduSubjectService subjectService) {
this.subjectService = subjectService;
}
public SubjectExcelListener() {
}
//读取excel内容,一行一行读取
@Override
public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
if (subjectData == null) {
throw new GuliException(20001, "文件数据为空");
}
//一行一行读取,第一个值为一级分类,第二个值为二级分类
//先判断一级分类是否重复
EduSubject existOneSubject = this.existOneSubject(subjectData.getOneSubjectName(), subjectService);
//没有相同的一级分类
if(existOneSubject==null){
existOneSubject=new EduSubject();
existOneSubject.setParentId("0");
existOneSubject.setTitle(subjectData.getOneSubjectName());
subjectService.save(existOneSubject);
}
//获取一级分类的id值
String pid=existOneSubject.getId();
//判断二级分类是否重复
EduSubject existTwoSubject = this.existTwoSubject(subjectData.getTwoSubjectName(), subjectService, pid);
if(existTwoSubject==null){
existTwoSubject=new EduSubject();
existTwoSubject.setParentId(pid);
existTwoSubject.setTitle(subjectData.getTwoSubjectName());
subjectService.save(existTwoSubject);
}
}
//判断一级分类不能重复添加
private EduSubject existOneSubject(String name, EduSubjectService subjectService) {
LambdaQueryWrapper<EduSubject> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EduSubject::getTitle, name)
.eq(EduSubject::getParentId, "0");
EduSubject oneSubject = subjectService.getOne(queryWrapper);
return oneSubject;
}
//判断二级分类不能重复添加
private EduSubject existTwoSubject(String name, EduSubjectService subjectService,String pid) {
LambdaQueryWrapper<EduSubject> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EduSubject::getTitle, name)
.eq(EduSubject::getParentId, pid);
EduSubject twoSubject = subjectService.getOne(queryWrapper);
return twoSubject;
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
4.7 结果展示
Excel模板如下
上传后数据库数据如下