在管理一个系统时,总会有许多的数据,为了方便浏览查看数据,系统总会提供「导出Excel」的功能;有导出就有导入,在要向数据库中插入大量的数据时,我们向程序提供准备好的 Excel,然后程序读取表格内容,并将数据添加到数据库中。
实现这个「导入/导出 Excel」的功能也不复杂,我们使用第三方的类库即可实现。
技术选型
能够实现「导入/导出 Excel」的第三方常用类库有 Apache poi、Java Excel(JXL)和阿里巴巴开源的 Easyexcel 等。这么多类库该怎么选呢?在这里我给大家推荐阿里巴巴开源的「Easyexcel」。
性能对比
poi 和 jxl 对内存的消耗很大,在处理大批量的数据时,容易造成内存溢出。比如处理一个 3M 的 Excel,poi 和 jxl 可能需要上百兆的内存,但 easyexcel 可能只需要几百或几千 KB(内存消耗对比有些夸张)。在性能这一块,Excel 完全是吊打 poi 和 jxl。学习复杂度对比
我最开始使用的是 poi。在学习它的时候,理解起来不难,就是操作的时候太特么的难了。因为 poi 需要自己处理数据,还有复杂的表格样式,就光是处理数据这一款就很头疼了。等你写好所有的代码,没有几百行,你是实现不了的。反观 easyexcel。它能自己处理数据,表格格式也简单,即使是小白也很容易上手。在学习复杂的这块也吊打 poi,而 jxl 我没了解,但多半也是被吊打。
项目结构
pom.xml
在项目中需要额外添加 EasyExcel 和文件上传的依赖(需要上传 Excel)。需要注意的时,EasyExcel 和 Apache poi 存在冲突,所以需要在项目中去除 poi 的依赖,然而我们并没有在项目引入 poi 的依赖,又怎么会又 poi 呢?这是因为在我们的项目中,有其它包依赖于 poi,而我们就需要将其找出来,并去除其中的 poi 依赖。最简单的方法就是一个个试。
.........
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<!-- 去除 poi -->
<exclusions>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</exclusion>
</exclusions>
<version>${org.slf4j-version}</version>
</dependency>
<!-- 文件上传依赖 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
</dependency>
<!--Alibaba-Excel-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.1.2-beat1</version>
</dependency>
ExcelListener
使用 EasyExcel,我们需要继承 AnalysisEventListener
。
public class ExcelListener extends AnalysisEventListener {
//可以通过实例获取该值
private List<Object> datas = new ArrayList<Object>();
public void invoke(Object o, AnalysisContext analysisContext) {
datas.add(o);//数据存储到list,供批量处理,或后续自己业务逻辑处理。
doSomething(o);//根据自己业务做处理
}
private void doSomething(Object object) {
//1、入库调用接口
}
public List<Object> getDatas() {
return datas;
}
public void setDatas(List<Object> datas) {
this.datas = datas;
}
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// datas.clear();//解析结束销毁不用的资源
}
}
其中, invoke()
和 doAfterAllAnalysed()
是必须实现的方法。
在 invoke()
中,我们将数据封装到 list
中,再在控制器中,通过 getter()
方法获取数据,这样我们就可以获取到 easyexcel
帮我们解析好的数据,再将数据进行类型转化,这样,我们就可以对数据进行写入操作。
Category
这是一个实体类。我们导出 Excel 时,有时需要表头,如果需要表头,我们就可以在相应的实体类中加入 @ExcelProperty(value = "id", index = 0)
注解,并且继承 BaseRowModel
。其中 value 代表在导出 Excel 时,该字段对应的表头名称;index 代表该字段对应的表头位置。
public class Catagory extends BaseRowModel {
@ExcelProperty(value = "id", index = 0)
private Integer id;
@ExcelProperty(value = "name", index = 1)
private String name;
.........
}
ExcleController
作为程序的控制器,其中包含 导入/导出 Excel 的 @RequestMapping
。
/expor
这是导出 Excel 的控制器,导出的思路也很简单。
添加响应头信息;
添加 ExcelWriter;
添加 Sheet(表单);
添加数据;
输出。
@RequestMapping("/expor")
public String exporExcel(HttpServletResponse response) throws IOException {
ExcelWriter writer = null;
OutputStream outputStream = response.getOutputStream();
try {
//添加响应头信息
response.setHeader("Content-disposition", "attachment; filename=" + "catagory.xls");
response.setContentType("application/msexcel;charset=UTF-8");//设置类型
response.setHeader("Pragma", "No-cache");//设置头
response.setHeader("Cache-Control", "no-cache");//设置头
response.setDateHeader("Expires", 0);//设置日期头
//实例化 ExcelWriter
writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLS, true);
//实例化表单
Sheet sheet = new Sheet(1, 0, Catagory.class);
sheet.setSheetName("目录");
//获取数据
List<Catagory> catagoryList = excleService.findAll();
//输出
writer.write(catagoryList, sheet);
writer.finish();
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
response.getOutputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
return "index";
}
/import
这是导入 Excel 的控制器,实现思路与导入的思路类似,不过这个不需添加响应头信息。
实例化 ExcelListener;
实例化 ExcelReader;
读取表格信息;
向数据库插入数据。
@RequestMapping("/import")
public String importExcel(@RequestParam("file") MultipartFile file) throws IOException {
InputStream inputStream = file.getInputStream();
//实例化实现了AnalysisEventListener接口的类
ExcelListener listener = new ExcelListener();
//传入参数
ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener);
//读取信息
excelReader.read(new Sheet(1, 1, Catagory.class));
//获取数据
List<Object> list = listener.getDatas();
List<Catagory> catagoryList = new ArrayList<Catagory>();
Catagory catagory = new Catagory();
//转换数据类型,并插入到数据库
for (int i = 0; i < list.size(); i++) {
catagory = (Catagory) list.get(i);
catagoryMapper.insertCategory(catagory);
}
return "index";
}
JSP
涉及到文件的上传,所以在 JSP 中,需要注意 form
的 enctype
类型。不然,你在上传文件时会一直报错。
<form action="${pageContext.request.contextPath}/import", method="post", enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit">
</form>
写到这里,程序的主要代码也看的差不多了,其它的代码请查看项目源码。
导出 Excel 效果
JSP 效果
点击获取项目源码