EasyPOI
简介
官网
http://doc.wupaas.com/docs/easypoi/easypoi-1c0u6ksp2r091
介绍
Easypoi的目标不是替代poi,而是让一个不懂导入导出的快速使用poi完成Excel和word的各种操作,而不是看很多api才可以完成这样工作
独特的功能
- 基于注解的导入导出,修改注解就可以修改Excel
- 支持常用的样式自定义
- 基于map可以灵活定义的表头字段
- 支持一堆多的导出,导入
- 支持模板的导出,一些常见的标签,自定义标签
- 支持HTML/Excel转换,如果模板还不能满足用户的变态需求,请用这个功能
- 支持word的导出,支持图片,Excel
引入POM
- 1.easypoi 父包–作用大家都懂得
- 2.easypoi-annotation 基础注解包,作用与实体对象上,拆分后方便maven多工程的依赖管理
- 3.easypoi-base 导入导出的工具包,可以完成Excel导出,导入,Word的导出,Excel的导出功能
- 4.easypoi-web 耦合了spring-mvc 基于AbstractView,极大的简化spring-mvc下的导出功能
- 5.sax 导入使用xercesImpl这个包(这个包可能造成奇怪的问题哈),word导出使用poi-scratchpad,都作为可选包了
如果不使用spring mvc的便捷福利,直接引入easypoi-base 就可以了,easypoi-annotation
如果使用maven,请使用如下坐标
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.1.0</version>
</dependency>
Excel注解版
基本注解
easypoi起因就是Excel的导入导出,最初的模板是实体和Excel的对应,model–row,filed–col 这样利用注解我们可以和容易做到excel到导入导出
经过一段时间发展,现在注解有5个类分别是
- @Excel 作用到filed上面,是对Excel一列的一个描述
- @ExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,科目就可以用集合表示
- @ExcelEntity 表示一个继续深入导出的实体,但他没有太多的实际意义,只是告诉系统这个对象里面同样有导出的字段
- @ExcelIgnore 和名字一样表示这个字段被忽略跳过这个导导出
- @ExcelTarget 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做出不同处理
例1-基本功能示例
实体类
@Data
@ExcelTarget("User表")
public class User implements Serializable {
@Excel(name = "编号")
private String id;
@Excel(name = "姓名")
private String name;
@Excel(name = "年龄")
private Integer age;
@Excel(name = "生日")
private Date bir;
}
业务类
//模拟查询数据库
public List<User> getUsers(){
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(String.valueOf(i));
user.setName("sb"+i);
user.setAge(5+i);
user.setBir(new Date());
users.add(user);
}
return users;
}
@Test
public void testExport() throws IOException {
// 获取数据
List<User> users = getUsers();
// 导出excel
// 参数1:exportParams 导出配置对象 参数2:导出的类型 参数3:导出数据集合
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("用户信息表", "用户信息"), User.class, users);
// 将excel写入指定位置
FileOutputStream outputStream = new FileOutputStream("E:\\新建文件夹\\test.xlsx");
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
结果
@Excel注解参数
这个是必须使用的注解,如果需求简单只使用这一个注解也是可以的,涵盖了常用的Excel需求,需要大家熟悉这个功能,主要分为基础,图片处理,时间处理,合并处理几块,name_id是上面讲的id用法,这里就不累言了
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
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 | 导出隐藏列 |
例2-单元格宽度及格式示例
我们发现在例1中所创建出来的单元格大小都一致,从而就出现了压缩长单元格内容的问题,利用上述的参数width即可改变
实体类
@Data
@ExcelTarget("User表")
public class User implements Serializable {
@Excel(name = "编号")
private String id;
@Excel(name = "姓名")
private String name;
@Excel(name = "年龄")
private Integer age;
// 改变单元格宽度及日期的时间格式
@Excel(name = "生日",width=35,format = "yyyy-MM-dd HH:mm:ss")
private Date bir;
}
结果
例3-部分属性功能示例
实体类
@Data
@ExcelTarget("User表")
public class User implements Serializable {
// orderNum可以使每一列按照从小到大的方式排列,值越小的列越靠左
@Excel(name = "编号",orderNum = "0")
private String id;
@Excel(name = "姓名",orderNum = "1")
private String name;
@Excel(name = "年龄",orderNum = "2")
private Integer age;
// 改变单元格宽度及日期的时间格式
@Excel(name = "生日",width=35,format = "yyyy-MM-dd HH:mm:ss",orderNum = "4")
private Date bir;
// replace的格式为{"xx_xx","xx_xx"...},在“_”之前的为将要替换成的值,之后的为被替换掉的值
@Excel(name = "用户状态",replace = {"激活_1","锁定_0"},orderNum = "5")
private Integer status;
// suffix将会在值后加一个后缀
@Excel(name = "存款",suffix = "$",orderNum = "3")
private Integer money;
}
业务类
//模拟查询数据库
public List<User> getUsers(){
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(String.valueOf(i));
user.setName("sb"+i);
user.setAge(5+i);
user.setBir(new Date());
if (i%2==0){
user.setStatus(1);
}else
user.setStatus(0);
user.setMoney(i*50);
users.add(user);
}
return users;
}
结果
例4-list导出
实体类
// @ExcelIgnore可以忽略该属性的导出
@ExcelIgnore
private List<String> habbys;
// 为了让上方的list能够正常的按格式导出,我们使用以下方式,将list拼接成一个字符串,再导出
@Excel(name = "爱好", width = 20, orderNum = "6")
private String habbyStr;
public String getHabbyStr() {
final StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < habbys.size(); i++) {
stringBuilder.append(habbys.get(i));
if (i < habbys.size() - 1) {
stringBuilder.append("、");
}
}
return stringBuilder.toString();
}
业务类
//模拟查询数据库
public List<User> getUsers(){
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(String.valueOf(i));
user.setName("sb"+i);
user.setAge(5+i);
user.setBir(new Date());
user.setCard(card);
if (i%2==0){
user.setStatus(1);
user.setHabbys(Arrays.asList("唱","跳","rap"));
}else {
user.setStatus(0);
user.setHabbys(Arrays.asList("dota","lol","wow"));
}
user.setMoney(i*50);
users.add(user);
}
return users;
}
结果
例5-一对一对象导出
实体类
// @ExcelEntity标志此为一对一关系
@ExcelEntity
private Card card;
@Data
@ExcelTarget("身份证信息")
public class Card implements Serializable {
//此处的orderNum也可以用来主序排列
@Excel(name = "身份证号码",width = 20,orderNum = "7")
private String cardID;
@Excel(name = "住址",width = 20,orderNum = "8")
private String address;
}
业务类
//模拟查询数据库
public List<User> getUsers(){
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(String.valueOf(i));
user.setName("sb"+i);
user.setAge(5+i);
user.setBir(new Date());
Card card = new Card();
card.setCardID("这里是身份证号!");
card.setAddress("桃花源北区8栋2单元"+i+"楼");
user.setCard(card);
if (i%2==0){
user.setStatus(1);
user.setHabbys(Arrays.asList("唱","跳","rap"));
}else {
user.setStatus(0);
user.setHabbys(Arrays.asList("dota","lol","wow"));
}
user.setMoney(i*50);
users.add(user);
}
return users;
}
结果
例6-一对多对象导出
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ExcelTarget("订单信息")
public class Order implements Serializable {
@Excel(name = "订单号",width = 15,orderNum = "9")
private String orderID;
@Excel(name = "订单名",width = 10,orderNum = "10")
private String orderName;
}
// @ExcelCollection标志此为一对多关系
@ExcelCollection(name = "订单列表",orderNum = "8")
private List<Order> orders;
业务类
//模拟查询数据库
public List<User> getUsers(){
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(String.valueOf(i));
user.setName("sb"+i);
user.setAge(5+i);
user.setBir(new Date());
// 身份
Card card = new Card();
card.setCardID("这里是身份证号!");
card.setAddress("桃花源北区8栋2单元"+i+"楼");
user.setCard(card);
// 订单
List<Order> orders = new ArrayList<>();
orders.add(new Order("12"+i,"可莉"));
orders.add(new Order("12"+i,"刻晴"));
orders.add(new Order("12"+i,"神里"));
user.setOrders(orders);
if (i%2==0){
user.setStatus(1);
user.setHabbys(Arrays.asList("唱","跳","rap"));
}else {
user.setStatus(0);
user.setHabbys(Arrays.asList("dota","lol","wow"));
}
user.setMoney(i*50);
users.add(user);
}
return users;
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tya2kSGa-1631694702529)(笔记图片/
)]
例7-大数据量导出
大数据导出是当我们的导出数量在几万,到上百万的数据时,一次从数据库查询这么多数据加载到内存然后写入会对我们的内存和CPU都产生压力,这个时候需要我们像分页一样处理导出分段写入Excel缓解Excel的压力 EasyPoi提供的是两个方法 **强制使用 xssf版本的Excel **
最好大量数据进行分页处理,每次导出数据最好不要超过1w条记录。
业务类
@Test
public void testBigExport() throws IOException {
// 获取数据
List<User> users = getUsers();
// 导出excel
// 参数1:exportParams 导出配置对象 参数2:导出的类型 参数3:导出数据集合
Workbook workbook = ExcelExportUtil.exportBigExcel(new ExportParams("用户列表","测试"), User.class,users);
// 将excel写入指定位置
FileOutputStream outputStream = new FileOutputStream("E:\\新建文件夹\\big.xlsx");
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
例8-导入
实体类
属性上的注解name必须和表头一致
@Data
@ExcelTarget("emps")
public class Emp implements Serializable {
@Excel(name = "编号")
private String id;
@Excel(name = "姓名")
private String name;
@Excel(name = "年龄")
private Integer age;
@Excel(name = "生日",format = "yyyy-MM-dd HH:mm:ss")
private Date bir;
@Excel(name = "用户状态",replace = {"激活_1", "锁定_0"})
private String status;
}
业务类
@Test
public void testImport() throws Exception {
// 参数1:导入excel文件流 参数2:导入的类型 参数3:导入的配置对象
ImportParams params = new ImportParams();
// 设置标题占几列
params.setTitleRows(1);
// 设置header列占几行
params.setHeadRows(2);
List<Emp> emps = ExcelImportUtil.importExcel(new FileInputStream("E:\\新建文件夹\\test.xlsx"), Emp.class, params);
emps.forEach(System.out::println);
}