当前位置: 代码网 > it编程>编程语言>Java > 使用Java填充Word模板的操作指南

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

2025年09月28日 Java 我要评论
前言最近有个java填充word模板的需求,包括文本,列表和复选框勾选,写一个工具类,以此记录。提示:以下是本篇文章正文内容,下面案例可供参考一、设置word模板选择文档中要填充的地方点击->选

前言

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

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

一、设置word模板

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

普通字段

填充完毕:

列表字段

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

复选框

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

二、代码

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. 模板放入项目

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

破解文件放入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

引入破解文件

<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(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 int  目标宽
	 * @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 key = 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, string 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 fillworddto = 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();
    }

四、运行结果

五、注意事项

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

found end of mail merge region 'experiencelist' that does not match start of mail merge region 'jllist'.

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

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

以上就是使用java填充word模板的操作指南的详细内容,更多关于java填充word模板的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com