本文主要是介绍使用Java填充Word模板的操作指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《使用Java填充Word模板的操作指南》本文介绍了Java填充Word模板的实现方法,包括文本、列表和复选框的填充,首先通过Word域功能设置模板变量,然后使用poi-tl、aspose-words...
前言
最近有个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(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(); }
四、运行结果
五、注意事项
在编辑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模板的操作指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!