如何通过Aspose.Word Java实现JSON驱动的普通域与表格邮件合并?
解决方案:基于JSON完成Aspose.Words普通域+表格区域邮件合并
核心思路
不需要依赖硬编码XML或分两次执行合并,两种可行方案都能基于单一JSON输入完成需求,以下是具体实现:
方案一:直接用JSON处理两类合并(推荐)
利用Aspose.Words原生的JsonDataSource处理表格区域,同时用普通execute()处理单值域,将两次调用封装成统一逻辑,对外部接口透明。
代码实现(Spring Boot环境)
import com.aspose.words.*; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; public class MailMergeService { public byte[] mergeWord(byte[] templateBytes, String jsonInput) throws Exception { // 1. 解析JSON数据 ObjectMapper objectMapper = new ObjectMapper(); Map<String, Object> dataMap = objectMapper.readValue(jsonInput, new TypeReference<>() {}); // 分离普通域数据和表格区域数据 Map<String, Object> commonFields = new HashMap<>(); String tableRegionName = null; List<?> tableData = null; for (Map.Entry<String, Object> entry : dataMap.entrySet()) { if (entry.getValue() instanceof List) { tableRegionName = entry.getKey(); tableData = (List<?>) entry.getValue(); } else { commonFields.put(entry.getKey(), entry.getValue()); } } // 2. 加载Word模板 Document doc = new Document(new ByteArrayInputStream(templateBytes)); // 3. 执行普通域合并 doc.getMailMerge().execute( commonFields.keySet().toArray(new String[0]), commonFields.values().toArray() ); // 4. 执行表格区域合并 if (tableRegionName != null && tableData != null) { JsonDataSource jsonDataSource = new JsonDataSource( new ByteArrayInputStream(jsonInput.getBytes(StandardCharsets.UTF_8)) ); doc.getMailMerge().executeWithRegions(jsonDataSource); } // 5. 输出合并后的文档 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); doc.save(outputStream, SaveFormat.DOCX); return outputStream.toByteArray(); } }
注意事项
- Word模板中:普通域用
{MERGEFIELD title}格式,表格区域需标记{TableStart:Table1}和{TableEnd:Table1}(与JSON中的数组键名一致) - Aspose.Words版本需≥19.10(原生支持
JsonDataSource)
方案二:JSON转符合要求的XML统一合并
通过Jackson将JSON转换成Aspose.Words可识别的XML结构,一次性调用executeWithRegions()完成两类合并。
步骤1:定义映射实体类
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import java.util.List; @JacksonXmlRootElement(localName = "Root") public class MergeData { @JacksonXmlProperty(localName = "title") private String title; @JacksonXmlProperty(localName = "header") private String header; @JacksonXmlElementWrapper(localName = "Table1") @JacksonXmlProperty(localName = "Item") private List<TableItem> table1; // getter、setter省略 } class TableItem { @JacksonXmlProperty(localName = "name") private String name; @JacksonXmlProperty(localName = "age") private Integer age; // getter、setter省略 }
步骤2:JSON转XML并执行合并
import com.aspose.words.*; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; public class MailMergeXmlService { public byte[] mergeWord(byte[] templateBytes, String jsonInput) throws Exception { // 1. JSON转XML ObjectMapper objectMapper = new ObjectMapper(); MergeData mergeData = objectMapper.readValue(jsonInput, MergeData.class); XmlMapper xmlMapper = new XmlMapper(); String xmlData = xmlMapper.writeValueAsString(mergeData); // 2. 加载XML数据源 XmlMailMergeDataSource dataSource = new XmlMailMergeDataSource( new ByteArrayInputStream(xmlData.getBytes(StandardCharsets.UTF_8)), "Root" ); // 3. 执行合并 Document doc = new Document(new ByteArrayInputStream(templateBytes)); doc.getMailMerge().executeWithRegions(dataSource); // 4. 输出结果 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); doc.save(outputStream, SaveFormat.DOCX); return outputStream.toByteArray(); } }
关键说明
- 生成的XML结构符合Aspose要求:根节点为
<Root>,普通域作为根节点子元素,表格区域用<Table1>包裹<Item>子节点(对应Word中的区域标记) - 此方案适合需要统一用
executeWithRegions()处理的场景,但多了一次JSON转XML的开销
最优方案选择
- 优先选方案一:无需额外转换,逻辑简单,性能更优,仅需两次合并调用但可封装成统一接口,对外部无感知
- 方案二适合必须用单一
executeWithRegions()调用的场景,需确保XML结构与Word模板标记完全匹配
内容的提问来源于stack exchange,提问作者Pankaj Patil
相关产品推荐
相关产品推荐

