SpringBoot+EasyPOI实现快速excel导入导出
使用场景
SpringBoot可以快速使用EasyPOI
进行便捷的导入导出,这里是一份简单的教程,包含导入
和导出
部分。
EasyPoi的主要特点
- 设计精巧,使用简单
- 接口丰富,扩展简单
- 默认值多,write less do more
- AbstractView 支持,web导出可以简单明了
官方gitee:https://gitee.com/lemur/easypoi
什么场景该用哪个方法
-
导出
- 正规excel导出 (格式简单,数据量可以,5W以内吧)
注解方式: ExcelExportUtil.exportExcel(ExportParams entity, Class<?> pojoClass,Collection<?> dataSet) - 不定多少列,但是格式依然简单数据库不大
自定义方式: ExcelExportUtil.exportExcel(ExportParams entity, List entityList,Collection<?> dataSet) - 数据量大超过5W,还在100W以内
注解方式 ExcelExportUtil.exportBigExcel(ExportParams entity, Class<?> pojoClass,IExcelExportServer server, Object queryParams)
自定义方式: ExcelExportUtil.exportBigExcel(ExportParams entity, List excelParams,IExcelExportServer server, Object queryParams) - 样式复杂,数据量尽量别大
模板导出 ExcelExportUtil.exportExcel(TemplateExportParams params, Map<String, Object> map) - 一次导出多个风格不一致的sheet
模板导出 ExcelExportUtil.exportExcel(Map<Integer, Map<String, Object>> map,TemplateExportParams params) - 一个模板但是要导出非常多份
模板导出 ExcelExportUtil.exportExcelClone(Map<Integer, List<Map<String, Object>>> map,TemplateExportParams params) - 模板无法满足你的自定义,试试html
自己构造html,然后我给你转成excel ExcelXorHtmlUtil.htmlToExcel(String html, ExcelType type) - 数据量过百万级了.放弃excel吧,csv导出
注解方式: CsvExportUtil.exportCsv(CsvExportParams params, Class<?> pojoClass, OutputStream outputStream)
自定义方式: CsvExportUtil.exportCsv(CsvExportParams params, List entityList, OutputStream outputStream)
9. word导出
模板导出: WordExportUtil.exportWord07(String url, Map<String, Object> map)
10. PDF导出
模板导出: TODO
-
导入
如果想提高性能 ImportParams 的concurrentTask 可以帮助并发导入,仅单行,最小1000
excel有单个的那种特殊读取,readSingleCell 参数可以支持- 不需要检验,数据量不大(5W以内)
注解或者MAP: ExcelImportUtil.importExcel(File file, Class<?> pojoClass, ImportParams params) - 需要导入,数据量不大
注解或者MAP: ExcelImportUtil.importExcelMore(InputStream inputstream, Class<?> pojoClass, ImportParams params) - 数据量大了,或者你有特别多的导入操作,内存比较少,仅支持单行
SAX方式 ExcelImportUtil.importExcelBySax(InputStream inputstream, Class<?> pojoClass, ImportParams params, IReadHandler handler) - 数据量超过EXCEL限制,CSV读取
小数据量: CsvImportUtil.importCsv(InputStream inputstream, Class<?> pojoClass,CsvImportParams params)
大数据量: CsvImportUtil.importCsv(InputStream inputstream, Class<?> pojoClass,CsvImportParams params, IReadHandler readHandler)
- 不需要检验,数据量不大(5W以内)
- 正规excel导出 (格式简单,数据量可以,5W以内吧)
关于Excel导出XLS和XLSX区别
- 导出时间XLS比XLSX快2-3倍
- 导出大小XLS是XLSX的2-3倍或者更多
- 导出需要综合网速和本地速度做考虑~
几个工程的说明
- easypoi 父包–作用大家都懂得
- easypoi-annotation 基础注解包,作用与实体对象上,拆分后方便maven多工程的依赖管理
- easypoi-base 导入导出的工具包,可以完成Excel导出,导入,Word的导出,Excel的导出功能
- easypoi-web 耦合了spring-mvc 基于AbstractView,极大的简化spring-mvc下的导出功能
- sax 导入使用xercesImpl这个包(这个包可能造成奇怪的问题哈),word导出使用poi-scratchpad,都作为可选包了
maven
maven库直接导入即可,最新版本4.2.0
,用新不用旧,可以在 https://mvnrepository.com/search?q=EasyPOI
检查一下是否是最新版本。
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.2.0</version>
</dependency>
Annotation注解解析
@Excel
重点关注即可
,这个是必须使用的注解,如果需求简单只使用这一个注解也是可以的,涵盖了常用的Excel需求,需要大家熟悉这个功能,附上属性详解。
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
name |
String |
null |
列名,支持name_id |
needMerge |
boolean |
fasle |
是否需要纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row) |
orderNum |
String |
"0" |
列的排序,支持name_id |
replace |
String[] |
{} |
值得替换导出是{a_id,b_id} 导入反过来 |
savePath |
String |
"upload" |
导入文件保存路径,如果是图片可以填写,默认是upload/className/ IconEntity这个类对应的就是upload/Icon/ |
type |
int |
1 |
导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本 |
width |
double |
10 |
列宽 |
height |
double |
10 |
列高,后期打算统一使用@ExcelTarget的height,这个会被废弃,注意 |
isStatistics |
boolean |
fasle |
自动统计数据,在追加一行统计,把所有数据都和输出这个处理会吞没异常,请注意这一点 |
isHyperlink |
boolean |
false |
超链接,如果是需要实现接口返回对象 |
isImportField |
boolean |
true |
校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败,支持name_id |
exportFormat |
String |
"" |
导出的时间格式,以这个是否为空来判断是否需要格式化日期 |
importFormat |
String |
"" |
导入的时间格式,以这个是否为空来判断是否需要格式化日期 |
format |
String |
"" |
时间格式,相当于同时设置了exportFormat 和 importFormat |
databaseFormat |
String |
"yyyyMMddHHmmss" |
导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出 |
numFormat |
String |
"" |
数字格式化,参数是Pattern,使用的对象是DecimalFormat |
imageType |
int |
1 |
导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的 |
suffix |
String |
"" |
文字后缀,如% 90 变成90% |
isWrap |
boolean |
true |
是否换行 即支持\n |
mergeRely |
int[] |
{} |
合并单元格依赖关系,比如第二列合并是基于第一列 则{0}就可以了 |
mergeVertical |
boolean |
fasle |
纵向合并内容相同的单元格 |
fixedIndex |
int |
-1 |
对应excel的列,忽略名字 |
isColumnHidden |
boolean |
false |
导出隐藏列 |
@ExcelTarget
限定一个到处实体的注解,以及一些通用设置,作用于最外面的实体
@ExcelEntity
标记是不是导出excel 标记为实体类,一遍是一个内部属性类,标记是否继续穿透,可以自定义内部id
@ExcelCollection
一对多的集合注解,用以标记集合是否被数据以及集合的整体排序
DEMO
在实战之前请看一份的DEMO
代码,寻找灵感。
- 无需处理的例如id信息。
- 需要处理的普通字段信息,带必须判断,否则报错。
- 前缀后缀 suffix/prefix
- 需要处理的是/否,男/女等简单判断信息。
- 需要处理的日期格式。
@Data
public class User implements java.io.Serializable {
/**
* id(不处理,无需id)
*/
private String id;
/**
* 姓名(必须)
*/
@Excel(name = "姓名", width = 30, isImportField = "true_st")
private String name;
/**
* 性别
*/
@Excel(name = "性别", replace = { "男_1", "女_2" }, suffix = "人", isImportField = "true_st")
private int gender;
@Excel(name = "创建时间", databaseFormat = "yyyy年MM月dd日 HH:mm:ss", format = "yyyy-MM-dd", isImportField = "true_st", width = 20)
private Date createTime;
}
导出实战
以下内容来自真实项目
并做DEMO化处理。
实体类
isImportField = "true_st"
表示导入必须字段。width
,具体什么是合适的宽度,这个可以自己在excel拖动一个单元格大小进行检查。
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @description 个人证书
* @author zhengkai.blog.csdn.net
* @date 2020-07-29
*/
@Data
public class CertPerson implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
/**
* id
*/
private Integer certId;
/**
* 证书
*/
@Excel(name = "证书编码", width = 30 ,isImportField = "true_st")
private String certNumber;
/**
* 姓名
*/
@Excel(name = "姓名", width = 10 ,isImportField = "true_st")
private String certName;
/**
* 身份证号码
*/
@Excel(name = "证件号", width = 30 ,isImportField = "true_st")
private String personId;
/**
* 颁发日期
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "发证时间", databaseFormat = "yyyy年MM月dd日", format = "yyyy-MM-dd", isImportField = "true_st", width = 20)
private Date certValidateStart;
/**
* 认证课程
*/
@Excel(name = "课程名称", width = 60,isImportField = "true_st")
private String certLesson;
/**
* 工作单位
*/
@Excel(name = "单位", width = 60,isImportField = "true_st")
private String certCompany;
/**
* 备注
*/
@Excel(name = "备注", width = 20)
private String certText;
public CertPerson() {
}
}
Controller方面
-
storageService.getPathString()
为项目用到的封装方法,获取要项目保存文件的目录供上传和下载使用。 -
ReturnT
为返回封装方法,根据自己项目修改 - 查询
所需导出数据
后使用ExcelExportUtil.exportExcel
进行Workbook生成
- 使用
FilreOutputSteam
写入Workbook
对象到FilePath
具体路径
/**
* excel导出
* by zhengkai.blog.csdn.net
*/
@PostMapping("/export")
public ReturnT export(){
QueryWrapper<CertPerson> queryWrapper = new QueryWrapper<CertPerson>();
queryWrapper.orderByDesc("cert_validate_start");
List<CertPerson> pageList = certPersonMapper.selectList(queryWrapper);
Workbook workbook = ExcelExportUtil.exportExcel(
new ExportParams("证书查询系统","个人证书"),CertPerson.class, pageList);
try {
FileOutputStream fos = new FileOutputStream(storageService.getPathString()+"person_download.xls");
workbook.write(fos);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
return ReturnT.SUCCESS("person_download.xls");
}
UI交互方面
点击后台进行生成,生成后插入新的a标签,点击标签弹出进行下载。
$.ajax({
type: 'POST',
url: '${request.contextPath}/certPerson/export?token='+layui.data('token').token,
data:result,
dataType: "json",
contentType: "application/json",
success: function (responseData) {
if (responseData.code === 200) {
$("#exportArea").html('<a href="${request.contextPath}/file/files/'+responseData.msg+'"><i class="layui-icon layui-icon-download-circle"></i>点击下载excel</a>');
$("#exportArea").attr("class","layui-btn layui-btn-normal layui-btn-sm data-export-btn");
} else {
layer.msg(responseData.msg, function () {
});
}
}
});
导出效果
导入实战
为了方便测试,我们省略了上传环节
,直接复制刚才生成的person_download.xls到person_upload.xls
作为用户上传后的文件,后台直接读取该文件实现解析。
导入的基础跟导出一样都是需要对应
/**
* excel导入
* by zhengkai.blog.csdn.net
*/
@PostMapping("/import")
public ReturnT importExcel(){
ImportParams params = new ImportParams();
params.setTitleRows(1);
params.setHeadRows(1);
long start = new Date().getTime();
List<CertPerson> list = ExcelImportUtil.importExcel(
new File(storageService.getPathString()+"person_upload.xls"),
CertPerson.class, params);
//输出导入信息到控制台,执行导入业务
log.info(JSON.toJSONString(list));
//省略导入业务,根据自身项目需要进行调整
return ReturnT.SUCCESS("person_cert_export.xls");
}
检查输出的内容,控制台会把所有数据打印成json。