当前位置: 首页 > news >正文

Java导出写入固定Excel模板数据

目录

介绍

引入easyExcel

sheet页属性单值写入

sheet页列表数据写入

数据占位写入

非占位写入


介绍

  有时数据导入导出时,有些excel是固定好的标题数据,也就是固定的excel模板数据,此时让我们进行数据的写出,按照固定配置的标题数据进行导出excel

比如下面的样式,治理信息页面的

可以看到治理信息sheet页是固定好的表头模板,其他sheet页是集合列表形式,也是固定好表头的;此时可以使用阿里的easyExcel来简单实现excel固定模板数据的导出

引入easyExcel

引入maven依赖

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.3</version>
</dependency>

sheet页属性单值写入

数据库表和java实体类需要和excel表sheet数据进行建模对应,这里简单介绍下实体类的对应,数据库建表,service,mapper层不再介绍,博主使用的是mybatis-plus来和数据库进行查询交互

sheet页属性单值,可以看到博主这里列举的例子该sheet页的每个属性值都是单一数据,和java中的实体属性一一对应,此时使用数据写入时,excel的对应位置需要直接写入对应实体属性值进行占位,并且使用 {} 进行包裹,:

模板excel写好占位属性值后,将对应excel放入java工程目录的rescourse目录下

书写方法查询数据,然后进行数据写入

