轻松玩转Excel,springboot集成easyexcel
最近这不又接到一个需求,上游用户想要下载上报给我们的列表数据,用来进行一些简单的线下分析。
用户的需求必须满足啊!于是我就吭哧吭哧的找到俺的chrome大哥,立即所搜”springboot下载json数据“的模板代码,妄图通过CV大法快速实现用户需求。
后来转念一想,用户想要的仅是列表数据,如果下载一个json数据还要让用户进行预处理才能进行分析,体验也太不友好了😗😗,于是决定直接下载一个Excel文件。
Excel文件下载没搞过啊😫😫,chrome大哥又得靠你了😂😂。
最先找到是apache-poi,这个就有点吊了,通过该lib,我们能够使用Java读写Microsoft Office文档,这不就是用Java写Word、PPT啥的么😮😮。了解该lib的基础功能后,我去找了下”通过apache poi读写excel“的模板代码😘😘。好家伙!!!暂且不说性能怎么样,这一个一个单元格的操作方法就能够累死人,虽然说操作的细致程度非常高。但是对我来说仅是想要一个api能够将List数据转化成Excel就行了,越简单越好。
造轮子的事情工作之外可以做,工作内还是要效率第一。
后面就碰到了EasyExcel,发现用起来真的非常方便。于是便想写一篇小文章记录下整个集成过程,也方便后续查阅。
1、搭建springboot web工程
这个相信各位老司机都轻车熟路了,这里也不过多叙述了,实在不行IDEA的Spring Initializr也是非常好用的工具。
2、引入EasyExcel的依赖包
这里我使用的是3.1.3的版本,读者可以使用最新的版本哈。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.3</version>
</dependency>
3、下载Excel
首先我们准备一个非常简单的bean,作为列表的元数据。
该bean有三个字段,自然而然,最终生成的Excel也将有三列,分别对应这三个字段。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private int age;
private String name;
private String address;
}
接下来写下载接口,顶层的RequestMapping
这里仅写一次,大家知道后面的接口路径都有/easyexcel
前缀就行了。
核心是download接口,该接口逻辑主要分三步:
- 准备数据。这里只要准备一个List格式的数据就行,元数据就用我们上面的bean即可。读者可以根据自己的业务需要进行调整。
- 设置响应。这里我们要将响应数据设置为excel格式。
- 写入数据。这个就是Easyexcle非常棒的地方,它提供了非常简洁的API供用户使用,只需要一行代码就能够将List列表转化为Excel文件。write方法指定输出流和写入数据的class对象;sheet方法指定excel的sheet名称;doWrite则指定写入的列表数据。
@RestController
@RequestMapping("/easyexcel")
public class EasyexcelController {
@GetMapping("/download")
public void download(HttpServletResponse response) {
try {
// 准备数据
List<Student> studentList = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
Student s = new Student();
s.setAge(i * 10 + 1);
s.setName("name" + i);
s.setAddress("address" + i);
studentList.add(s);
}
// 设置响应
response.setContentType("application/vnd.excel");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("file", "UTF-8").replaceAll("\+", "%20");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
// 写入数据
EasyExcel.write(response.getOutputStream(), Student.class).sheet("sheet1").doWrite(studentList);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行应用,在浏览器网址栏输入http://localhost:8080/easyexcel/download,即可看到文件已经被下载下来啦。
打开文件看下,内容就是上面生成的列表数据。
4、读取Excel
我们先来写一个最简单的读接口。
依旧在上面的EasyexcelController
,我们添加如下读接口:
@GetMapping("/read")
public void readExcel() {
// 这里换成你们的excel文件路径
File file = new File("FilePath");
EasyExcel.read(file, Student.class, new ReadListener<Student>() {
@Override
public void invoke(Student s, AnalysisContext analysisContext) {
System.out.println(s);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("read finished");
}
}).sheet("sheet1").doRead();
}
执行结果如下所示:
最最最简单的读接口可以看到代码量非常的少,主要就是下面几步:
- 构造文件对象File。EasyExcel提供的API非常丰富,我们可以构造一个File对象,也可以通过文件路径直接读取;
- 调用
EasyExcel.read()
函数读取文件。这里我们需要指定文件file,指定反序列化的类对象以及一个监听器。上面我们直接使用匿名内部类的方式创建了ReadListener
监听器。该监听器的invoke
方法会在读取完Excel的每一行记录时调用一次,doAfterAllAnalysed
方法会在读取完全部数据后调用一次。EasyExcel这么设计的目的是:一些Excel的内容非常多,几千上万行。如果把数据全部读取到内存中,机器肯定吃不消。因此设计了invoke
方法,每次读取完一行记录回调一次,我们可以在这里进行一些定制化操作,比如每读取100行就将数据持久化到数据库中,然后清空内存再读取下100条数据。doAfterAllAnalysed
方法则可以最终兜底,处理最后未持久化的数据。
持久化的代码如下所示:
@GetMapping("/read")
public void readExcel() {
// 这里换成你们的excel文件路径
File file = new File("FilePath");
EasyExcel.read(file, Student.class, new ReadListener<Student>() {
public static final int CACHE_SIZE = 100;
private List<Student> cached = new ArrayList<>(CACHE_SIZE);
@Override
public void invoke(Student s, AnalysisContext analysisContext) {
cached.add(s);
if (cached.size() >= CACHE_SIZE) {
saveData();
cached = new ArrayList<>(CACHE_SIZE);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
saveData();
}
}).sheet("sheet1").doRead();
}
5、上传Excel
最简单的上传接口如下所示:
@GetMapping("/upload")
public void upload(MultipartFile file) {
try {
EasyExcel.read(file.getInputStream(), Student.class, new ReadListener<Student>() {
@Override
public void invoke(Student s, AnalysisContext analysisContext) {
System.out.println(s);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("read finished");
}
}).sheet("sheet1").doRead();
} catch (Exception e) {
e.printStackTrace();
}
}
可以看出写法上和读取Excel接口非常类似,只不过我们通过web的方式接收了Excel文件而已。
该接口的请求结果如下所示:
6、写入Excel
写Excel和下载Excel也非常类似,只不过一个是写入文件当中,一个是写入到网络流当中。
我们就用上面的Excel为例,向其中写入一个Student(age=101, name=name10, address=address10)
。
写入的代码如下:
@PostMapping("/write")
public void write(@RequestBody Student student) {
// 你的文件路径
File file = new File("FilePath");
EasyExcel.write(file, Student.class).sheet("sheet1").doWrite(Collections.singleton(student));
// 写入成功后,我们尝试读取下文件
EasyExcel.read(file, Student.class, new ReadListener<Student>() {
@Override
public void invoke(Student s, AnalysisContext analysisContext) {
System.out.println(s);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("read finished");
}
}).sheet("sheet1").doRead();
}
接口运行结果如下所示,可以看到我们成功写入了数据。
7、总结
从上面的4个接口来看,EasyExcel确实为我们提供了非常简单的API来操作Excel文件,我们仅需少量代码便可以实现强大的功能。
当然,EasyExcel的功能远不止这些,还包括“多sheet读取”、“读表头”、“数据转换”等功能,本篇文章仅是介绍了最常用的功能,大家如果有特殊需求的话,可以参考EasyExcel的官方文档 easyexcel.opensource.alibaba.com/docs/curren… ,去探索更多可能哈。
转载自:https://juejin.cn/post/7185784917895151673