5.3.EasyPOI导出
5.3.1.前言
easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板语言(熟悉的表达式语法),完成以前复杂的写法
5.3.2.EasyPoi的主要特点
1.设计精巧,使用简单2.接口丰富,扩展简单3.默认值多,write less do more4.spring mvc支持,web导出可以简单明了
5.3.3.功能
Excel自适应xls和xlsx两种格式,word只支持docx模式
1.Excel导入
注解导入
Map导入
大数据量导入sax模式
导入文件保存
文件校验
字段校验
2.Excel导出
注解导出
模板导出
html导出
3.Excel转html
4.word导出
5.pdf导出
5.3.4.Easypoi介绍
Easypoi 为谁而开发
不太熟悉poi的
不想写太多重复太多的
只是简单的导入导出的
喜欢使用模板的
都可以使用easypoi
Easypoi的目标是什么,Easypoi的目标不是替代poi,而是让一个不懂导入导出的快速使用poi完成Excel和word的各种操作,而不是看很多api才可以完成这样工作
为什么会写Easypoi
以前的以前(岁月真TMD的快)我虽然写了不少代码但还是很少写poi,然后跳到一家公司之后就和业务人员聊上了,来这个需要个报表,这个报表样式是这样的,这个表头是这样的,就这样我写了大量的poi代码,每次都是大量的篇幅,copy to copy,无聊的一逼,然后加入了jeecg,jeecg中有一个小的工具类,虽然我也不知道是谁写的,然是可以用注解搞定最简单的导出,突然豁然开朗,我可以完善,让我从报表的苦海当中脱离出来,这样我花了一周的时间做了第一个版本支持导入导出放到了jeecg,发现还是不错的,慢慢的用的人越来越多,我就把这块独立出来了,再然后有人提出了模板,然后就加入了模板功能,提出了word的需求,加入了word的功能,后来工作忙了虽然没再参与jeecg,但还是一直维持这easypoi的更新,根据见识的增长也不断的重构这代码,直到现在
独特的功能
基于注解的导入导出,修改注解就可以修改Excel
支持常用的样式自定义
基于map可以灵活定义的表头字段
支持一对多的导出,导入
支持模板的导出,一些常见的标签,自定义标签
支持HTML/Excel转换,如果模板还不能满足用户的变态需求,请用这个功能
支持word的导出,支持图片,Excel
5.3.5.依赖jar包
-
1.easypoi-annotation 基础注解包,作用与实体对象上,拆分后方便maven多工程的依赖管理
-
2.easypoi-base 导入导出的工具包,可以完成Excel导出,导入,Word的导出,Excel的导出功能
-
3.easypoi-web 耦合了spring-mvc 基于AbstractView,极大的简化spring-mvc下的导出功能
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.0.0</version>
</dependency>
5.3.6.Excel 注解版
Excel的导入导出是Easypoi的核心功能,前期基本也是围绕这个打造的,主要分为三种方式的处理,其中模板和Html目前只支持导出,因为支持Map.class其实导入应该是怎样都支持的
easypoi起因就是Excel的导入导出,最初的模板是实体和Excel的对应,model--row,filed--col 这样利用注解我们可以和容易做到excel到导入导出经过一段时间发展,现在注解有5个类分别是
@Excel 作用到filed上面,是对Excel一列的一个描述
@ExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,科目就可以用集合表示
@ExcelEntity 表示一个继续深入导出的实体,但他没有太多的实际意义,只是告诉系统这个对象里面同样有导出的字段
@ExcelIgnore 和名字一样表示这个字段被忽略跳过这个导出
@ExcelTarget 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做出不同处理
@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 | 导出隐藏列 |
@ExcelTarget
限定一个到处实体的注解,以及一些通用设置,作用于最外面的实体
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
value | String | null | 定义ID |
height | double | 10 | 设置行高 |
fontSize | short | 11 | 设置文字大小 |
@ExcelEntity
标记是不是导出excel 标记为实体类,以遍是一个内部属性类,标记是否继续穿透,可以自定义内部id
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
id | String | null | 定义ID |
@ExcelCollection
一对多的集合注解,用以标记集合是否被数据以及集合的整体排序
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
id | String | null | 定义ID |
name | String | null | 定义集合列名,支持nanm_id |
orderNum | int | 0 | 排序,支持name_id |
type | Class<?> | ArrayList.class | 导入时创建对象使用 |
5.3.7. 对象定义
首先定义一个我们导出的对象,为了节省篇幅,统一忽略getter,setter
public class User {
@Excel(name="ID", height = 20, width = 30)
private String id;
@Excel(name="名字")
private String name;
@Excel(name="年龄")
private Integer age;
@Excel(name="生日",format = "yyyy年MM月dd日",width = 20)
private Date bir;
}
5.3.8.生成Excel代码如下:
public class TestEasyPoi {
@Test
public void testExport() throws Exception{
List<User> users = new ArrayList<User>();
users.add(new User("1", "小黄", 23, new Date()));
users.add(new User("2", "小刘", 26, new Date()));
users.add(new User("3", "小黑", 24, new Date()));
users.add(new User("4", "小张", 18, new Date()));
//参数:标题,表名,实体类类对象,导出的集合
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("计算机一班学生","学生"),User.class, users);
workbook.write(new FileOutputStream(new File("E:/easypoi.xls")));
workbook.close();
}
}
5.3.9.一对多关系导出
学生实体(多)
@ExcelTarget(value = "student")
public class Student {
@Excel(name="ID")
private String id;
@Excel(name="学生姓名")
private String name;
@Excel(name="学生年龄")
private Integer age;
}
老师实体(一)
@ExcelTarget(value = "teacher")
public class Teacher {
@ExcelIgnore
private String id;
@Excel(name="老师姓名")
private String name;
@ExcelCollection(name="计算机学生")
private List<Student> students;
}
5.3.10.生成Excel代码如下:
@Test
public void TestEasyPois() throws Exception{
//创建学生集合
List<Student> stus = new ArrayList<Student>();
stus.add(new Student("1", "小黄", 23));
stus.add(new Student("2", "小刘", 26));
stus.add(new Student("3", "小黑", 24));
stus.add(new Student("4", "小张", 18));
Teacher teacher = new Teacher("1","张超男",stus);
//创建老师集合
List<Teacher> teachers = new ArrayList<Teacher>();
teachers.add(teacher);
//参数:(一级标题,二级标题,表名),实体类类对象,导出的集合
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("计算机一班学生","计算机","学生"),Teacher.class, teachers);
workbook.write(new FileOutputStream(new File("E:/easypoi.xls")));
//释放资源
workbook.close();
}
这样我们就完成了需求,效果如图
但是名字没有合并,不太美观
给老师名字加了needMerge = true的属性,就可以完成单元格的合并
@Excel(name="老师姓名",needMerge = true)
private String name;
如图:
还可以多添加几位老师,
Teacher teacher = new Teacher("1","张超男",stus);
Teacher teacher1 = new Teacher("2","张坤",stus);
//创建老师集合
List<Teacher> teachers = new ArrayList<Teacher>();
teachers.add(teacher);
teachers.add(teacher1);
效果如图:
5.3.11.图片的导出:
@Excel(name="头像",type = 2 ,width = 40 , height = 20,imageType = 1)
private String headPic;
表示type =2 该字段类型为图片,imageType=1 (默认可以不填),表示从file读取,字段类型是个字符串类型 可以用相对路径也可以用绝对路径,绝对路径优先依次获取
//创建学生集合
List<Student> stus = new ArrayList<Student>();
stus.add(new Student("1", "小黄", 23,"C:/Users/Administrator/Desktop/cmfzcode/cmfz_zhangcn/WebRoot/img/captcha.jpg"));
stus.add(new Student("2", "小刘", 26,"WebRoot/img/captcha.jpg"));
stus.add(new Student("3", "小黑", 24,"WebRoot/img/captcha.jpg"));
stus.add(new Student("4", "小张", 18,"WebRoot/img/captcha.jpg"));
5.4.EasyPoi导入
public class TestEasyPoiInput {
public static void main(String[] args) throws Exception {
//创建导入对象
ImportParams params = new ImportParams();
params.setTitleRows(1); //表格标题行数,默认0
params.setHeadRows(2); //表头行数,默认1
//获取导入数据
List<Teacher> teachers = ExcelImportUtil.importExcel(new FileInputStream(new File("D:/TestEasyPoi.xls")),Teacher.class, params);
for (Teacher teacher : teachers) {
System.out.println(teacher);
}
}
}
5.5.EasyPoi图片导入
@Test
public void testEasyPoiPhotos() {
ImportParams params = new ImportParams();
params.setTitleRows(1);
params.setHeadRows(1);
try {
//导入 参数:对应实体,导入参数
List<Photo> photos = ExcelImportUtil.importExcel(new FileInputStream(new File("D://easypoiPhoto.xls")),Photo.class, params);
for (Photo photo : photos) {
System.out.println(photo);
}
} catch (Exception e) {
e.printStackTrace();
}
}
上传路径:设置保存路径saveUrl 默认为"upload/excelUpload"可以手动修改 ImportParams 修改下就可以 final修饰不能修改