使用Java填充Word模板的操作指南

2025-09-28 13:50

本文主要是介绍使用Java填充Word模板的操作指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《使用Java填充Word模板的操作指南》本文介绍了Java填充Word模板的实现方法,包括文本、列表和复选框的填充,首先通过Word域功能设置模板变量,然后使用poi-tl、aspose-words...

前言

最近有个Java填充Word模板的需求,包括文本,列表和复选框勾选,写一个工具类,以此记录。

提示:以下是本篇文章正文内容,下面案例可供参考

一、设置word模板

选择文档中要填充的地方点击->选择插入->文档部件->域->域名(mergeFeild)->填写变量名称.

普通字段

使用Java填充Word模板的操作指南

使用Java填充Word模板的操作指南

填充完毕:

使用Java填充Word模板的操作指南

列表字段

操作和普通字段一样,区别是需要在首行第一列插入列表开始域,首行最后一列插入结束域,中间正常字段。格式为:StartTable:<数组字段名>,EndTable:<数组字段名>

使用Java填充Word模板的操作指南

复选框

复选框找了好多种方法尝试没有成功,最后取巧,和普通字段一样设置占位符,通过代码逻辑处理.

使用Java填充Word模板的操作指南

二、代码

1. 引入POM

poi/hutool/ASPose-words/gson:

	<!-- hutool工具类 -->
		<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.14</version>
        </dependency>
		<!--word模板数据解析-->
		<dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl</artifactId>
            <version>1.9.0-beta</version>
        </dependency>
		<!-- word/pdf操作 -->
		<dependency>
            <groupId>com.aspose</groupId>
            <artifactId>aspose-words</artifactId>
            <version>18.8</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.9</version>
        </dependency>

2. 模板放入项目

这里是放在项目里,也可以放在云上存储。

使用Java填充Word模板的操作指南

破解文件放入resouce,否则会有水印,aspose-words在maven仓库中也没有,需要下载后安装在本地仓库。

安装命令

mvn install:install-file -Dfile=路径/aspose-words-18.8.jar -DgroupId=com.aspose -DartifactId=aspose-words -Dversion=18.8 -Dpackaging=jar

引入破解文件

使用Java填充Word模板的操作指南

<License>
  <Data>
    <Products>
      <Product>Aspose.Total for Java</Product>
      <Product>Aspose.Words for Java</Product>
    </Products>
    <EditionType>Enterprise</EditionType>
    <SubscriptionExpiry>20991231</SubscriptionExpiry>
    <LicenseExpiry>20991231</LicenseExpiry>
    <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
  </Data>
  <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>
</License>

3.代码

