SpringBoot整合Easyexcel操作Excel,闲暇之余,让我们学习更多

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

  • @param context

*/

@Override

public void doAfterAllAnalysed(AnalysisContext context) {

// 这里也要保存数据,确保最后遗留的数据也存储到数据库

saveData();

LOGGER.info(“所有数据解析完成!”+count);

}

/**

  • 加上存储数据库

*/

private void saveData() {

LOGGER.info(“{}条数据,开始存储数据库!”, list.size());

//进行数据库层面操作

demoMapper.save(list);

LOGGER.info(“存储数据库成功!”);

}

}

mapper层:此处只是模拟

/**

  • @Author: crush

  • @Date: 2021-10-31 11:39

  • version 1.0

*/

@Repository

public class DemoMapper {

public void save(List demoModels){

System.out.println(“Mapper:”+demoModels);

}

}

类型转换

2.2、读单个Sheet

/**

  • demo1 最简单的读

  • 我们先操作单个的Sheet,进行读操作

    • 1. 创建excel对应的实体对象 参照{@link QuestionModel}

    • 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DocumentListener}

    • 3. 直接读即可

*/

@Test

public void demo1TestRead() {

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去

// 写法1:

String fileName = “E:\project_code\commons-utils\springboot-excel\src\main\resources\excel\demo.xlsx”;

// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭

EasyExcel.read(fileName, DemoModel.class, new DemoListener()).sheet().doRead();

}

这里我们无需指定sheet,因为我们就一个工作表,直接默认就完事了。

控制台输出:

