docx4j操作word文档之替换模板数据

docx4j替换模板数据

docx4j

docx4j是一个开源(ASLv2)Java库,用于创建和操作Microsoft Open XML(Word docx,Powerpoint pptx和Excel xlsx)文件;它类似于Microsoft的OpenXML SDK,但适用于Java。docx4j使用JAXB来创建内存中的对象表示。

示例

1. word中创建占位符

如果我要替换word文档中的动态数据,只需把数据用${xxx}形式标注。
在这里插入图片描述
这里可能会存在一个问题:
将.docx文档压缩成.zip文档,再xml文件阅读器打开word/document.xml文件,可以看到有可能出现下图占位符被分隔的问题,这样的话,到时候不能被数据替换。
在这里插入图片描述
原因:网上有许多,有的说占位符格式不统一;有的说单词校验问题。
解决方法:我刚开始试了把占位符的格式统一,好像没什么用,然后只能在xml文件里一个一个的改,既累又麻烦!最后,把要写的占位符先写到记事本中,然后再复制到word中,这样就不会被分隔。

2.获取模板以及替换数据

import org.docx4j.model.datastorage.migration.VariablePrepare;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;

import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

public class Docx4jDemo1 {

    public static void main(String[] args) {
        Map<String, String> data = new HashMap<>();
        data.put("classname", "三年二班");
        data.put("total", "50");
        data.put("male", "30");
        data.put("female", "20");
        data.put("name", "小明");
        data.put("sex", "男");
        data.put("age", "10");
        data.put("phone", "13888888888");
        data.put("address", "中国");
        data.put("email", "xiaoming@163.com");
        try {
            replaceData(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 加载模板并替换数据
     *
     * @param data
     * @return
     * @throws Exception
     */
    public static void replaceData(Map<String, String> data) throws Exception {
        final String TEMPLATE_NAME = "D://1.docx";
        InputStream templateInputStream = new FileInputStream(TEMPLATE_NAME);
        //加载模板文件并创建WordprocessingMLPackage对象
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(templateInputStream);
        MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
        VariablePrepare.prepare(wordMLPackage);
        documentPart.variableReplace(data);
        OutputStream os = new FileOutputStream(new File("D://test.docx"));
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        wordMLPackage.save(outputStream);
        outputStream.writeTo(os);
        os.close();
        outputStream.close();
        templateInputStream.close();
    }

    /**
     * 如果从数据库查出来的是不同对象集合,那么该方法直接把对象的属性和值直接存为Map
     * 比如示例中可以是两个对象,ClassInfo(className,total,male,female)、student(name,sex,...)
     * 前提是模板中的占位符一定要和对象的属性名一一对应
     * @param objlist
     * @return
     * @throws Exception
     */
    public HashMap<String, String> toMap(List<Object> objlist) throws Exception {
        HashMap<String, String> variables = new HashMap<>();
        String value = "";
        if (objlist == null && objlist.isEmpty()) {
            return null;
        } else {
            for (Object obj : objlist) {
                Field[] fields = null;
                fields = obj.getClass().getDeclaredFields();
                //删除字段数组里的serialVersionUID
                for (int i = 0; i < fields.length; i++) {
                    fields[i].setAccessible(true);
                    if (fields[i].getName().equals("serialVersionUID")) {
                        fields[i] = fields[fields.length - 1];
                        fields = Arrays.copyOf(fields, fields.length - 1);
                        break;
                    }
                }
                //遍历数组,获取属性名及属性值
                for (Field field : fields) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    //如果属性类型是Date
                    if (field.getGenericType().toString().equals("class java.util.Date")) {
                        PropertyDescriptor pd = new PropertyDescriptor(fieldName, obj.getClass());
                        Method getMethod = pd.getReadMethod();
                        Date date = (Date) getMethod.invoke(obj);
                        value = (date == null) ? "" : new SimpleDateFormat("yyyy-MM-dd").format(date);
                    } else if (field.getGenericType().toString().equals("class java.lang.Integer")) {
                        //如果属性类型是Integer
                        PropertyDescriptor pd = new PropertyDescriptor(fieldName, obj.getClass());
                        Method getMethod = pd.getReadMethod();
                        Object object = getMethod.invoke(obj);
                        value = (object == null) ? String.valueOf(0) : object.toString();
                       
                    } else if (field.getGenericType().toString().equals("class java.lang.Double")) {
                        //如果属性类型是Double
                        PropertyDescriptor pd = new PropertyDescriptor(fieldName, obj.getClass());
                        Method getMethod = pd.getReadMethod();
                        Object object = getMethod.invoke(obj);
                        value = (object == null) ? String.valueOf(0.0) : object.toString();
                       
                    } else {
                        PropertyDescriptor pd = new PropertyDescriptor(fieldName, obj.getClass());
                        Method getMethod = pd.getReadMethod();
                        Object object = getMethod.invoke(obj);
                        value = (object == null) ? "  " : object.toString();
                        
                    }
                    variables.put(fieldName, value);
                }
            }
            return variables;
        }
    }
}

结果

在这里插入图片描述
这些都是一些简单的功能,复杂的后续会有,因为时间关系,只写了这点。这些功能的实现都是前辈们智慧的结晶以及自己的一些探索。有什么不足之处望大家批评指正!感谢大家!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用 Docx4j 操作 Word替换占位符的 Java 代码示例: ```java import java.io.File; import java.util.HashMap; import javax.xml.bind.JAXBElement; import org.docx4j.dml.wordprocessingDrawing.Inline; import org.docx4j.jaxb.Context; import org.docx4j.model.fields.merge.MailMerger; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.ContentAccessor; import org.docx4j.wml.Document; import org.docx4j.wml.Drawing; import org.docx4j.wml.R; import org.docx4j.wml.Text; public class Docx4jDemo { public static void main(String[] args) throws Exception { // 加载模板文件 File file = new File("template.docx"); WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(file); // 获取文档主体部分 MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); Document document = documentPart.getContents(); // 定义要替换的占位符和对应的值 HashMap<String, String> mappings = new HashMap<String, String>(); mappings.put("name", "张三"); mappings.put("age", "30"); mappings.put("gender", "男"); // 替换占位符 MailMerger.performReplacements(document, mappings); // 处理含有图片的占位符 List<Object> paragraphs = document.getBody().getContent(); for (Object paragraph : paragraphs) { List<Object> runs = getAllElementFromObject(paragraph, R.class); for (Object run : runs) { List<Object> texts = getAllElementFromObject(run, Text.class); for (Object text : texts) { String value = ((Text) text).getValue(); if (value.contains("{{image")) { // 获取图片名称 String imageName = value.substring(value.indexOf("{{image=") + 8, value.indexOf("}}")); // 获取图片文件 File imageFile = new File(imageName); byte[] imageBytes = FileUtils.readFileToByteArray(imageFile); // 创建图片对象 BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, imageBytes); Inline inline = imagePart.createImageInline(null, null, 0, 1, false, 800, 600, 1); // 替换占位符 Object parent = run; List<Object> siblings = getAllElementFromObject(parent, Drawing.class); int index = siblings.indexOf(run); siblings.add(index + 1, inline); ((ContentAccessor) parent).getContent().remove(run); } } } } // 保存修改后的文档 wordMLPackage.save(new File("output.docx")); } /** * 递归获取指定类型的元素列表 * @param obj * @param toSearch * @return */ public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) { List<Object> result = new ArrayList<Object>(); if (obj instanceof JAXBElement) obj = ((JAXBElement<?>) obj).getValue(); if (obj.getClass().equals(toSearch)) { result.add(obj); } else if (obj instanceof ContentAccessor) { List<?> children = ((ContentAccessor) obj).getContent(); for (Object child : children) { result.addAll(getAllElementFromObject(child, toSearch)); } } return result; } } ``` 代码中首先加载 Word 模板文件,然后获取文档主体部分,定义要替换的占位符和对应的值,使用 MailMerger.performReplacements 方法替换占位符,最后处理含有图片的占位符,并保存修改后的文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值