实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class FillWordDTO implements Serializable {

    private String name;

    private String age;

    private String yuyan;

    private String yingyu;

    private String deyu;

    private String fayu;

    private String zhengshu;

    private String yiji;

    private String erji;

    private List<ExperienceList> experienceList;

    public static FillWordDTO create(){
        FillWordDTO fillWordDTO = new FillWordDTO();
        fillWordDTO.setName("小王");
        fillWordDTO.setAge("18");
        fillWordDTO.setYuyan("☑");
        fillWordDTO.setYingyu("☑");
        fillWordDTO.setDeyu("□");
        fillWordDTO.setFayu("☑");
        fillWordDTO.setZhengshu("☑");
        fillWordDTO.setYiji("☑");
        fillWordDTO.setErji("□");
        fillWordDTO.setExperienceList(China编程Arrays.asList(
                new ExperienceList("小王", "2020-01-01", "2020-01-01", "小王"),
                new ExperienceList("小王", "2020-01-01", "2020-01-01", "小王")
        ));
        return fillWordDTO;
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class ExperienceList {

    private String school;

    private String startTime;

    private String endTime;

    private String remark;
}

工具类

import com.aspose.words.*;
import com.aspose.words.net.System.Data.DataRow;
import com.aspose.words.net.System.Data.DataTable;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class ContractUtil {

	private ContractUtil() {
	}

	/**
	 * 调整bufferedimage大小
	 * @param source BufferedImage 原始image
	 * @param targetW inpythont  目标宽
	 * @param targetH int  目标高
	 * @param flag boolean 是否同比例调整
	 * @return BufferedImage  返回新image
	 */
	public static BufferedImage resizeBufferedImage(BufferedImage source, int targetW, int targetH, boolean flag) {
		int type = source.getType();
		BufferedImage target = null;
		double sx = (double) targetW / source.getWidth();
		double sy = (double) targetH / source.getHeight();
		if (flag && sx > sy) {
			sx = sy;
			targetW = (int) (sx * source.getWidth());
		} else if(flag && sx <= sy){
			sy = sx;
			targetH = (int) (sy * source.getHeight());
		}
		if (type == BufferedImage.TYPE_CUSTOM) { // handmade
			ColorModel cm = source.getColorModel();
			WritableRaster raster = cm.createCompatibleWritableRaster(targetW, targetH);
			boolean alphaPremultiplied = cm.isAlphaPremultiplied();
			target = new BufferedImage(cm, raster, alphaPremultiplied, null);
		} else {
			target = new BufferedImage(targetW, targetH, type);
		}
		Graphics2D g = target.createGraphics();
		g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
		g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
		g.dispose();
		return target;
	}


	/**
	 * 填充 word 模板(object数据格式)
	 *
	 * @param modelWordByte word模版二进制文件
	 * @param obj     要填充的数据
	 * @return 组合数据之后的word二进制
	 */
	public static byte[] fillWordDataByDomain(byte[] modelWordByte, Object obj) {
		try {
			Class<?> aClass = obj.getClass();
			Field[] fields = aClass.getDeclaredFields();
			Map<String, Object> data = new HashMap<>(fields.length);
			for (Field field : fields) {
				PropertyDescriptor pd = new PropertyDescriptor(field.getName(), aClass);
				Method method = pd.getReadMethod();
				String keandroidy = field.getName();
				Object value = method.invoke(obj);
				if (value != null) {
					data.put(key, value);
				}
			}
			return fillWordDataByMap(modelWordByte, data);
		} catch (Exception e) {
			e.printStackTrace();
			return new byte[0];
		}
	}


	/**
	 * 填充 word 模板(map数据格式)
	 *
	 * @param file word二进制
	 * @param data 要填充的数据
	 * @return 组合数据之后的word二进制
	 */
	public static byte[] fillWordDataByMap(byte[] file, Map<String, Object> data) throws Exception {
		byte[] ret = null;
		if (data == null || data.isEmpty()) {
			return ret;
		}

		try (InputStream is = new ByteArrayInputStream(file);
			 ByteArrayOutputStream out = new ByteArrayOutputStream()) {

			Document doc = new Document(is);
			DocumentBuilder builder = new DocumentBuilder(doc);
			Map<String, String> toData = new HashMap<>();

			for (Map.Entry<String, Object> entry : data.entrySet()) {

				String key = entry.getKey();
				Object value = entry.getValue();

				// 处理表格数据
				if (value instanceof List && !key.equals("checkboxOptions")) {
					DataTable dataTable = fillListData((List) value, key, builder);
					doc.getMailMerge().executeWithRegions(dataTable);
				}

				// 图片插入
				else if (value instanceof BufferedImage) {
					builder.moveToMergeField(key);
					builder.insertImage((BufferedImage) value);
				}

				// 其他普通字段正常填充
				else {
					String valueStr = String.valueOf(value);
					if (value != null && !"null".equals(valueStr)) {
						toData.put(key, valueStr);
					}
				}
			}

			// 执行普通字段合并
			String[] fieldNames = new String[toData.size()];
			String[] values = new String[toData.size()];
			int i = 0;
			for (Map.Entry<String, String> entry : toData.entrySet()) {
				fieldNames[i] = entry.getKey();
				values[i] = entry.getValue();
				i++;
			}

			doc.getMailMerge().execute(fieldNames, values);
			doc.save(out, SaveOptions.createSaveOptions(SaveFormat.DOCX));
			ret = out.toByteArray();
		}

		return ret;
	}

	/**
	 * 勾选段落中的复选框字段(适用于 Aspose.Words 18.8)
	 */
	private static void checkTheCheckbox(Paragraph paragraph) throws Exception {
		FieldCollection fields = paragraph.getRange().getFields();

		int count = fields.getCount();
		for (int i = 0; i < count; i++) {
			com.aspose.words.Field field = fields.get(i);
			if (field.getType() == FieldType.FIELD_FORM_CHECK_BOX) {
				// 设置字段结果为 "✓" 表示勾选(或根据模板实际显示字符调整)
				setCheckboxChecked(field, true);
			}
		}
	}

	private static void setCheckboxChecked(com.aspose.words.Field field, boolean checked) throws Exception {
		if (checked) {
			field.setResult("✓"); // 根据模板中实际勾选状态设置
		} else {
			field.setResult("□"); // 可选:取消勾选
		}
	}




	/**
	 * 封装 list 数据到 word 模板中(word表格)
	 *
	 * @param list      数据
	 * @param tableName 表格列表变量名称
	 * @return word表格数据DataTable
	 */
	private static DataTable fillListData(List<Object> list, Striandroidng tableName, DocumentBuilder builder) throws Exception {

		//创建DataTable,并绑定字段
		DataTable dataTable = new DataTable(tableName);
		for (Object obj : list) {
			//创建DataRow,封装该行数据
			DataRow dataRow = dataTable.newRow();
			Class<?> objClass = obj.getClass();
			Field[] fields = objClass.getDeclaredFields();
			for (int i = 0; i < fields.length; i++) {
				Field field = fields[i];
				dataTable.getColumns().add(fields[i].getName());
				PropertyDescriptor pd = new PropertyDescriptor(field.getName(), objClass);
				Method method = pd.getReadMethod();
				dataRow.set(i, method.invoke(obj));
			}
			dataTable.getRows().add(dataRow);
		}
		return dataTable;
	}

	//    private static License license = null;

	/**
	 * 加载 license
	 * 由于 aspose是收费的,若没有 license,则会出现水印。
	 */
    static {
        try {
            InputStream is = ContractUtil.class.getResourceAsStream("/License.XML");
			License license = new License();
            license.setLicense(is);
        } catch (Exception e) {
            throw new RuntimeException("自动加载aspose证书文件失败!");
        }
    }

}


三、测试

main方法测试,可以根据实际需求改为response输出或者上传到存储服务器后返回链接地址。

    public static void main(String[] args) throws IOException {

        FillWordDTO filpythonlWordDTO = FillWordDTO.create();
        // 读取模板文件
        byte[] modelByte = Files.readAllBytes(Paths.get("E:\\project\\spring-demo\\src\\main\\resources\\templates\\test.docx"));
        // 调用工具类,获取填充数据后的文件
        byte[] resultByte = ContractUtil.fillWordDataByDomain(modelByte, fillWordDTO);

        // 处理该二进制文件,此处处理为输出到桌面
        File resultFile = new File("C:\\Users\\Lenovo\\Desktop\\demo.docx");
        FileOutputStream fos = new FileOutputStream(resultFile);
        fos.write(resultByte);
        fos.close();
    }

四、运行结果

使用Java填充Word模板的操作指南

五、注意事项

在编辑word域代码时,有时会有隐藏的代码导致填充失败

Found end of mail merge region 'experienceList' that does not match start of mail merge region 'jlList'.

出现以上错误或者想查看域代码,按如下操作

在word中依次点击「文件→选项→高级」,在「显示文档内容」区域勾选「显示域代码而非域值」,找到报错域代码后删除,重新添加域就解决了。

以上就是使用Java填充Word模板的操作指南的详细内容,更多关于Java填充Word模板的资料请关注编程China编程(www.chinasem.cn)其它相关文章!

这篇关于使用Java填充Word模板的操作指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1156072

相关文章

Java8 Collectors.toMap() 的两种用法

《Java8Collectors.toMap()的两种用法》Collectors.toMap():JDK8中提供,用于将Stream流转换为Map,本文给大家介绍Java8Collector... 目录一、简单介绍用法1:根据某一属性,对对象的实例或属性做映射用法2:根据某一属性,对对象集合进行去重二、Du

java中ssh2执行多条命令的四种方法

《java中ssh2执行多条命令的四种方法》本文主要介绍了java中ssh2执行多条命令的四种方法,包括分号分隔、管道分隔、EOF块、脚本调用,可确保环境配置生效,提升操作效率,具有一定的参考价值,感... 目录1 使用分号隔开2 使用管道符号隔开3 使用写EOF的方式4 使用脚本的方式大家平时有没有遇到自

linux系统中java的cacerts的优先级详解

《linux系统中java的cacerts的优先级详解》文章讲解了Java信任库(cacerts)的优先级与管理方式,指出JDK自带的cacerts默认优先级更高,系统级cacerts需手动同步或显式... 目录Java 默认使用哪个?如何检查当前使用的信任库?简要了解Java的信任库总结了解 Java 信

Spring Boot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)

《SpringBoot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)》本文将以一个实际案例(用户管理系统)为例,详细解析SpringBoot中Co... 目录引言:为什么学习Spring Boot分层架构?第一部分:Spring Boot的整体架构1.1