23:35:52.583 [main] INFO com.crush.excel.listener.DemoListener - 解析到一条数据:{“communityName”:“掘金”,“email”:“nzc_wyh@163.com”,“homePageUrl”:“https://juejin.cn/user/2859142558267559”,“name”:“宁在春”,“specialty”:“Java后端开发”,“startDate”:“2021-10-31 12:01:52”}

23:35:52.584 [main] INFO com.crush.excel.listener.DemoListener - 解析到一条数据:{“communityName”:“CSDN”,“email”:“nzc_wyh@163.com”,“homePageUrl”:“https://blog.csdn.net/weixin_45821811?spm=1000.2115.3001.5343”,“name”:“宁在春”,“specialty”:“Java后端开发”,“startDate”:“2020-05-11 12:01:52”}

23:35:52.585 [main] INFO com.crush.excel.listener.DemoListener - 2条数据,开始存储数据库!

Mapper:[DemoModel(name=宁在春, communityName=掘金, homePageUrl=https://juejin.cn/user/2859142558267559, specialty=Java后端开发, email=nzc_wyh@163.com, startDate=2021-10-31 12:01:52), DemoModel(name=宁在春, communityName=CSDN, homePageUrl=https://blog.csdn.net/weixin_45821811?spm=1000.2115.3001.5343, specialty=Java后端开发, email=nzc_wyh@163.com, startDate=2020-05-11 12:01:52)]

23:35:52.617 [main] INFO com.crush.excel.listener.DemoListener - 存储数据库成功!

23:35:52.618 [main] INFO com.crush.excel.listener.DemoListener - 所有数据解析完成!2

这是最简单的方式,也是读取Excel中,单个Sheet的操作,但我们平时中,一个excel是会有多个工作表的。

如下:

2.3、读多个Sheet

image-20211031204647817

其实本质上还是操作单个sheet工作表。

因为各个Sheet的数据不同,因而要建立多个Model和多个监听类。

这边就不再把全部model贴出了,如果不太明白,可以去文末看看源码。

image-20211031211039694

同时也要创建多个监听器。

image-20211031213105078

mapper层在这里就省略了哈。

/**

  • 读多个或者全部sheet,这里注意一个sheet不能读取多次,多次读取需要重新读取文件

    1. 创建excel对应的实体对象 参照{@link QuestionModel}
    1. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DocumentListener}
    1. 直接读即可

*/

@Test

public void repeatedRead() {

String fileName = “E:\project_code\commons-utils\springboot-excel\src\main\resources\excel\Document_Success.xlsx”;

// 读取需要读取的Sheet

ExcelReader excelReader = EasyExcel.read(fileName).build();

// 自己使用功能必须不同的Listener

ReadSheet readSheet1 =

EasyExcel.readSheet(0).head(DocumentModel.class).registerReadListener(new DocumentListener()).build();

ReadSheet readSheet2 =

EasyExcel.readSheet(1).head(TemplateModel.class).registerReadListener(new TemplateListener()).build();

ReadSheet readSheet3 =

EasyExcel.readSheet(2).head(SectionModel.class).registerReadListener(new SectionListener()).build();

ReadSheet readSheet4 =

EasyExcel.readSheet(3).head(QuestionModel.class).registerReadListener(new QuestionListener()).build();

ReadSheet readSheet5 =

EasyExcel.readSheet(4).head(OptionModel.class).registerReadListener(new OptionListener()).build();

ReadSheet readSheet6 =

EasyExcel.readSheet(5).head(ConditionModel.class).registerReadListener(new ConditionListener()).build();

ReadSheet readSheet7 =

EasyExcel.readSheet(6).head(QuestionTooltipModel.class).registerReadListener(new QuestionTooltipListener()).build();

ReadSheet readSheet8 =

EasyExcel.readSheet(7).head(OptionTooltipModel.class).registerReadListener(new OptionTooltipListener()).build();

// 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能

excelReader.read(readSheet1, readSheet2, readSheet3, readSheet4, readSheet5, readSheet6, readSheet7, readSheet8);

// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的

excelReader.finish();

}

控制台输出:

23:42:19.733 [main] INFO com.crush.excel.listener.DocumentListener - 解析到一条数据:{“customerId”:1,“name”:“Document i”}

23:42:19.755 [main] INFO com.crush.excel.listener.TemplateListener - 解析到一条数据:{“documentType”:1,“fontStyleId”:1,“lobId”:1,“name”:“Template q”,“userGroupId”:1}

23:42:19.785 [main] INFO com.crush.excel.listener.SectionListener - 解析到一条数据:{“index”:1,“name”:“Section 1”,“order”:1}

23:42:19.785 [main] INFO com.crush.excel.listener.SectionListener - 解析到一条数据:{“index”:2,“name”:“Section 2”,“order”:2}

23:42:19.823 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{“allowComments”:“false”,“answerType”:“1”,“enhancedField”:“false”,“index”:“1”,“order”:“1”,“question”:“This is Simple Question”,“required”:“true”,“sectionIndex”:“1”}

23:42:19.824 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{“allowComments”:“false”,“answerType”:“2”,“enhancedField”:“false”,“index”:“2”,“order”:“2”,“question”:“This is Simple Question”,“required”:“false”,“sectionIndex”:“1”}

23:42:19.825 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{“allowComments”:“false”,“answerType”:“10”,“enhancedField”:“false”,“index”:“3”,“order”:“3”,“question”:“This is Simple Question”,“required”:“false”,“sectionIndex”:“1”}

23:42:19.826 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{“allowComments”:“false”,“answerType”:“3”,“enhancedField”:“false”,“index”:“4”,“order”:“1”,“question”:“This is Simple Question”,“required”:“true”,“sectionIndex”:“2”}

23:42:19.827 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{“allowComments”:“false”,“answerType”:“5”,“enhancedField”:“false”,“index”:“5”,“order”:“2”,“question”:“This is Simple Question”,“required”:“false”,“sectionIndex”:“2”}

23:42:19.831 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{“allowComments”:“false”,“answerType”:“12”,“enhancedField”:“false”,“index”:“6”,“order”:“3”,“question”:“This is Simple Question”,“required”:“true”,“sectionIndex”:“2”}

23:42:19.847 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{“index”:1,“order”:1,“questionIndex”:3,“value”:“Option 1”}

23:42:19.848 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{“index”:2,“order”:2,“questionIndex”:3,“value”:“Option 2”}

23:42:19.849 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{“index”:3,“order”:3,“questionIndex”:3,“value”:“Option 3”}

23:42:19.849 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{“index”:4,“order”:4,“questionIndex”:3,“value”:“Option 4”}

23:42:19.850 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{“index”:5,“order”:1,“questionIndex”:6,“value”:“Option 1”}

23:42:19.850 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{“index”:6,“order”:2,“questionIndex”:6,“value”:“Option 2”}

23:42:19.851 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{“index”:7,“order”:3,“questionIndex”:6,“value”:“Option 3”}

23:42:19.868 [main] INFO com.crush.excel.listener.ConditionListener - 解析到一条数据:{“action”:1,“index”:1,“questionIndex”:1,“selectedAnswer”:“Test”,“triggerQuestionIndex”:1,“triggerSectionIndex”:1}

23:42:19.869 [main] INFO com.crush.excel.listener.ConditionListener - 解析到一条数据:{“action”:1,“index”:2,“questionIndex”:2,“selectedAnswer”:“Test”,“triggerSectionIndex”:2}

23:42:19.888 [main] INFO com.crush.excel.listener.QuestionTooltipListener - 解析到一条数据:{“endIndex”:10,“index”:1,“parentIndex”:1,“startIndex”:1,“text”:“Sample Tooltip”}

23:42:19.908 [main] INFO com.crush.excel.listener.OptionTooltipListener - 解析到一条数据:{“endIndex”:10,“index”:1,“parentIndex”:1,“startIndex”:1,“text”:“Sample Tooltip”}

23:42:19.910 [main] INFO com.crush.excel.listener.OptionTooltipListener - 解析到一条数据:{“endIndex”:10,“index”:2,“parentIndex”:2,“startIndex”:1,“text”:“Sample Tooltip”}

我们可以在获取到数据的时候,存储进数据库。另外我们常常会上传excel,进行数据的导入,所以我们再来看看web中的excel的读。

2.4、web中的读

@AutowiredDemoMapper demoMapper;/** * 文件上传 *

* 1. 创建excel对应的实体对象 参照{@link UploadData} *

* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} *

* 3. 直接读即可 */@PostMapping(“upload”)@ResponseBodypublic String upload(MultipartFile file) throws IOException { EasyExcel.read(file.getInputStream(), DemoModel.class, new DemoListener(demoMapper)).sheet().doRead(); return “success”;}

image-20211101000304010

image-20211101000349426

我想这样的场景是我们在Web开发中最常用到的那种。

如果是内存足够,数据量不是特别大的话,像我这么写也是完全能够接受的。

如果是操作数据十万或几十万数据的大兄弟,可以前去官网看看优化方案。👉Easyexcel | github

三、写Excle操作 writeExcel


3.1、写到单个Sheet中

/**

  • 最简单的写

  • 1. 创建excel对应的实体对象 参照{@link DemoModel}

  • 2. 直接写即可

*/

@Test

public void simpleWrite() {

DemoModel model = new DemoModel();

model.setName(“宁在春”);

model.setCommunityName(“知乎”);

model.setHomePageUrl(“https://www.zhihu.com/creator/manage/creation/all”);

model.setEmail(“nza_wyh@163.com”);

model.setSpecialty(“SpringBoot”);

model.setStartDate(“2021-10-31 12:00:00”);

DemoModel model2 = new DemoModel();

model2.setName(“宁在春2”);

model2.setCommunityName(“知乎2”);

model2.setHomePageUrl(“2https://www.zhihu.com/creator/manage/creation/all”);

model2.setEmail(“nza_wyh@163.com2”);

model2.setSpecialty(“SpringBoot2”);

model2.setStartDate(“2021-10-31 12:00:00”);

List models = new ArrayList();

models.add(model);

models.add(model2);

// 写法1

String fileName = “E:\project_code\commons-utils\springboot-excel\src\main\resources\excel\demo2.xlsx”;

// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭

// 如果这里想使用03 则 传入excelType参数即可

EasyExcel.write(fileName, DemoModel.class).sheet(0).doWrite(models);

// // 写法2

// // 这里 需要指定写用哪个class去写

ExcelWriter excelWriter = EasyExcel.write(fileName, DemoModel.class).build();

WriteSheet writeSheet = EasyExcel.writerSheet(0).build();

excelWriter.write(models, writeSheet);

// 千万别忘记finish 会帮忙关闭流

excelWriter.finish();

}

这是操作excel文件中单个Sheet的操作,十分简单。

EasyExcel.write(fileName, DemoModel.class).sheet(0).doWrite(models);关于sheet()中的参数0,我们其实就一张Sheet工作表,填与不填其实都一样,另外,此处也可以填sheet表名字,也是一样 。

操作结果:

image-20211101004643750

注意:

注意:我发现如果我是直接向这个excel文件进行写入,默认是采用覆盖的方式进行写入,即之前有的信息都会被覆盖掉。

测试:

写之前:

image-20211101004951295

写之后:

image-20211101005021227

补充:

如果我们直接写,是采用覆盖模式的,这肯定是不符合一些业务场景的。所以肯定有解决方式的,

easyexcel中对此也是有处理的。

它有一个根据模板写入,模板如下:

image-20211101010819547

/**

  • 根据模板写入

  • 1. 创建excel对应的实体对象 参照

  • 2. 使用 注解指定写入的列

  • 3. 使用withTemplate 写取模板

  • 4. 直接写即可

*/

@Test

public void templateWrite() {

DemoModel model = new DemoModel();

model.setName(“宁在春”);

model.setCommunityName(“知乎”);

model.setHomePageUrl(“https://www.zhihu.com/creator/manage/creation/all”);

model.setEmail(“nza_wyh@163.com”);

model.setSpecialty(“SpringBoot”);

model.setStartDate(“2021-10-31 12:00:00”);

DemoModel model2 = new DemoModel();

model2.setName(“宁在春2”);

model2.setCommunityName(“知乎2”);

model2.setHomePageUrl(“2https://www.zhihu.com/creator/manage/creation/all”);

model2.setEmail(“nza_wyh@163.com2”);

model2.setSpecialty(“SpringBoot2”);

model2.setStartDate(“2021-10-31 12:00:00”);

List models = new ArrayList();

models.add(model);

models.add(model2);

String templateFileName = “E:\project_code\commons-utils\springboot-excel\src\main\resources\excel\demo2.xlsx”;

String fileName = “E:\project_code\commons-utils\springboot-excel\src\main\resources\excel\templateWrite.xlsx”;

// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭

EasyExcel.write(fileName, DemoModel.class).withTemplate(templateFileName).sheet().doWrite(models);

}

最后的效果如下:

image-20211101011041698

写到注意那一小节的时候,我也有考虑这个是如何进行处理的。

我最开始想的是,是先把文件读出来,然后把数据拼接起来,再写进去。但是我一下就推翻这个想法,一旦那样做,内存消耗什么的都太大了,不太合适。

然后简单看了一下,它是直接new了一个File,加载进内存。(觉得自己好憨)


因为这个我又去测试了个不同的,如果把模板修改的不符合会咋样。

image-20211101085113831

测试的结果就是符合我的猜测,就是copy了一份原文件,在源文件的基础上进行写操作,不管原文件格式如何,都会进行保留。

image-20211101085258579

3.2、重复写入或写到多个Sheet中

重复写入:

其实就是循环了单个的操作。

// 方法1 如果写到同一个sheet

String fileName = “E:\project_code\commons-utils\springboot-excel\src\main\resources\excel\demo2.xlsx”;

// // 这里 需要指定写用哪个class去写

ExcelWriter excelWriter = EasyExcel.write(fileName, DemoModel.class).build();

WriteSheet writeSheet = EasyExcel.writerSheet(0).build();

// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来

for (int i = 0; i < 5; i++) {

// 分页去数据库查询数据 这里可以去数据库查询每一页的数据

List data = data();

excelWriter.write(data, writeSheet);

}

// 千万别忘记finish 会帮忙关闭流

excelWriter.finish();

data()就是生成数据的一个方法。

写到多个Sheet中:

其本质也是上面那样,只是调用不同监听类,不同的对象罢了,更简单的方式,以做到不同的处理,目前还没有找到更简单的方法。

和读多个sheet中一样的方式,在此处就不再复述了。

3.3、web中的写

既然有写就要也有读了,有始有终,这个也给大家贴出来了。

/**

  • 文件下载(失败了会返回一个有部分数据的Excel)

面试题总结

其它面试题(springboot、mybatis、并发、java中高级面试总结等)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
ata, writeSheet);

}

// 千万别忘记finish 会帮忙关闭流

excelWriter.finish();

data()就是生成数据的一个方法。

写到多个Sheet中:

其本质也是上面那样,只是调用不同监听类,不同的对象罢了,更简单的方式,以做到不同的处理,目前还没有找到更简单的方法。

和读多个sheet中一样的方式,在此处就不再复述了。

3.3、web中的写

既然有写就要也有读了,有始有终,这个也给大家贴出来了。

/**

  • 文件下载(失败了会返回一个有部分数据的Excel)

面试题总结

其它面试题(springboot、mybatis、并发、java中高级面试总结等)

[外链图片转存中…(img-6j0uaym2-1713573169540)]

[外链图片转存中…(img-SOsx8kpr-1713573169540)]

[外链图片转存中…(img-y54R6HOQ-1713573169540)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-XLFzxUqk-1713573169541)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,可以给你提供一个思路。 首先,需要在SpringBoot中引入EasyExcel的依赖,可以通过以下方式在pom.xml文件中添加: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.9</version> </dependency> ``` 接着,需要编写一个Controller来接收上传的Excel文件,并读取其中的内容,解析成MySQL建表语句并返回字符串。可以参考以下代码: ```java @RestController public class ExcelController { @PostMapping("/upload") public String uploadExcel(@RequestParam("file") MultipartFile file) throws IOException { // 读取Excel文件 InputStream inputStream = file.getInputStream(); ExcelReader excelReader = new ExcelReader(inputStream, null, new ExcelListener()); excelReader.read(); // 获取解析出来的建表语句 List<String> createTableSqls = ExcelListener.getCreateTableSqls(); // 将建表语句拼接成一个字符串返回 StringBuilder sb = new StringBuilder(); for (String createTableSql : createTableSqls) { sb.append(createTableSql).append("\n"); } return sb.toString(); } /** * EasyExcel的监听器,用于解析Excel内容并生成建表语句 */ public static class ExcelListener extends AnalysisEventListener<List<String>> { private static List<String> createTableSqls = new ArrayList<>(); private static final String TABLE_NAME_PREFIX = "table_"; private static final String COLUMN_NAME_PREFIX = "col_"; @Override public void invoke(List<String> rowData, AnalysisContext context) { // 生成建表语句 String tableName = TABLE_NAME_PREFIX + context.getCurrentSheet().getSheetNo(); StringBuilder sb = new StringBuilder(); sb.append("CREATE TABLE ").append(tableName).append(" (\n"); for (int i = 0; i < rowData.size(); i++) { String columnName = COLUMN_NAME_PREFIX + i; sb.append(" ").append(columnName).append(" VARCHAR(255)"); if (i != rowData.size() - 1) { sb.append(","); } sb.append("\n"); } sb.append(");"); createTableSqls.add(sb.toString()); } @Override public void doAfterAllAnalysed(AnalysisContext context) { // 解析完成后清空缓存 createTableSqls.clear(); } public static List<String> getCreateTableSqls() { return createTableSqls; } } } ``` 上面的代码中,我们定义了一个ExcelListener类作为EasyExcel的监听器,用于解析Excel内容并生成建表语句。在Controller中,我们将上传的Excel文件读取并交给ExcelListener来处理,最终将生成的建表语句拼接成一个字符串返回。 需要注意的是,上面的代码中生成的建表语句只是一个示例,具体的生成规则需要根据实际情况进行修改。 希望这个思路能对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值