开发者

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

目录
  • 前言
  • 一、设置word模板
    • 普通字段
    • 列表字段
    • 复选框
  • 二、代码
    • 1. 引入POM
    • 2. 模板放入项目
    • 3.代码
      • 实体类
      • 工具类
  • 三、测试
    • 四、运行结果
      • 五、注意事项

        前言

        最近有个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(编程客栈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模板的资料请关注编程客栈(www.devze.com)其它相关文章!

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