近期使用EasyPOI实现了excel表格存入数据库的功能,下面介绍一下使用过程和遇到的难点。
目录
1、背景介绍
2、使用过程及注意点
1、引入依赖
2、编写实体类
3、可以开始尝试上传了
4、尝试导出
3、结语
1、背景介绍
我的项目是使用ruoyi脚手架搭建的SpringBoot项目,希望实现固定格式excle的上传功能,并且存入数据库,以及从数据库中再导出的功能。这是表格样式以及为其设计的数据表。
可以看到,表格样式有固定的一行标题,表头既有两行合并,也有单独一行。这类情况按照以往经验使用Apache POI可以完成,但比较麻烦,所有选择更为简单的EasyPOI。
2、使用过程及注意点
1、引入依赖
在pom.xml文件添加依赖
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.1.2</version>
</dependency>
或者是
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.1.2</version>
</dependency>
哪个可以用就用哪个,注意版本号要一致。
注意点1:easypoi是本身只是对poi的封装,所以引入他的jar包可以会跟其他的包产生冲突,导致项目启动失败,或是接下的错误。所有要解决jar包依赖冲突。我是使用idea的maven heler插件,可显示依赖结构,,处理依赖冲突很方便。
2、编写实体类
这里需要用到@Excel注解,当然还有其他注解比如@ExcelCollection,@ExcelEntity ,@ExcelIgnore,@ExcelTarget等,我们现在用不到。
在@Excel注解中,我用到了name(列名)、groupName(组名)、orderNum(列的排序)、fixedIndex(对应excel的列,忽略名字)。
name对应列名,比较直观,groupName对应合并项的组名,凡是有合并项的都要添加(同时之后表头列数是2,之后会讲到),orderNum可有可无影响不大。值得一提的是这个fixedIndex。因为我的的表头有合并项,刚开始只加了orderNum,只能读到合并列中的第一列。查了很多博客都没有效果,之后才知道需要fixedIndex来固定一下绝对位置。原理不清楚。
这几个注解要与自己的excel表对应,还有许多其他属性可以参考官网。完成这步是实现导入导出的关键,需要多次尝试。
@Data
@TableName("h_account")
public class HAccount extends Model<HAccount> {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@Excel(name = "序号")
private int id;
@TableField("`name`")
@Excel(name = "名称",groupName = "重大应用",orderNum = "1")
private String name;
@TableField("req_name")
@Excel(name = "需求名称",groupName = "重大需求",orderNum = "2",fixedIndex = 2)
private String reqName;
@TableField("req_type")
@Excel(name = "需求类型",groupName = "重大需求",orderNum = "3",fixedIndex = 3)
private String reqType;
@TableField("req_content")
@Excel(name = "需求内容",groupName = "重大需求",orderNum = "4",fixedIndex = 4)
private String reqContent;
@TableField("scene_framework")
@Excel(name = "基本架构",groupName = "多跨场景",orderNum = "5",fixedIndex = 5)
private String sceneFramework;
@TableField("scene_sub")
@Excel(name = "小切口子场景",groupName = "多跨场景",orderNum = "6",fixedIndex = 6)
private String sceneSub;
@TableField("reform_project")
@Excel(name = "改革项目",groupName = "重大改革",orderNum = "7",fixedIndex = 7)
private String reformProject;
@TableField("reform_task")
@Excel(name = "改革任务",groupName = "重大改革",orderNum = "8",fixedIndex = 8)
private String reformTask;
@TableField("departments")
@Excel(name = "责任单位",orderNum = "9",fixedIndex = 9)
private String departments;
@TableField("remark")
@Excel(name = "备注",orderNum = "10")
private String remark;
}
3、可以开始尝试上传了
在Controller里编写方法,通过几个easypoi的方法就可以实现读取,这就是他的easy之处。
首先注意的是引包,因为easypoi是封装的,所以会有重名,所以注意包的正确。再接着注意读取表头的设置,要与自己的表格对应上。
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
public List<HAccount> upload(@RequestParam("file") MultipartFile multipartFile,
) throws Exception {
//new一个模板
ImportParams params = new ImportParams();
//设置表格标题行数,默认0,这是读取时会跳过的行数
params.setTitleRows(1);
//表头行数,默认1。上午提到,如果有合并的列名,就要设置读取表头的行数
params.setHeadRows(2);
//开始读取,并用list接收,方便处理
List<HAccount> result = ExcelImportUtil.importExcel(multipartFile.getInputStream(), HAccount.class, params);
System.out.println(JSONUtil.toJsonStr(result));
return result;
}
通过这样就可以在控制台上看到json格式的上传结果了。再使用for each等方法对其处理,实现自己需要的功能。例如我要实现写入数据库。
4、尝试导出
在上传完成后,数据库已经有了,接下试试导出。
由于我们在实体类中给每个对象都加了@Excel注解,导出就变得十分简单,不用再用代码设计表格样式,直接导出就会显示原先的样式。
用两种办法接收文件,一是下载到本地的目录下,
public void export1(List<HAccount> result,String title) {
// 输出到本地地址
try {
ExportParams params = new ExportParams(title, "sheet1", ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(params, HAccount.class, result);
File saveFile = new File("excel");
if (!saveFile.exists()) {
saveFile.mkdirs();
}
//地址
FileOutputStream fos = new FileOutputStream("C:/Users/Desktop/55/9.xlsx");
workbook.write(fos);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
二是传给浏览器处理。
public int export( @RequestBody List<HAccount> result,
@RequestParam HttpServletResponse response){
//生成输出模板
ExportParams params = new ExportParams(title, "sheet1", ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(params, HAccount.class, result);
if(workbook==null){
return 0;
}
// 重置响应对象
response.reset();
// 当前日期,用于导出文件名称
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String dateStr = sdf.format(new Date());
// 指定下载的文件名--设置响应头
//设置输出的文件名
response.setHeader("Content-Disposition", "attachment;filename=" +dateStr+".xlsx");
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
// 写出数据输出流到页面
try {
OutputStream output = response.getOutputStream();
BufferedOutputStream bufferedOutPut = new BufferedOutputStream(output);
workbook.write(bufferedOutPut);
bufferedOutPut.flush();
bufferedOutPut.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
return 1;
}
通过以上方法的调用就可以生成与原先格式相同的excel表格。
3、结语
笔者在使用easypoi的过程遇到一些问题,网络上虽然有很多教学的博客,但由于每个人需要处理的表格都不相同,所有问题一直没能有效解决。最关键的就是@Excel注解的使用,里面的许多属性不太直观,需要反复尝试。希望以上的问答能够解决你的问题,同时也欢迎在评论区留言互动。