热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

springboot中使用poitl导出word(包含表格合并单元格)实例

一、背景在业务开发过程中,遇到有需要生成包含表格的word文档,且一部分表格需要动态生成,且需要根据数据来合并单元格,最后呈

一、背景

        在业务开发过程中,遇到有需要生成包含表格的word文档,且一部分表格需要动态生成,且需要根据数据来合并单元格,最后呈现的方式如下图:

 一开始想到的解决方案是通过freemarker来生成,但是需要转xml生成模板,过程比较复杂,因此,在查阅一些资料后,最终选择了poi-tl来实现。相比于freemarker,poi-tl导出word的好处在于可以直接使用word模板,比较直观,且比较好调整格式。

二、实现

1、引入jar包


com.deepoovepoi-tl1.7.3

org.apache.poipoi-ooxml4.1.2

org.apache.poipoi-ooxml-schemas4.1.2

org.apache.poipoi4.1.2

2、构造word模板

        1)简单包含属性的表格模板

        


姓名{{name}}年龄{{age}}
身份证号{{idCardNo}}家庭住址{{addr}}
联系电话{{tel}}学历{{education}}
是否党员{{isPartyMember}}毕业院校{{school}}
紧急联系人{{contactPer}}紧急联系方式{{contactTel}}
邮箱{{email}}

        2)需要循环list填充的表格模板


{{userList}} 姓名性别年龄
[name][sex][age]

        3)需要动态合并单元格的表格模板


{{userList}}班级小组姓名学号

        合并单元格操作需要在代码实现

3、代码实现合并单元格

public void export(HttpServletResponse response, SysDefineMethod sysDefineMethod) {Map dataMap = new HashMap<>();//企业基本信息dataMap.put("baseInfo", baseInfo);//机组信息dataMap.put("unitList", unitList);//人员信息dataMap.put("userList", userList);ClassPathResource classPathResource = new ClassPathResource("templates/template.docx");String resource = classPathResource.getUrl().getPath();//给需要单独处理的表格绑定处理策略Configure cOnfig= Configure.newBuilder().bind("unitList", new DefineMethodPolicy()).build();XWPFTemplate template = XWPFTemplate.compile(resource, config).render(dataMap);// 生成的word格式String formatSuffix = ".docx";// 拼接后的文件名String fileName = "GreenHouseGas" + System.currentTimeMillis() + formatSuffix;//文件名try {//=================生成word到设置浏览默认下载地址=================// 设置强制下载不打开response.setContentType("application/force-download");// 设置文件名response.addHeader("Content-Disposition", "attachment;filename=" + fileName);OutputStream out = response.getOutputStream();template.write(out);out.flush();out.close();template.close();} catch (Exception e) {e.printStackTrace();}}

机组信息合并单元格策略类

package com.carbon.system.policy;import com.alibaba.fastjson.JSON;
import com.carbon.system.domain.SysDefineMethod;
import com.carbon.system.domain.vo.ElectricityInfoVo;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.springframework.util.CollectionUtils;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** @Description* @Author admin*/
public class DefineMethodPolicy extends DynamicTableRenderPolicy {// 填充数据所在行数int listsStartRow = 2;@Overridepublic void render(XWPFTable table, Object data) {if (null == data) {return;}List defineMethodList = JSON.parseArray(JSON.toJSONString(data), SysDefineMethod.class);Map> unitDefineMethodMap = defineMethodList.stream().collect(Collectors.groupingBy(SysDefineMethod::getUnitId));Map> unitParamMap = defineMethodList.stream().collect(Collectors.groupingBy(defineMethod->defineMethod.getUnitId()+"-"+defineMethod.getParamType()));if (!CollectionUtils.isEmpty(defineMethodList)) {table.removeRow(listsStartRow);List dataList = new ArrayList<>();for (SysDefineMethod tmp : defineMethodList) {String paramType = tmp.getParamType();switch (paramType){case "0":tmp.setParamType("测试参数1");break;case "1":tmp.setParamType("测试参数2");}RowRenderData renderData = RowRenderData.build(tmp.getUnitName(),tmp.getParamType(),tmp.getParamMonth().toString(),tmp.getEquipmentModel()==null?"":tmp.getEquipmentModel(),tmp.getCheckFrequency()==null?"":tmp.getCheckFrequency(),tmp.getCheckFrequencyRule()==null?"":tmp.getCheckFrequencyRule(),tmp.getCheckMethodStandard()==null?"":tmp.getCheckMethodStandard(),tmp.getEntrustOrgName()==null?"":tmp.getEntrustOrgName(),tmp.getCheckReportNo()==null?"":tmp.getCheckReportNo(),tmp.getCheckDate()==null?"":tmp.getCheckDate().toString(),tmp.getMethodStandardEntrust()==null?"":tmp.getMethodStandardEntrust(),tmp.getDefaultValue()==null?"":tmp.getDefaultValue());dataList.add(renderData);}// 循环插入行for (int i = dataList.size() - 1; i >= 0; i--) {XWPFTableRow insertNewTableRow = table.insertNewTableRow(listsStartRow);for (int j = 0; j <12; j++) {insertNewTableRow.createCell();}// 渲染单行机组数据MiniTableRenderPolicy.Helper.renderRow(table, listsStartRow, dataList.get(i));}List unitList = JSON.parseArray(JSON.toJSONString(unitDefineMethodMap.keySet()), Integer.class);List paramList = JSON.parseArray(JSON.toJSONString(unitParamMap.keySet()), String.class);//处理合并for (int i = 0; i tmpList = unitDefineMethodMap.get(unitId);if (unit_name.equals(unitName)) {// 合并第0列的第i+2行到第i+unitSize行的单元格TableTools.mergeCellsVertically(table, 0, i + 2, i + tmpList.size()+1);//处理垂直居中for (int y = 0; y <12; y++) {XWPFTableCell cell = table.getRow(i + 2).getCell(y);cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); //垂直居中}unitList.remove(j);break;}}//处理第二列参数类型合并Object v1 = dataList.get(i).getCells().get(1).getCellText();String paramType = v+"-"+v1;for (int j = 0; j tmpList = unitParamMap.get(key);String paramName=tmpList.get(0).getUnitName()+"-"+tmpList.get(0).getParamType();if (paramType.equals(paramName)) {// 合并第1列的第i+1行到第i+unitSize行的单元格TableTools.mergeCellsVertically(table, 1, i+2, i + tmpList.size()+1);//处理垂直居中for (int y = 0; y <12; y++) {XWPFTableCell cell = table.getRow(i + 2).getCell(y);cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); //垂直居中}paramList.remove(j);break;}}}}}
}


推荐阅读
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文详细介绍了PHP中与URL处理相关的三个函数:http_build_query、parse_str和查询字符串的解析。通过示例和语法说明,讲解了这些函数的使用方法和作用,帮助读者更好地理解和应用。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • node.jsrequire和ES6导入导出的区别原 ... [详细]
author-avatar
air12345
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有