前言
最近有个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模板的资料请关注代码网其它相关文章!
发表评论