使用xdocreport导出word

之前java总用freemaker进行导出,但是改xml实在是太繁琐了,这次找了另一个工具进行体验.

一、简单导出

pom引入

 <dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres.xdocreport.core</artifactId><version>2.0.6</version></dependency><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres.xdocreport.document</artifactId><version>2.0.6</version></dependency><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres.xdocreport.template</artifactId><version>2.0.6</version></dependency><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres.xdocreport.document.docx</artifactId><version>2.0.6</version></dependency><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId><version>2.0.6</version></dependency>

导出代码

public void genDoc() {RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;HttpServletResponse response = attributes.getResponse();try (InputStream inputStream = POICacheManager.getFile("template.docx")) {// 3. 读取模板,创建 IXDocReport 对象IXDocReport report = XDocReportRegistry.getRegistry().loadReport(inputStream, TemplateEngineKind.Freemarker);// 4. 创建上下文,设置变量(你可以按需扩展)IContext context = report.createContext();context.put("name", "张三");//编辑域代码 ctrl F9 类别选 邮件合并 域名mergefield 域代码后面填 ${name}// 设置响应头,准备输出 Word 文件response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");response.setHeader("Content-Disposition", "attachment; filename=generated-document.docx");// 5. 生成 Word 并写入响应输出流try (OutputStream out = response.getOutputStream()) {report.process(context, out);}} catch (Exception e) {log.error(">>> 生成 Word 失败:", e);// 手动返回错误信息try {response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);response.getWriter().write("生成文档失败:" + e.getMessage());} catch (Exception ex) {log.error(">>> 写回错误信息失败", ex);}}}

在resource目录新建word文件名为template.docx

打开template.docx

输入任意字符,然后 Ctrl+9插入域,然后右键编辑域,类别选 邮件合并 域名选mergefield 域代码后面填 ${name} 保存后用上面的代码导出

导出后可以看到域代码位置被填充为张三了。

二、进阶用法

1.动态表格行

分两种情况处理

(1)第一列为序号列

将第一列填充3个域  

"@before-row[#list productInfoList as item]" 
${item?index+1} 
@after-row[/#list] 

第二列 填充实际的字段即可

${item.name}

(2)第一列不序号列

将上文中的序号表达式${item?index+1} 换成你想填充的表达式,如

${item.code} 

其他处理跟上卖弄一样

在java中的定义,先定义实体,然后context.put即可

//假设之前定义了productInfo实体,实体有code name等字段
List<ProductInfo> productInfoList = new ArrayList();
...context.put("productInfoList", productInfoList );

2.图片

图片不用域,在要导入的地方插入一张图片,然后建立书签,建立书签的方法如下

选中文档中的某张图片,单击【插入】菜单下【链接】子菜单中的【书签】。

这里的书签名跟上面的域变量名类似

java代码

//根据文件读取
IImageProvider iImageProvider = new FileImageProvider(file, false);
context.put("pic", iImageProvider);//dataurlbase64的字符串,不含前缀
byte[] imageBytes = Base64.getDecoder().decode(base64Image);
//创建 ByteArrayImageProvider 实例
ByteArrayImageProvider imageProvider = new ByteArrayImageProvider(imageBytes, "png");
context.put("pic", imageProvider );

3.条件显示隐藏

使用if标签,下面是3个域

[#if data.ccUser??] 申请人:${data.ccUser } [/#if]

可以看到两个if标签域包裹了文字和变量

4.空值处理

空值直接使用会报错,可使用表达式

${tx.amount!}

或者

${tx.amount?if_exists}

上面表达式表示有值填充,无值不填充

5.单元格合并

实现起来比较复杂,在模板中先合并,然后对多列使用第一节的动态表格行基本上可以实现按层级合并,如果是跨列合并,比较复杂的合并目前还没找到好的解决方案?或许需要考虑原生freemaker或者poi-tl?

6.关键字

在实体中应尽量避免使用以下关键字

length 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/86074.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …

C++.OpenGL (2/64)你好,三角形(Hello Triangle)

你好,三角形(Hello Triangle) 绘制流程概览 #mermaid-svg-MvIGIovxiuKVfzy8 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MvIGIovxiuKVfzy8 .error-icon{fill:#552222;}#mermaid-svg-MvIGIovxiuKVfzy8 .error…

汽车安全体系:FuSa、SOTIF、Cybersecurity 从理论到实战

汽车安全&#xff1a;功能安全&#xff08;FuSa&#xff09;、预期功能安全&#xff08;SOTIF&#xff09;与网络安全(Cybersecurity) 从理论到实战的安全体系 引言&#xff1a;自动驾驶浪潮下的安全挑战 随着自动驾驶技术从L2向L4快速演进&#xff0c;汽车安全正从“机械可靠…

N2语法 列挙、話題提出

1&#xff0c;&#xff5e;やら&#xff5e;やら  接続&#xff1a;名詞、辞書形  意味&#xff1a;…啦…啦&#xff08;列举代表性的事物&#xff09;  例文&#xff1a;     家に帰って料理やら洗濯やら何もしなければならない。     帰国前、買い物やら荷造りや…

深入理解React Hooks的原理与实践

深入理解React Hooks的原理与实践 引言 React Hooks 自 2018 年 React 16.8 发布以来&#xff0c;彻底改变了前端开发者的编码方式。它通过函数式组件提供了状态管理和生命周期等功能&#xff0c;取代了传统的类组件&#xff0c;使得代码更加简洁、复用性更强。然而&#xff…

RockyLinux9.6搭建k8s集群

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

链游技术破壁:NFT资产确权与Play-to-Earn经济模型实战

链游技术破壁&#xff1a;NFT资产确权与Play-to-Earn经济模型实战 ——从「投机泡沫」到「可持续生态」的技术重构 一、NFT确权技术革新&#xff1a;从链上存证到动态赋权 跨链确权架构 全链互操作协议&#xff1a;采用LayerZero协议实现以太坊装备与Solana土地的跨链组合&…

Java下载文件(特殊字符编码处理)

当你在这个问题上花费了数小时而解决不了&#xff0c;你才会知道这篇文章对你的帮助 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.http.HttpEntity; import org.springframewo…

TDengine 高级功能——读缓存

简介 在物联网&#xff08;IoT&#xff09;和工业互联网&#xff08;IIoT&#xff09;大数据应用场景中&#xff0c;实时数据的价值往往远超历史数据。企业不仅需要数据处理系统具备高效的实时写入能力&#xff0c;更需要能快速获取设备的最新状态&#xff0c;或者对最新数据进…

YOLO在C#中的完整训练、验证与部署方案

YOLO在C#中的完整训练、验证与部署方案 C# 在 YOLO 部署上优势明显&#xff08;高性能、易集成&#xff09;&#xff0c;但训练能力较弱&#xff0c;通常需结合 Python 实现。若项目对开发效率要求高且不依赖 C# 生态&#xff0c;建议全程使用 Python&#xff1b;若需深度集成…

pikachu靶场通关笔记17 CSRF关卡03-CSRF(Token)

目录 一、CSRF原理 二、CSRF Token 三、源码分析 四、CSRF Token tracker插件 1、插件简介 2、插件安装 五、渗透实战 1、用户登录 2、修改个人信息 3、bp拦截报文 4、bp改报文探测 5、配置CSRF-Token-Tracer 6、bp改包成功 7、查看CSRF Token Tracker配置 本系…

C#面试问题81-100

85. What are anonymous types? 匿名类型是在需要的地方直接定义的类型&#xff0c;甚至都 不给它命名。它非常适合我们这种用例——类型小且临时&#xff0c;而且我们无意在其 他地方使用它 匿名类型是直接从 System.Object 派生的类对象。它们不能转换为任何 其他类型。●…

【Ragflow】25.Ragflow-plus开发日志:excel文件解析新思路/公式解析适配

引言 RagflowPlus v0.3.0 版本中&#xff0c;增加了对excel文件的解析支持&#xff0c;但收到反馈&#xff0c;说效果并不佳。 以下测试文件内容来自群友反馈提供&#xff0c;数据已脱敏处理。 经系统解析后&#xff0c;分块效果如下&#xff1a; 可以看到&#xff0c;由于该…

VS2022下C++ Boost库安装与使用使用

一.Boost概述 1.简介 Boost 是一个广泛使用的 C 库集合&#xff0c;提供了许多高质量、可移植、高效的工具和组件&#xff0c;被视为 C 标准库的延伸。自 1998 年成立以来&#xff0c;Boost 已成为 C 社区的核心资源&#xff0c;许多 Boost 库通过实践验证后被纳入 C 标准&am…

内嵌式mqtt server

添加moquette依赖 <dependency><groupId>io.moquette</groupId><artifactId>moquette-broker</artifactId><version>0.17</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>…

php执行后报502,无错误提示的排查和解决

文章目录 一、阐述问题二、开始排查1.执行代码展示2.PHP层面排查问题3.系统层面排查问题1. 分析系统日志2. core dump 分析2.1 core dump 是什么2.2 core dump 配置 并 生成 core 文件2.3 gdb 解析 core 文件 4. 问题解决 三、赠送内容四、总结 一、阐述问题 这个问题花了我起…

MySQL 核心知识点解析

最近正在复习Java八股&#xff0c;所以会将一些热门的八股问题&#xff0c;结合ai与自身理解写成博客便于记忆 InnoDB 和 MyISAM 的区别 特性InnoDBMyISAM事务支持支持ACID事务不支持事务锁机制行级锁表级锁外键支持支持不支持崩溃恢复有crash-safe能力无存储结构聚簇索引非…

CppCon 2015 学习:Comparison is not simple, but it can be simpler.

What is comparison? 这段文字是从计算机科学、编译器设计或系统优化的角度来定义和评价“比较&#xff08;comparison&#xff09;”这个操作&#xff1a; 1. Pervasive&#xff08;无处不在&#xff09; 比较操作在编程中极为常见&#xff0c;存在于&#xff1a; 分支语句&…

RocketMQ入门5.3.2版本(基于java、SpringBoot操作)

一、RocketMQ概述 RocketMQ是一款由阿里巴巴于2012年开源的分布式消息中间件&#xff0c;旨在提供高吞吐量、高可靠性的消息传递服务。主要特点有&#xff1a; 灵活的可扩展性 海量消息堆积能力 支持顺序消息 支持多种消息过滤方式 支持事务消息 支持回溯消费 支持延时消…

VR线上展厅特点分析与优势

VR线上展厅&#xff1a;特点、优势与实际应用 VR线上展厅&#xff0c;作为虚拟现实&#xff08;VR&#xff09;技术在展示行业的创新应用&#xff0c;正逐步改变着传统的展览方式。通过模拟真实的物理环境&#xff0c;为参观者提供身临其境的展览体验&#xff0c;成为展示行业…