SpringBoot整合EasyExcel的完整过程记录

网友投稿 404 2022-09-10


SpringBoot整合EasyExcel的完整过程记录

目录为什么要用EasyExcel1.EasyExcel简介2.使用EasyExcel实现写2.1 创建实体类2.2 测试写Excel3.使用EasyExcel实现读3.1 创建读取操作的监听器3.2 测试读Excel4.springboot项目实践EasyExcel4.1 pom中引入相关依赖4.2 创建数据库表及添加数据4.3 实体类4.4 Controller层4.5 Service层4.6 创建监听器(核心部分)4.7 结果展示总结

为什么要用EasyExcel

由于apache poi和jxl,excelPOI都有一个严重的问题,就是非常消耗内存,特别处理数据量多时,速度慢并且时有异常发生,所以改用由阿里研发的easyExcel更可靠一些,它的官方建议对于1000行以内的采用原来poi的写法一次读写,但于1000行以上的数据,有用了一行行进行解析的方案,这样避免了内存的溢出。

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 getData() {

List 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 {

/**

* 一行一行读取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 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 =http:// "D:\\write.xlsx";

//传入三个参数:文件路径+封装的类的class+监听器

EasyExcel.read(fileName, DemoData.class,new ExcelListener())

.sheet()

.doRead();

}

}

控制台输出如下

4.springboot项目实践EasyExcel

通过在后台管理上传excel文件添加课程分类(一共两级分类)

4.1 pom中引入相关依赖

com.alibaba

easyexcel

3.0.5

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(shttp://ubjectService)).sheet().doRead();

} catch (Exception e) {

e.printStackTrace();

}

}

4.6 创建监听器(核心部分)

/**

* @author xppll

* @date 2021/12/3 12:02

*/

@Component

public class SubjectExcelListener extends AnalysisEventListener {

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 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 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模板如下

上传后数据库数据如下

如果想要详细使用可以参考官方文档:EasyExcel

总结


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:poj3180 The Cow Prom
下一篇:双连通分量模板(连通分量例子)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~