有天上飞的概念, 就要有落地的实现
概念十遍不如代码一遍, 朋友, 希望你把文中所有的代码案例都敲一遍
先赞后看, 养成习惯
SpringBoot 图文教程系列文章目录
SpringBoot 图文教程 1「概念 + 案例 思维导图」「基础篇上」 https://mp.weixin.qq.com/s/phk6j3ChBP-kPtS2xZeEZg
SpringBoot 图文教程 2 - 日志的使用「logback」「log4j」 https://mp.weixin.qq.com/s/7Mw_xhFF4Q5NtdtcsHc67Q
SpringBoot 图文教程 3-「'初恋'情结」集成 Jsp https://mp.weixin.qq.com/s/BYzVg5NBcF_ou_PyX8ygag
SpringBoot 图文教程 4-SpringBoot 实现文件上传下载 https://mp.weixin.qq.com/s/6ctykPo3eDBEB7YsC0PAZw
SpringBoot 图文教程 5-SpringBoot 中使用 Aop https://mp.weixin.qq.com/s/17qMRlv_mUfwkcVD05Bh2g
SpringBoot 图文教程 6-SpringBoot 中过滤器的使用 https://mp.weixin.qq.com/s/r2BO4UMNRAw_REA6nNFLKw
SpringBoot 图文教程 7-SpringBoot 拦截器的使用姿势这都有 https://mp.weixin.qq.com/s/YpDhuOTpt1vjYjnhnK8YdQ
SpringBoot 图文教程 8 - SpringBoot 集成 MBG「代码生成器」 https://mp.weixin.qq.com/s/uGYO4fkw03Kxpfp_PIA8rQ
SpringBoot 图文教程 9-SpringBoot 导入导出 Excel 「Apache Poi」 https://mp.weixin.qq.com/s/BXfxhO5rFFg6XZQ0rZgGMg
前言
上一篇文章中简单介绍了 Poi 的使用方式, 但是用 Poi 去写代码着实繁琐了一些, 假如你要实现的是复杂的需求, 譬如: 图片导出, 多表数据导出, 模板导出, 大数据量导出等等, 用最原生的 Poi 就不是很好的选择了.
难道要自己封装工具类了吗?
no no 轮子虽好, 最好是别人写好的. 所以从这篇文章开始介绍两个优秀的 Poi 工具 Easypoi 和 阿里开源的 EasyExcel.
EasyPoi
EasyPoi 是对 poi 封装的一个工具库, 封装好了一些常见的 Excel 操作
最基本的导入导出
图片的导入导出
多表数据的导入导出
大批量数据的导入导出
模板的导出
接下来我们一起来将以上的功能实现出来
官网地址: http://easypoi.mydoc.io/#category_50222
最基本的导入导出
最基本的导入导出, 要导出的数据的实体类如下:
- public class Teacher {
- /**
- * 老师的主键
- */
- private Integer teacherId;
- /**
- * 名字
- */
- private String teacherName;
- /**
- * 头像图片地址
- */
- private String teacherImage;
- /**
- * 老师的状态 0 代表正常 1 代表删除
- */
- private Integer teacherStatus;
- }
省略 get set
1. 导入依赖
- <dependency>
- <groupId>cn.afterturn</groupId>
- <artifactId>easypoi-base</artifactId>
- <version>3.2.0</version>
- </dependency>
- <dependency>
- <groupId>cn.afterturn</groupId>
- <artifactId>easypoi-web</artifactId>
- <version>3.2.0</version>
- </dependency>
- <dependency>
- <groupId>cn.afterturn</groupId>
- <artifactId>easypoi-annotation</artifactId>
- <version>3.2.0</version>
- </dependency>
2. 给要导出数据实体类加注解
我们要导出的数据的实体类是 Teacher 所以需要给 Teacher 加 Easypoi 的注解
EasyPoi 是注解式开发, 所有的注解详情见官方文档, 但是如果要完成的需求是最简单的导入导出的话,@Excel 一个注解就足够了.
@Excel
这个是必须使用的注解, 如果需求简单只使用这一个注解也是可以的, 涵盖了常用的 Excel 需求, 需要大家熟悉这个功能, 主要分为基础, 图片处理, 时间处理, 合并处理几块
@Excel 的官方 API http://easypoi.mydoc.io/#text_186900
添加好注解的实体类如下:
3. 直接使用 EasyPoi 中的工具类导入导出
EasyPoi 是注解式开发, 对 Excel 所有的定义, 样式也好, 日期格式化也好, 都是在实体类的注解中定义
导出代码
- /**
- * easypoi 导出
- */
- @Test
- public void test4() throws IOException {
- // 模拟数据
- List<Teacher> list = new ArrayList<>();
- list.add(new Teacher(1,"李老师","hhh.jpg",1));
- list.add(new Teacher(2,"李老师","hhh.jpg",1));
- list.add(new Teacher(3,"李老师","hhh.jpg",1));
- list.add(new Teacher(4,"李老师","hhh.jpg",1));
- list.add(new Teacher(5,"李老师","hhh.jpg",1));
- list.add(new Teacher(6,"李老师","hhh.jpg",1));
- /**
- * 导出参数对象
- * 参数 1 标题
- * 参数 2 表的名字
- */
- ExportParams exportParams = new ExportParams("所有老师数据","teacher");
- /**
- * exportExcel 导出 Excel 文件
- * 参数 1 导出参数对象
- * 参数 2 要导出的实体类的类对象
- * 参数 3 要导出的数据 需要一个集合 数据库查询出来的老师对象的集合
- *
- * 返回值就是封装好的文件对象
- */
- Workbook workbook = ExcelExportUtil.exportExcel(exportParams, Teacher.class, list);
- workbook.write(new FileOutputStream("/Users/lubingyang/Desktop/teachers.xls"));
- }
导出之后的 Excel 如下:
导入代码
关于导入 没有需要单独定义的配置 只要能够导出就能够直接写导入的代码
- /**
- * easypoi 导入
- */
- @Test
- public void test5() throws Exception {
- FileInputStream inputStream = new FileInputStream("/Users/lubingyang/Desktop/teachers.xls");
- /**
- * ImportParams 导入参数对象
- * 定义标题栏和表头数据
- */
- ImportParams importParams = new ImportParams();
- importParams.setTitleRows(1);
- importParams.setHeadRows(1);
- /**
- * importExcel 导入方法
- * 参数 1 流 读取要导入的文件
- * 参数 2 要导入的实体类的类对象 上师对象的类对象
- * 参数 3 导入参数对象
- *
- * 返回值 导入数据 直接封装为集合对象
- */
- List<Teacher> teachers = ExcelImportUtil.importExcel(inputStream, Teacher.class, importParams);
- for (Teacher teacher : teachers) {
- System.out.println(teacher);
- }
- }
值的替换 图片导入导出
值的替换
通过官方文档很容易找到如下内容
根据文档修改实体类
执行导出代码 可以得到如下效果
图片导出
修改实体类
修改完之后可以直接导出
根据测试, 如果图片地址字段存储的是相对路径, 最好处理为网络绝对绝对路径或者本地绝对路径
图片导入
在实体类的注解上需要设置图片导入之后的保存路径
API
集合数据导入导出
在增加一个实体类 Student , 在 Teacher 类中有一个学生集合, 导出 Teacher 的同时需要将 Student 的数据也导出, 对应的数据库操作一般都是连表查询, 那么这样的数据怎么导出到 Excel 呢?
实体类加注解
针对 Teacher 类集合属性的导入导出, 需要给该属性加注解 @ExcelConllection
官方文档地址: http://easypoi.mydoc.io/#text_197841
导出代码如下
- @Test
- public void test4() throws IOException {
- List<Student> students = new ArrayList<>();
- students.add(new Student("hh","男"));
- students.add(new Student("hh","男"));
- // 模拟数据
- List<Teacher> list = new ArrayList<>();
- list.add(new Teacher(1,"李老师","/Users/lubingyang/Desktop/hhh.jpg",1,students));
- list.add(new Teacher(6,"李老师","/Users/lubingyang/Desktop/hhh.jpg",1,students));
- /**
- * 导出参数对象
- * 参数 1 标题
- * 参数 2 表的名字
- */
- ExportParams exportParams = new ExportParams("所有老师数据","teacher");
- /**
- * exportExcel 导出 Excel 文件
- * 参数 1 导出参数对象
- * 参数 2 要导出的实体类的类对象
- * 参数 3 要导出的数据 需要一个集合 数据库查询出来的老师对象的集合
- *
- * 返回值就是封装好的文件对象
- */
- Workbook workbook = ExcelExportUtil.exportExcel(exportParams, Teacher.class, list);
- workbook.write(new FileOutputStream("/Users/lubingyang/Desktop/teachers.xls"));
- }
效果如下
大批量数据导出(百万数据)
关于百万数据导出 推荐使用 阿里开源的 EasyExcel 官方介绍可以将内存控制在 kb
大数据导出是当我们的导出数量在几万, 到上百万的数据时, 一次从数据库查询这么多数据加载到内存, 然后写入会对我们的内存和 CPU 都产生压力, 这个时候需要我们像分页一样处理导出, 分段写入 Excel 缓解压力
EasyPoi 提供的是两个方法 强制使用 xssf 版本的 Excel
- /**
- * @param entity
- * 表格标题属性
- * @param pojoClass
- * Excel 对象 Class
- * @param dataSet
- * Excel 对象数据 List
- */
- public static Workbook exportBigExcel(ExportParams entity, Class<?> pojoClass,
- Collection<?> dataSet) {
- ExcelBatchExportServer batachServer = ExcelBatchExportServer
- .getExcelBatchExportServer(entity, pojoClass);
- return batachServer.appendData(dataSet);
- }
- public static void closeExportBigExcel() {
- ExcelBatchExportServer batachServer = ExcelBatchExportServer.getExcelBatchExportServer(null,
- null);
- batachServer.closeExportBigExcel();
- }
思路
分页读取数据
将每次读取到的数据写入 Excel
实现代码
准备一个百万数据的用户表
- @Test
- public void test10() throws IOException {
- Date start = new Date();
- // 查询数据库 用户表总条数
- Integer userCount = userDao.selectCount(null);
- // 计算总页数
- Integer pageCount = userCount / 200000 + 1;
- List<CmfzUser> users = null;
- Workbook workbook = null;
- ExportParams params = new ExportParams("大数据测试", "测试");
- // 查询测试 页数 每次查询 20w 条数据
- for (int i = 1; i <= pageCount; i++) {
- System.out.println(i);
- users = userDao.selectPage(new Page<>(i, 200000), null).getRecords();
- // 通过 EasyPoi 的大数据导出方法 导出
- workbook = ExcelExportUtil.exportBigExcel(params, CmfzUser.class, users);
- users.clear();
- }
- Date end = new Date();
- System.out.println(new Date().getTime() - start.getTime());
- workbook.write(new FileOutputStream("/Users/lubingyang/Desktop/hhhh.xlsx"));
- }
执行的总时间为:
Tips:
时间问题没做详细的性能测试 官方有相关的测试: http://easypoi.mydoc.io/#text_202983
- @Test
- public void fe_map() throws Exception {
- // 读取模板文件
- TemplateExportParams params = new TemplateExportParams(
- "/Users/k/Desktop / 专项支出用款申请书_map.xls");
- // 模拟要写入模板的数据
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("date", "2014-12-25");
- map.put("money", 2000000.00);
- map.put("upperMoney", "贰佰万");
- map.put("company", "执笔潜行科技有限公司");
- map.put("bureau", "财政局");
- map.put("person", "JueYue");
- map.put("phone", "1879740****");
- List<Map<String, String>> listMap = new ArrayList<Map<String, String>>();
- for (int i = 0; i <4; i++) {
- Map<String, String> lm = new HashMap<String, String>();
- lm.put("id", i + 1 + "");
- lm.put("zijin", i * 10000 + "");
- lm.put("bianma", "A001");
- lm.put("mingcheng", "设计");
- lm.put("xiangmumingcheng", "EasyPoi" + i + "期");
- lm.put("quancheng", "开源项目");
- lm.put("sqje", i * 10000 + "");
- lm.put("hdje", i * 10000 + "");
- listMap.add(lm);
- }
- map.put("maplist", listMap);
- // 导出模板
- Workbook workbook = ExcelExportUtil.exportExcel(params, map);
- FileOutputStream fos = new FileOutputStream("/Users/k/Desktop / 专项支出用款申请书 111_map.xls");
- workbook.write(fos);
- fos.close();
- }
来源: https://www.cnblogs.com/bingyang-py/p/12419663.html