public void exportGovernanceReport(String orgId, HttpServletResponse response) {QyxxStandardGovernanceReportDto dto = queryExportGovernanceReport(orgId);if(dto == null){log.warn("导出数据或列不存在");return;}// 方法1: 使用 Spring 的 ClassPathResource 来定位文件ClassPathResource resource = new ClassPathResource("excelTemp/governanceReport.xlsx");try (// 1. 读取模板到内存ByteArrayOutputStream templateOut = new ByteArrayOutputStream();) {// 先加载模板EasyExcel.write(templateOut).withTemplate(resource.getInputStream()).build().finish();byte[] templateBytes = templateOut.toByteArray();try (// 2. 基于模板进行填充ByteArrayInputStream templateInput = new ByteArrayInputStream(templateBytes);ByteArrayOutputStream output = new ByteArrayOutputStream()) {ExcelWriterBuilder writerBuilder = EasyExcel.write(output).withTemplate(templateInput);// 构建 writer 和 sheetExcelWriter writer = writerBuilder.build();WriteSheet sheet = EasyExcel.writerSheet("治理信息").build();// ✅ EasyExcel 4.x 正确填充方式:直接传 dto 对象// 前提:Excel 模板中写的是 {orgFullName},而不是 {data.orgFullName}writer.fill(dto, sheet);writer.finish();// 3. 输出到 responsebyte[] finalBytes = output.toByteArray();response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("治理报告", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");response.setContentLength(finalBytes.length);try (ServletOutputStream servletOutputStream = response.getOutputStream()) {servletOutputStream.write(finalBytes);servletOutputStream.flush();}} catch (IOException e) {log.error("导出失败:写入响应流异常", e);throw new ApiException("导出失败:请联系管理员");}} catch (Exception e) {log.error("导出治理报告失败: {}", CommonUtil.analysisExceptionMessage(e), e);throw new ApiException("导出失败:请联系管理员");}}

注意这里的方法,这里是博主的一个查询方法,这里可以忽略,因为无论什么样的场景这里都是会有查询数据的地方,这里在用时可以灵活实现自己的逻辑,反正就是到这一步时,dto里就已经查询到数据了,查询到数据后,下面的步骤才进入到写入的逻辑

打个断点看下这里查询的数据

可以看到dto这里已经查询到数据了

后续进行写入

先拿取放在rescourse目录下的excle模板文件

使用apipost测试运行

可以看到都出的excel文件,指定占位的地方已被替换为对应数据的值

sheet页列表数据写入

前面介绍的是sheet页的单值属性写入,在有的数据里是以列表形式的数据绑定,一行就是一条数据,

比如下面的示例

此时的数据绑定有两种方法可以进行数据写入

数据占位写入

第一种写法还是按照{} 数据占位的写法,但是这里的占位写法需要调整下

还是dto实体里,要定义好列表sheet页的实体属性集合

高管信息的就不再展示,同理,excel里占位 需要加上 前缀进行占位 {xx.属性值}

下面上代码

QyxxStandardGovernanceReportDto dto = queryExportGovernanceReport(orgId);if(dto == null){log.warn("导出数据或列不存在");return;}// 方法1: 使用 Spring 的 ClassPathResource 来定位文件ClassPathResource resource = new ClassPathResource("excelTemp/governanceReport.xlsx");try (// 1. 读取模板到内存ByteArrayOutputStream templateOut = new ByteArrayOutputStream();) {// 先加载模板EasyExcel.write(templateOut).withTemplate(resource.getInputStream()).build().finish();byte[] templateBytes = templateOut.toByteArray();try (// 2. 基于模板进行填充ByteArrayInputStream templateInput = new ByteArrayInputStream(templateBytes);ByteArrayOutputStream output = new ByteArrayOutputStream()) {ExcelWriterBuilder writerBuilder = EasyExcel.write(output).withTemplate(templateInput);// 构建 writer 和 sheetExcelWriter writer = writerBuilder.build();WriteSheet sheet = EasyExcel.writerSheet("治理信息").build();// ✅ EasyExcel 4.x 正确填充方式:直接传 dto 对象// 前提:Excel 模板中写的是 {orgFullName},而不是 {data.orgFullName}writer.fill(dto, sheet);Map<String, List<?>> dataMap = new HashMap<>();dataMap.put("席位归属分布", dto.getBoardSeatDistributions());dataMap.put("董事信息", dto.getDirectorInfos());// 后续还有其他多个sheet页,还可以接着添加// ========== 循环填充每个 sheet ==========FillConfig verticalConfig = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).build();for (Map.Entry<String, List<?>> entry : dataMap.entrySet()) {String sheetName = entry.getKey();List<?> dataList = entry.getValue();if (CollectionUtils.isEmpty(dataList)) {log.warn("Sheet [{}] 数据为空,跳过填充", sheetName);continue;}WriteSheet sheetNameSheet = EasyExcel.writerSheet(sheetName).build();// 使用 FillWrapper,统一用 "data" 作为占位符前缀writer.fill(new FillWrapper("data", dataList), verticalConfig, sheetNameSheet);}// 3. 输出到 responsebyte[] finalBytes = output.toByteArray();response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("治理报告", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");response.setContentLength(finalBytes.length);try (ServletOutputStream servletOutputStream = response.getOutputStream()) {servletOutputStream.write(finalBytes);servletOutputStream.flush();}} catch (IOException e) {log.error("导出失败:写入响应流异常", e);throw new ApiException("导出失败:请联系管理员");}} catch (Exception e) {log.error("导出治理报告失败: {}", CommonUtil.analysisExceptionMessage(e), e);throw new ApiException("导出失败:请联系管理员");}}

这里由于是拿取对应名字的sheet页,所以将sheet页名字作为map的key,对应sheet页要传入的集合数据作为map的value,循环map进行写入excel数据

测试接口查看文件:

可以看到数据已经渲染上

非占位写入

excel模板里如果不想写入占位符进行占位绑定,需要在java对应实体类中使用

@ExcelProperty("对应excel列名")

代码调整:

public void exportGovernanceReport(String orgId, HttpServletResponse response) {QyxxStandardGovernanceReportDto dto = queryExportGovernanceReport(orgId);if(dto == null){log.warn("导出数据或列不存在");return;}// 方法1: 使用 Spring 的 ClassPathResource 来定位文件ClassPathResource resource = new ClassPathResource("excelTemp/governanceReports.xlsx");System.out.println(resource.getFilename());System.out.println(resource.exists());System.out.println(resource.getPath());try (// 1. 读取模板到内存ByteArrayOutputStream templateOut = new ByteArrayOutputStream();) {// 先加载模板EasyExcel.write(templateOut).withTemplate(resource.getInputStream()).build().finish();byte[] templateBytes = templateOut.toByteArray();try (// 2. 基于模板进行填充ByteArrayInputStream templateInput = new ByteArrayInputStream(templateBytes);ByteArrayOutputStream output = new ByteArrayOutputStream()) {ExcelWriterBuilder writerBuilder = EasyExcel.write(output).withTemplate(templateInput);// 构建 writer 和 sheetExcelWriter writer = writerBuilder.build();WriteSheet sheet = EasyExcel.writerSheet("治理信息").build();// ✅ EasyExcel 4.x 正确填充方式:直接传 dto 对象// 前提:Excel 模板中写的是 {orgFullName},而不是 {data.orgFullName}writer.fill(dto, sheet);//// ========== ✅ Sheet2: 席位归属分布(集合数据)==========if (CollectionUtils.isNotEmpty(dto.getBoardSeatDistributions())) {WriteSheet sheet2 = EasyExcel.writerSheet("席位归属分布").build();writer.write(dto.getBoardSeatDistributions(), sheet2);} else {System.out.println("【警告】boardSeatDistributions 为空");}// ========== ✅ Sheet2: 席位归属分布(集合数据)==========writer.finish();// 3. 输出到 responsebyte[] finalBytes = output.toByteArray();response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("治理报告", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");response.setContentLength(finalBytes.length);try (ServletOutputStream servletOutputStream = response.getOutputStream()) {servletOutputStream.write(finalBytes);servletOutputStream.flush();}} catch (IOException e) {log.error("导出失败:写入响应流异常", e);throw new ApiException("导出失败:请联系管理员");}} catch (Exception e) {log.error("导出治理报告失败: {}", CommonUtil.analysisExceptionMessage(e), e);throw new ApiException("导出失败:请联系管理员");}}

这里传入对应的实体数据集合

查看结果

可以看到数据正确渲染,但是有一个问题,就是渲染了多余的数据,实体字段里没有配置@ExcelProperty注解的字段数据也被渲染了,此时如果哪些字段不想被渲染需要加上@ExcelIgnore

即可

http://www.dtcms.com/a/515472.html

相关文章:

  • 合肥网站建设模板系统html怎么做商品页面
  • uniapp微信小程序页面跳转后定时器未清除问题解析与解决方案
  • 《从“直接对话”到 “集成开发调用”:智谱 GLM-4.6 引领 Coding 场景的效率跃迁》
  • 数据中心基础设施等级
  • 关于架空输电线识别树障or测距相关论文阅读
  • [go 面试] 深入理解并发控制:掌握锁的精髓
  • TypeScript 面试题及详细答案 100题 (61-70)-- 泛型(Generics)
  • 全球外贸网站制作教程icp网站快速备案
  • 《Hiding Images in Diffusion Models by Editing Learned Score Functions》 论文阅读
  • 频率分集阵列雷达——论文阅读
  • 网站备案信息如何下载潍坊市住房和城乡建设局网站下载
  • 比较好的企业网站百度举报网站
  • 数据库加密技术
  • nginx配置内嵌网页
  • 【微服务】SpringBoot 整合轻量级安全框架JWE 项目实战详解
  • 一个完整的AI项目从需求分析到部署的全流程详解
  • UE5 材质-14:减法subtract节点适用于向量与标量,数学 if 组件,由已遮罩材质结合自发光参数,周期性改变蒙版的大小,实现溶解效果
  • 构建AI智能体:七十一、模型评估指南:准确率、精确率、F1分数与ROC/AUC的深度解析
  • 基于脚手架微服务的视频点播系统-客户端业务逻辑处理部分(二)
  • 电商网站开发 文献综述百度网址大全 旧版本
  • 网站平台建设保密协议新网域名续费
  • 机器学习之生成对抗网络(GAN)
  • 零基础-动手学深度学习-13.11. 全卷积网络
  • JMeter测试关系数据库: JDBC连接
  • Linux(五):进程优先级
  • 【算法专题训练】26、队列的应用-广度优先搜索
  • 可靠性SLA:服务稳定性的量化承诺
  • 收集飞花令碎片——C语言内存函数
  • c语言-字符串
  • 红帽Linux -章8 监控与管理进程