Java 使用 XDocReport 导出 word 包含图片表格的处理

本文介绍了如何使用Java的XDocReport库结合Freemarker模板引擎,处理Word文档中的图片遍历插入。通过设置编辑域和使用IImageProvider接口,实现了在表格中根据数据列表动态插入多张图片的功能。同时提供了实体类和测试代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java 使用 XDocReport 导出word

前言

遇到word中,表格中每一个单元格图片需要遍历插入多张图片的问题,word模板制作也ok,但是遍历不展示,
主要是图片和表格都需要遍历,所以需要加标记,下面做一下两者的区别和实际展示的效果

首先根据制作word模板,绘制自己想要的样式,然后在需要动态生成的地方设置编辑域
(快捷键: ctrl + F9) ,右击可以修改编辑域的内容, 如图:
在这里插入图片描述
在这里插入图片描述

多张图片时需要 @before-row 和 @after-row 来制定最外层的list 循环

遍历一个加了 @before-row[#list data as h1] .... .....  @after-row[/#list]  
图片用书签定义的时候,同一个文件需要把每个key值唯一,如图:pic1,pic2 

在这里插入图片描述

实体类:
import lombok.Data;

import java.util.List;

/**
 * 模板中excel的内容
 */
@Data
public class XDocExportVo1 {

    // 描述1
    private String hiddenDescribe;

    // 描述2
    private String reformDescribe;

    // 调整前照片
    private List<PicVo> hiddenPics;

    // 调整后照片
    private List<PicVo> reformPics;

}

import fr.opensagres.xdocreport.document.images.IImageProvider;
import lombok.Data;

@Data
public class PicVo {
    // 模板中需要的图片
    private IImageProvider pic;
}
测试类:

import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.images.FileImageProvider;
import fr.opensagres.xdocreport.document.images.IImageProvider;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import fr.opensagres.xdocreport.template.formatter.NullImageBehaviour;
import vo.PicVo;
import vo.XDocExportVo1;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class TestXDocExport {
    public static void main(String[] args) throws Exception {
        export();
    }

    //实现类
    public static void export() throws Exception {
        //1.通过freemarker模板引擎加载文档,并缓存到registry中
        InputStream in = new FileInputStream("F:\\test_path\\model\\xDocExportModel1.docx");
//        InputStream in = TestXDocExport.class.getResourceAsStream("/templates/xDocExportModel1.docx");
        IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
        //2.设置填充字段、填充类以及是否为list。
        FieldsMetadata fieldsMetadata = report.createFieldsMetadata();
        // 文本
        IContext context = report.createContext();
        context.put("title1", "导出样式1");
        context.put("time1", "2023-05-16");

        /** *******************设置表格内容数据 BEGIN **************** */
        List<XDocExportVo1> list = new ArrayList<>();
        // 第一行数据
        XDocExportVo1 docExportVo1 = new XDocExportVo1();
        docExportVo1.setHiddenDescribe("调整前1");
        docExportVo1.setReformDescribe("调整后1");
        // 图片数据
        List<PicVo> picVos = new ArrayList<>();
        // 用本地的图片做一下测试,实际用途中需要根据自己的项目地址来
        IImageProvider p = new FileImageProvider(new File("F:\\test_path\\cat001.jpg"));
        // 设置图片的大小
        // p.setSize(30f,40f);
        PicVo picVo = new PicVo();
        picVo.setPic(p);
        picVos.add(picVo);

        IImageProvider p1 = new FileImageProvider(new File("F:\\test_path\\cat002.jpg"));
        PicVo picVo1 = new PicVo();
        picVo1.setPic(p1);
        picVos.add(picVo1);
        docExportVo1.setHiddenPics(picVos);

        List<PicVo> picVos2 = new ArrayList<>();
        IImageProvider p3 = new FileImageProvider(new File("F:\\test_path\\xiaomaomi1.jpeg"));
        PicVo picVo2 = new PicVo();
        picVo2.setPic(p3);
        picVos2.add(picVo2);

        IImageProvider p4 = new FileImageProvider(new File("F:\\test_path\\xiaomaomi2.jpeg"));
        PicVo picVo3 = new PicVo();
        picVo3.setPic(p4);
        picVos2.add(picVo3);
        docExportVo1.setReformPics(picVos2);
        list.add(docExportVo1);

        // 第二行数据(这里就简单点写了)
        XDocExportVo1 docExportVo2 = new XDocExportVo1();
        docExportVo2.setHiddenDescribe("调整前2");
        docExportVo2.setReformDescribe("调整后2");
        docExportVo2.setHiddenPics(picVos2);
        docExportVo2.setReformPics(picVos);
        list.add(docExportVo2);

        /** *******************设置表格内容数据 END **************** */
        // 设置表格数据
        context.put("data", list);
        // 设置list的数据来源模型
        fieldsMetadata.load("data",XDocExportVo1.class,true);

        //特殊字符
        fieldsMetadata.addFieldAsImage("pic1","list1.pic", NullImageBehaviour.RemoveImageTemplate);
        fieldsMetadata.addFieldAsImage("pic2","list2.pic", NullImageBehaviour.RemoveImageTemplate);

        OutputStream out = new FileOutputStream(new File("F:\\test_path\\model\\xDocExportModel1_out.docx"));
        report.setFieldsMetadata(fieldsMetadata);
        report.process(context, out);
        out.close();
    }
}

模板和导出效果

在这里插入图片描述

在这里插入图片描述

如果是单张图片

模板相对简单点,直接上代码

import fr.opensagres.xdocreport.document.images.IImageProvider;
import lombok.Data;

import java.util.List;

/**
 * 模板中excel的内容
 */
@Data
public class XDocExportVo2 {

    // 描述1
    private String hiddenDescribe;

    // 描述2
    private String reformDescribe;

    // 调整前照片
    private IImageProvider pic1;

    // 调整后照片
    private IImageProvider pic2;

}

import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.images.FileImageProvider;
import fr.opensagres.xdocreport.document.images.IImageProvider;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import fr.opensagres.xdocreport.template.formatter.NullImageBehaviour;
import vo.PicVo;
import vo.XDocExportVo1;
import vo.XDocExportVo2;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 模板2测试
 */
public class TestXDocExport2 {
    public static void main(String[] args) throws Exception {
        export();
    }

    //实现类
    public static void export() throws Exception {
        //1.通过freemarker模板引擎加载文档,并缓存到registry中
        InputStream in = TestXDocExport.class.getResourceAsStream("/templates/xDocExportModel2.docx");
        IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
        //2.设置填充字段、填充类以及是否为list。
        FieldsMetadata fieldsMetadata = report.createFieldsMetadata();
        // 文本
        IContext context = report.createContext();
        context.put("title1", "导出样式1");
        context.put("time1", "2023-05-16");

        /** *******************设置表格内容数据 BEGIN **************** */
        List<XDocExportVo2> list = new ArrayList<>();
        // 第一行数据
        XDocExportVo2 docExportVo1 = new XDocExportVo2();
        docExportVo1.setHiddenDescribe("调整前1");
        docExportVo1.setReformDescribe("调整后1");
        // 图片数据
        // 用本地的图片做一下测试,实际用途中需要根据自己的项目地址来
        IImageProvider p = new FileImageProvider(new File("F:\\test_path\\cat001.jpg"));
        // 设置图片的大小
        // p.setSize(30f,40f);
        docExportVo1.setPic1(p);
        docExportVo1.setPic2(new FileImageProvider(new File("F:\\test_path\\cat002.jpg")));
        list.add(docExportVo1);

        // 第二行数据(这里就简单点写了)
        XDocExportVo2 docExportVo2 = new XDocExportVo2();
        docExportVo2.setHiddenDescribe("调整前2");
        docExportVo2.setReformDescribe("调整后2");

        docExportVo2.setPic1(new FileImageProvider(new File("F:\\test_path\\xiaomaomi1.jpeg")));
        docExportVo2.setPic2(new FileImageProvider(new File("F:\\test_path\\xiaomaomi2.jpeg")));
        list.add(docExportVo2);

        /** *******************设置表格内容数据 END **************** */

        // 模板2
        // 设置表格数据
        context.put("h1", list);
        // 设置list的数据来源模型
        fieldsMetadata.load("h1", XDocExportVo2.class,true);
        //特殊字符
        fieldsMetadata.addFieldAsImage("pic1","h1.pic1", NullImageBehaviour.RemoveImageTemplate);
        fieldsMetadata.addFieldAsImage("pic2","h1.pic2", NullImageBehaviour.RemoveImageTemplate);

        OutputStream out = new FileOutputStream(new File("F:\\test_path\\model\\xDocExportModel2_out2.docx"));
        report.setFieldsMetadata(fieldsMetadata);
        report.process(context, out);
        out.close();
    }
}

在这里插入图片描述
在这里插入图片描述
[写了一个demo,可以点击链接下载看看]
https://download.youkuaiyun.com/download/weixin_35332034/87789220

### 使用Java导出复杂Word文档 #### Apache POI 库的应用 对于较为复杂的Word文档生成需求,Apache POI库提供了强大的功能。该库不仅能够处理简单的文本插入,还支持表格图片以及样式设置等多种高级特性[^1]。 ```java import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; public class ComplexWordExport { public static void main(String[] args) throws Exception { // 创建一个新的Word文档对象 XWPFDocument document = new XWPFDocument(); // 添加段落 XWPFParagraph paragraph = document.createParagraph(); XWPFRun run = paragraph.createRun(); // 设置字体大小和粗体属性 run.setFontSize(20); run.setBold(true); // 插入文字内容 run.setText("这是一个带有样式的段落"); // 将文档保存到指定路径下 FileOutputStream out = new FileOutputStream(new File("example.docx")); document.write(out); out.close(); document.close(); } } ``` 这段代码展示了如何利用Apache POI创建一个具有特定格式的段落,并将其写入`.docx`文件中。 #### 结合XDocReport与FreeMarker模板引擎 另一种高效的方式是采用XDocReport结合FreeMarker模板引擎来构建更加灵活多变的内容布局方案。这种方式允许开发者预先定义好文档结构作为模板,在实际运行时动态填充所需的数据字段,从而简化了程序逻辑的设计过程[^2]。 ```xml <!-- docx-template.ftl --> <#list items as item> ${item.name} - ${item.value}<br/> </#list> ``` ```java import fr.opensagres.xdocreport.document.IXDocReport; import fr.opensagres.xdocreport.document.registry.XDocReportRegistry; import freemarker.template.Configuration; import java.io.InputStream; import java.util.HashMap; import java.util.Map; public class TemplateBasedWordExport { private static final String TEMPLATE_PATH = "path/to/docx-template.ftl"; public static void generateReport() throws Exception{ Configuration cfg = new Configuration(Configuration.VERSION_2_3_31); Map<String, Object> dataModel = new HashMap<>(); List<Item> itemList = Arrays.asList( new Item("Item 1", "Value A"), new Item("Item 2", "Value B") ); dataModel.put("items", itemList ); InputStream in = getClass().getResourceAsStream("/"+TEMPLATE_PATH); IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in ,IXDocReport.Kind.FREEMARKER); IContext context = report.createContext(); context.putAll(dataModel); OutputStream out = new ByteArrayOutputStream(); report.process(context,out); Files.copy(((ByteArrayOutputStream)out).toByteArray(), Paths.get("output-report.docx"), StandardCopyOption.REPLACE_EXISTING); } static class Item { private String name; private String value; public Item(String n, String v){ this.name=n;this.value=v; } // Getters and setters... } } ``` 上述例子说明了怎样通过加载预设好的FTL模板文件并传入相应的数据模型完成最终报告的组装工作[^3]. #### Poi-Tl 模板语言的优势 当面对更为复杂的场景比如需要频繁调整页面版面设计或是希望减少编码量的情况下,则可以考虑引入专门针对Word文档定制化的poi-tl框架。它在继承了POI原有优势的基础上进一步优化了API接口的人机交互体验,使得即使是没有太多编程经验的操作人员也能轻松上手[^4].
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值