使用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 

在Java中,使用XDocReport和FreeMarker模板引擎结合Apache POI库来处理Word文档时,如果你想要遍历嵌套的集合并将其内容插入到Word文档中,通常会这样做: 首先,你需要在FreeMarker模板文件(`.ftl`)中设置循环结构。假设你有一个List<List<String>>的对象,你可以这样表示: ```freemarker <#list outerCollection as outerItem> <table border="1"> <#list outerItem as innerItem> <tr> <td>${innerItem}</td> <!-- 这里将innerItem遍历显示 --> </tr> </#list> </table> </#list> ``` 然后,在Java代码中,你需要准备数据模型,包括你的嵌套集合,并传递给XDocReport: ```java import freemarker.template.Configuration; import org.xdocreport.core.XDocReport; import org.xdocreport.data.DocumentDataModel; public void generateReport(List<List<String>> data) throws Exception { // 初始化Freemarker配置 Configuration cfg = new Configuration(Configuration.VERSION_2_3_30); cfg.setClassForTemplateLoading(getClass(), "/templates"); // 指定模板路径 // 创建数据模型 DocumentDataModel model = new DocumentDataModel(); model.put("outerCollection", data); // 将嵌套集合放入数据模型 // 使用XDocReport生成Word文档 XDocReport report = new XDocReport(cfg); String templateName = "your_template_name.docx"; // 模板文件名 InputStream inputStream = Resources.getResourceAsStream(templateName); OutputStream outputStream = new FileOutputStream("output.docx"); report.generateDocument(inputStream, model, outputStream); inputStream.close(); // 关闭输入流 outputStream.close(); // 关闭输出流 } ``` 在上述代码中,`Resources.getResourceAsStream()`需要替换为你实际的资源获取方式,如从类路径读取。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值