使用EasyPoi快速导出Word文档功能的实现步骤

《使用EasyPoi快速导出Word文档功能的实现步骤》EasyPoi是一个基于ApachePOI的开源Java工具库,旨在简化Excel和Word文档的操作,本文将详细介绍如何使用EasyPoi快速... 目录一、准备工作1、引入依赖二、准备好一个word模版文件三、编写导出方法的工具类四、在Export

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

java程序远程debug原理与配置全过程

《java程序远程debug原理与配置全过程》文章介绍了Java远程调试的JPDA体系,包含JVMTI监控JVM、JDWP传输调试命令、JDI提供调试接口,通过-Xdebug、-Xrunjdwp参数配... 目录背景组成模块间联系IBM对三个模块的详细介绍编程使用总结背景日常工作中,每个程序员都会遇到bu

MySQL之搜索引擎使用解读

《MySQL之搜索引擎使用解读》MySQL存储引擎是数据存储和管理的核心组件,不同引擎(如InnoDB、MyISAM)采用不同机制,InnoDB支持事务与行锁,适合高并发场景;MyISAM不支持事务,... 目录mysql的存储引擎是什么MySQL存储引擎的功能MySQL的存储引擎的分类查看存储引擎1.命令

Python sys模块的使用及说明

《Pythonsys模块的使用及说明》Pythonsys模块是核心工具,用于解释器交互与运行时控制,涵盖命令行参数处理、路径修改、强制退出、I/O重定向、系统信息获取等功能,适用于脚本开发与调试,需... 目录python sys 模块详解常用功能与代码示例获取命令行参数修改模块搜索路径强制退出程序标准输入

Java服务实现开启Debug远程调试

《Java服务实现开启Debug远程调试》文章介绍如何通过JVM参数开启Java服务远程调试,便于在线上排查问题,在IDEA中配置客户端连接,实现无需频繁部署的调试,提升效率... 目录一、背景二、相关图示说明三、具体操作步骤1、服务端配置2、客户端配置总结一、背景日常项目中,通常我们的代码都是部署到远程