Easyexcel(4-模板文件)
相关文章链接
- Easyexcel(1-注解使用)
- Easyexcel(2-文件读取)
- Easyexcel(3-文件导出)
- Easyexcel(4-模板文件)
文件导出
获取 resources 目录下的文件,使用 withTemplate 获取文件流导出文件模板
@GetMapping("/download1")
public void download1(HttpServletResponse response) {try (InputStream in = new ClassPathResource("测试.xls").getInputStream()) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");EasyExcel.write(response.getOutputStream()).withTemplate(in).sheet("sheet1").doWrite(Collections.emptyList());} catch (Exception e) {e.printStackTrace();}
}
注意:获取 resources 目录下的文件需要在 maven 中添加以下配置,过滤对应的文件,防止编译生成后的 class 文件找不到对应的文件信息
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><configuration><encoding>UTF-8</encoding><nonFilteredFileExtensions><nonFilteredFileExtension>xls</nonFilteredFileExtension><nonFilteredFileExtension>xlsx</nonFilteredFileExtension></nonFilteredFileExtensions></configuration>
</plugin>
对象填充导出
模板文件信息
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {@ExcelProperty(value = "用户Id")private Integer userId;@ExcelProperty(value = "姓名")private String name;@ExcelProperty(value = "手机")private String phone;@ExcelProperty(value = "邮箱")private String email;@ExcelProperty(value = "创建时间")private Date createTime;
}
@GetMapping("/download5")
public void download5(HttpServletResponse response) {try (InputStream in = new ClassPathResource("测试3.xls").getInputStream()) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试3", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");User user = new User(1, "张三", "12345678901", "zhangsan@qq.com", new Date());EasyExcel.write(response.getOutputStream(), User.class).withTemplate(in).sheet("模板").doFill(user);} catch (Exception e) {e.printStackTrace();}
}
注意:填充模板跟写文件使用的方法不一致,模板填充使用的方法是 doFill,而不是 doWrite
导出文件内容
List 填充导出
对象导出
模板文件信息
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {@ExcelProperty(value = "用户Id")private Integer userId;@ExcelProperty(value = "姓名")private String name;@ExcelProperty(value = "手机")private String phone;@ExcelProperty(value = "邮箱")private String email;@ExcelProperty(value = "创建时间")private Date createTime;
}
@GetMapping("/download2")
public void download2(HttpServletResponse response) {try (InputStream in = new ClassPathResource("测试.xls").getInputStream()) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");List<User> userList = new ArrayList<>();userList.add(new User(1, "张三", "12345678901", "zhangsan@qq.com", new Date()));userList.add(new User(2, "李四", "12345678902", "lisi@qq.com", new Date()));EasyExcel.write(response.getOutputStream(), User.class).withTemplate(in).sheet("模板").doFill(userList);} catch (Exception e) {e.printStackTrace();}
}
导出文件内容
对象嵌套对象(默认不支持)
原因排查
模板文件信息
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {@ExcelProperty(value = "用户Id")private Integer userId;@ExcelProperty(value = "姓名")private String name;@ExcelProperty(value = "手机")private String phone;@ExcelProperty(value = "邮箱")private String email;@ExcelProperty(value = "学生")private Student stu;@NoArgsConstructor@AllArgsConstructor@Datapublic static class Student {@ExcelProperty("姓名")private String name;@ExcelProperty("年龄")private Integer age;}
}
@GetMapping("/download3")
public void download3(HttpServletResponse response) {try (InputStream in = new ClassPathResource("测试2.xls").getInputStream()) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试2", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");List<User> userList = new ArrayList<>();userList.add(new User(1, "张三", "12345678901", "zhangsan@qq.com", new User.Student("张三", 12)));userList.add(new User(2, "李四", "12345678902", "lisi@qq.com", new User.Student("李四", 13)));EasyExcel.write(response.getOutputStream(), User.class).withTemplate(in).sheet("模板").doFill(userList);} catch (Exception e) {e.printStackTrace();}
}
导出文件内容
结果:Student 类的内容没有填充到模板文件中
查看 ExcelWriteFillExecutor 源码
可以看到 dataKeySet 集合中的数据只有 stu(没有 stu.name 和 stu.age),在! dataKeySet.contains(variable)方法中判断没有包含该字段信息,所以被过滤掉
修改源码支持
在 com.alibaba.excel.write.executor 包下创建 ExcelWriteFillExecutor 类,跟源码中的类名称一致,尝试修改 analysisCell.getOnlyOneVariable()方法中的逻辑以便支持嵌套对象,修改如下:
根据分隔符.进行划分,循环获取对象中字段的数据,同时在 FieldUtils.getFieldClass 方法中重新设置 map 对象和字段
if (analysisCell.getOnlyOneVariable()) {String variable = analysisCell.getVariableList().get(0);String[] split = variable.split("\\.");Map map = BeanUtil.copyProperties(dataMap, Map.class);Object value = null;if (split.length == 1) {value = map.get(variable);} else {int len = split.length - 1;for (int i = 0; i < len; i++) {Object o = map.get(split[i]);map = BeanMapUtils.create(o);}value = map.get(split[split.length - 1]);}ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(map,writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadClazz(), split[split.length - 1],writeContext.currentWriteHolder());cellWriteHandlerContext.setExcelContentProperty(excelContentProperty);createCell(analysisCell, fillConfig, cellWriteHandlerContext, rowWriteHandlerContext);cellWriteHandlerContext.setOriginalValue(value);cellWriteHandlerContext.setOriginalFieldClass(FieldUtils.getFieldClass(map, split[split.length - 1], value));converterAndSet(cellWriteHandlerContext);WriteCellData<?> cellData = cellWriteHandlerContext.getFirstCellData();// Restyleif (fillConfig.getAutoStyle()) {Optional.ofNullable(collectionFieldStyleCache.get(currentUniqueDataFlag)).map(collectionFieldStyleMap -> collectionFieldStyleMap.get(analysisCell)).ifPresent(cellData::setOriginCellStyle);}
}
导出文件内容
查看导出的文件内容,此时发现嵌套对象的内容可以导出了
对象嵌套 List(默认不支持)
原因排查
模板文件信息
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {@ExcelProperty(value = "用户Id")private Integer userId;@ExcelProperty(value = "姓名")private String name;@ExcelProperty(value = "手机")private String phone;@ExcelProperty(value = "邮箱")private String email;@ExcelProperty(value = "创建时间")private Date createTime;@ExcelProperty(value = "id列表")private List<String> idList;
}
@GetMapping("/download4")
public void download4(HttpServletResponse response) {try (InputStream in = new ClassPathResource("测试2.xls").getInputStream()) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");List<User> userList = new ArrayList<>();userList.add(new User(1, "张三", "12345678901", "zhangsan@qq.com", new Date(), Arrays.asList("234", "465")));userList.add(new User(2, "李四", "12345678902", "lisi@qq.com", new Date(), Arrays.asList("867", "465")));EasyExcel.write(response.getOutputStream(), User.class).withTemplate(in).sheet("模板").doFill(userList);} catch (Exception e) {e.printStackTrace();}
}
执行后会发现报错 Can not find ‘Converter’ support class ArrayList.
EasyExcel 默认不支持对象嵌套 List 的,可以通过自定义转换器的方式修改导出的内容
自定义转换器
public class ListConvert implements Converter<List> {@Overridepublic WriteCellData<?> convertToExcelData(List value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {if (value == null || value.isEmpty()) {return new WriteCellData<>("");}String val = (String) value.stream().collect(Collectors.joining(","));return new WriteCellData<>(val);}@Overridepublic List convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {if (cellData.getStringValue() == null || cellData.getStringValue().isEmpty()) {return new ArrayList<>();}List list = new ArrayList();String[] items = cellData.getStringValue().split(",");Collections.addAll(list, items);return list;}
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {@ExcelProperty(value = "用户Id")private Integer userId;@ExcelProperty(value = "姓名")private String name;@ExcelProperty(value = "手机")private String phone;@ExcelProperty(value = "邮箱")private String email;@ExcelProperty(value = "创建时间")private Date createTime;@ExcelProperty(value = "id列表", converter = ListConvert.class)private List<String> idList;
}
导出文件内容
可以看到 List 列表的数据导出内容为 String 字符串,显示在一个单元格内
Map 填充导出
简单导出
模板文件信息
注意:map跟对象导出有所区别,最前面没有.
@GetMapping("/download4")
public void download4(HttpServletResponse response) {try (InputStream in = new ClassPathResource("测试3.xls").getInputStream()) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");Map<String, String> map = new HashMap<>();map.put("userId", "123");map.put("name", "张三");map.put("phone", "12345678901");map.put("email", "zhangsan@qq.com");map.put("createTime", "2021-01-01");EasyExcel.write(response.getOutputStream(), User.class).withTemplate(in).sheet("模板").doFill(map);} catch (Exception e) {e.printStackTrace();}
}
导出文件内容
嵌套方式(不支持)
模板文件信息
@GetMapping("/download4")
public void download4(HttpServletResponse response) {try (InputStream in = new ClassPathResource("测试3.xls").getInputStream()) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");Map<String, String> map = new HashMap<>();map.put("userId", "123");map.put("name", "张三");map.put("phone", "12345678901");map.put("email", "zhangsan@qq.com");map.put("createTime", "2021-01-01");map.put("student.name", "小张");map.put("student.age", "23");EasyExcel.write(response.getOutputStream(), User.class).withTemplate(in).sheet("模板").doFill(map);} catch (Exception e) {e.printStackTrace();}
}
导出文件内容
注意:Easyexcel 不支持嵌套的方式导出数据
相关文章:

Easyexcel(4-模板文件)
相关文章链接 Easyexcel(1-注解使用)Easyexcel(2-文件读取)Easyexcel(3-文件导出)Easyexcel(4-模板文件) 文件导出 获取 resources 目录下的文件,使用 withTemplate 获…...

国产linux系统(银河麒麟,统信uos)使用 PageOffice 动态生成word文件
PageOffice 国产版 :支持信创系统,支持银河麒麟V10和统信UOS,支持X86(intel、兆芯、海光等)、ARM(飞腾、鲲鹏、麒麟等)、龙芯(LoogArch)芯片架构。 数据区域填充文本 数…...

Window11+annie 视频下载器安装
一、ffmpeg环境的配置 下载annie之前需要先配置ffmpeg视频解码器。 网址下载地址 https://ffmpeg.org/download.html1、在网址中选择window版本 2、点击后选择该版本 3、下载完成后对压缩包进行解压,后进行环境的配置 (1)压缩包解压&#…...
SAP GR(Group Reporting)配置篇(七)
1.7、合并处理的配置 1.7.1 定义方法 菜单路径 组报表的SAP S4HANA >合并处理的配置>定义方法 事务代码 SPI4...

共建智能软件开发联合实验室,怿星科技助力东风柳汽加速智能化技术创新
11月14日,以“奋进70载,智创新纪元”为主题的2024东风柳汽第二届科技周在柳州盛大开幕,吸引了来自全国的汽车行业嘉宾、技术专家齐聚一堂,共襄盛举,一同探寻如何凭借 “新技术、新实力” 这一关键契机,为新…...

优化表单交互:在 el-select 组件中嵌入表格显示选项
介绍了一种通过 el-select 插槽实现表格样式数据展示的方案,可更直观地辅助用户选择。支持列配置、行数据绑定及自定义搜索,简洁高效,适用于复杂选择场景。完整代码见GitHub 仓库。 背景 在进行业务开发选择订单时,如果单纯的根…...
每日一题 LCR 079. 子集
LCR 079. 子集 主要应该考虑遍历的顺序 class Solution { public:vector<vector<int>> subsets(vector<int>& nums) {vector<vector<int>> ans;vector<int> temp;dfs(nums,0,temp,ans);return ans;}void dfs(vector<int> &…...
cocos creator 3.8 Node学习 3
//在Ts、js中 this指向当前的这个组件实例 //this下的一个数据成员node,指向组件实例化的这个节点 //同样也可以根据节点找到挂载的所有组件 //this.node 指向当前脚本挂载的节点//子节点与父节点的关系 // Node.parent是一个Node,Node.children是一个Node[] // th…...

微信小程序底部button,小米手机偶现布局错误的bug
预期结果:某button fixed 到页面底部,进入该页面时,正常显示button 实际结果:小米13pro,首次进入页面,button不显示。再次进入时,则正常展示 左侧为小米手机第一次进入。 遇到bug的解决思路&am…...
【计组】复习题
冯诺依曼型计算机的主要设计思想是什么?它包括哪些主要组成部分? 主要设计思想: ①采用二进制表示数据和指令,指令由操作码和地址码组成。 ②存储程序,程序控制:将程序和数据存放在存储器中,计算…...
Apache Maven 标准文件目录布局
Apache Maven 采用了一套标准的目录布局来组织项目文件。这种布局提供了一种结构化和一致的方式来管理项目资源,使得开发者更容易导航和维护项目。理解和使用标准目录布局对于有效的Maven项目管理至关重要。本文将探讨Maven标准目录布局的关键组成部分,并…...

Android 功耗分析(底层篇)
最近在网上发现关于功耗分析系列的文章很少,介绍详细的更少,于是便想记录总结一下功耗分析的相关知识,有不对的地方希望大家多指出,互相学习。本系列分为底层篇和上层篇。 大概从基础知识,测试手法,以及案例…...

【Xbim+C#】创建圆盘扫掠IfcSweptDiskSolid
基础回顾 https://blog.csdn.net/liqian_ken/article/details/143867404 https://blog.csdn.net/liqian_ken/article/details/114851319 效果图 代码示例 在前文基础上,增加一个工具方法: public static IfcProductDefinitionShape CreateDiskSolidSha…...

IntelliJ+SpringBoot项目实战(四)--快速上手数据库开发
对于新手学习SpringBoot开发,可能最急迫的事情就是尽快掌握数据库的开发。目前数据库开发主要流行使用Mybatis和Mybatis Plus,不过这2个框架对于新手而言需要一定的时间掌握,如果快速上手数据库开发,可以先按照本文介绍的方式使用JdbcTemplat…...
利用oss进行数据库和网站图片备份
1.背景 由于网站迁移到香港云 服务器,虽然便宜,但是宿主服务器时不时重启,为了预防不可控的因素导致网站资料丢失,所以想到用OSS 备份网站数据,bucket选择在香港地区创建,这样和你服务器传输会更快。 oss…...

Excel - VLOOKUP函数将指定列替换为字典值
背景:在根据各种复杂的口径导出报表数据时,因为关联的表较多、数据量较大,一行数据往往会存在三个以上的字典数据。 为了保证导出数据的效率,博主选择了导出字典code值后,在Excel中处理匹配字典值。在查询百度之后&am…...

实验室管理平台:Spring Boot技术构建
3系统分析 3.1可行性分析 通过对本实验室管理系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本实验室管理系统采用SSM框架,JAVA作为开发语言&a…...

操作系统进程和线程——针对实习面试
目录 操作系统进程和线程什么是进程和线程?进程和线程的区别?进程有哪些状态?什么是线程安全?如何实现线程安全?什么是线程安全?如何实现线程安全? 进程间的通信有哪几种方式?什么是…...
使用 cnpm 安装 Electron,才是正确快速的方法
当然,下面是总结的几种安装 Electron 的方法,包括使用 npm 和 cnpm,以及一些常见的问题解决技巧。 ### 1. 使用 npm 安装 Electron #### 步骤 1: 初始化项目 在你的项目目录中初始化一个新的 Node.js 项目: bash npm init -y …...

【人工智能】PyTorch、TensorFlow 和 Keras 全面解析与对比:深度学习框架的终极指南
文章目录 PyTorch 全面解析2.1 PyTorch 的发展历程2.2 PyTorch 的核心特点2.3 PyTorch 的应用场景 TensorFlow 全面解析3.1 TensorFlow 的发展历程3.2 TensorFlow 的核心特点3.3 TensorFlow 的应用场景 Keras 全面解析4.1 Keras 的发展历程4.2 Keras 的核心特点4.3 Keras 的应用…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...
boost::filesystem::path文件路径使用详解和示例
boost::filesystem::path 是 Boost 库中用于跨平台操作文件路径的类,封装了路径的拼接、分割、提取、判断等常用功能。下面是对它的使用详解,包括常用接口与完整示例。 1. 引入头文件与命名空间 #include <boost/filesystem.hpp> namespace fs b…...
FTXUI::Dom 模块
DOM 模块定义了分层的 FTXUI::Element 树,可用于构建复杂的终端界面,支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...