最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2025年09月28日 10:32:43   作者:小碼氓  
本文介紹了Java填充Word模板的實(shí)現(xiàn)方法,包括文本、列表和復(fù)選框的填充,首先通過(guò)Word域功能設(shè)置模板變量,然后使用poi-tl、aspose-words等工具類(lèi)進(jìn)行數(shù)據(jù)處理,提供了完整的代碼實(shí)現(xiàn),需要的朋友可以參考下

前言

最近有個(gè)Java填充Word模板的需求,包括文本,列表和復(fù)選框勾選,寫(xiě)一個(gè)工具類(lèi),以此記錄。

提示:以下是本篇文章正文內(nèi)容,下面案例可供參考

一、設(shè)置word模板

選擇文檔中要填充的地方點(diǎn)擊->選擇插入->文檔部件->域->域名(mergeFeild)->填寫(xiě)變量名稱(chēng).

普通字段

填充完畢:

列表字段

操作和普通字段一樣,區(qū)別是需要在首行第一列插入列表開(kāi)始域,首行最后一列插入結(jié)束域,中間正常字段。格式為:StartTable:<數(shù)組字段名>,EndTable:<數(shù)組字段名>

復(fù)選框

復(fù)選框找了好多種方法嘗試沒(méi)有成功,最后取巧,和普通字段一樣設(shè)置占位符,通過(guò)代碼邏輯處理.

二、代碼

1. 引入POM

poi/hutool/aspose-words/gson:

	<!-- hutool工具類(lèi) -->
		<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.14</version>
        </dependency>
		<!--word模板數(shù)據(jù)解析-->
		<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. 模板放入項(xiàng)目

這里是放在項(xiàng)目里,也可以放在云上存儲(chǔ)。

破解文件放入resouce,否則會(huì)有水印,aspose-words在maven倉(cāng)庫(kù)中也沒(méi)有,需要下載后安裝在本地倉(cāng)庫(kù)。

安裝命令

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.代碼

實(shí)體類(lèi)

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;
}

工具類(lèi)

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() {
	}

	/**
	 * 調(diào)整bufferedimage大小
	 * @param source BufferedImage 原始image
	 * @param targetW int  目標(biāo)寬
	 * @param targetH int  目標(biāo)高
	 * @param flag boolean 是否同比例調(diào)整
	 * @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數(shù)據(jù)格式)
	 *
	 * @param modelWordByte word模版二進(jìn)制文件
	 * @param obj     要填充的數(shù)據(jù)
	 * @return 組合數(shù)據(jù)之后的word二進(jìn)制
	 */
	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數(shù)據(jù)格式)
	 *
	 * @param file word二進(jìn)制
	 * @param data 要填充的數(shù)據(jù)
	 * @return 組合數(shù)據(jù)之后的word二進(jìn)制
	 */
	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();

				// 處理表格數(shù)據(jù)
				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);
					}
				}
			}

			// 執(zhí)行普通字段合并
			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;
	}

	/**
	 * 勾選段落中的復(fù)選框字段(適用于 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) {
				// 設(shè)置字段結(jié)果為 "?" 表示勾選(或根據(jù)模板實(shí)際顯示字符調(diào)整)
				setCheckboxChecked(field, true);
			}
		}
	}

	private static void setCheckboxChecked(com.aspose.words.Field field, boolean checked) throws Exception {
		if (checked) {
			field.setResult("?"); // 根據(jù)模板中實(shí)際勾選狀態(tài)設(shè)置
		} else {
			field.setResult("□"); // 可選:取消勾選
		}
	}




	/**
	 * 封裝 list 數(shù)據(jù)到 word 模板中(word表格)
	 *
	 * @param list      數(shù)據(jù)
	 * @param tableName 表格列表變量名稱(chēng)
	 * @return word表格數(shù)據(jù)DataTable
	 */
	private static DataTable fillListData(List<Object> list, String tableName, DocumentBuilder builder) throws Exception {

		//創(chuàng)建DataTable,并綁定字段
		DataTable dataTable = new DataTable(tableName);
		for (Object obj : list) {
			//創(chuàng)建DataRow,封裝該行數(shù)據(jù)
			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是收費(fèi)的,若沒(méi)有 license,則會(huì)出現(xiàn)水印。
	 */
    static {
        try {
            InputStream is = ContractUtil.class.getResourceAsStream("/License.xml");
			License license = new License();
            license.setLicense(is);
        } catch (Exception e) {
            throw new RuntimeException("自動(dòng)加載aspose證書(shū)文件失敗!");
        }
    }

}


三、測(cè)試

main方法測(cè)試,可以根據(jù)實(shí)際需求改為response輸出或者上傳到存儲(chǔ)服務(wù)器后返回鏈接地址。

    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"));
        // 調(diào)用工具類(lèi),獲取填充數(shù)據(jù)后的文件
        byte[] resultByte = ContractUtil.fillWordDataByDomain(modelByte, fillWordDTO);

        // 處理該二進(jìn)制文件,此處處理為輸出到桌面
        File resultFile = new File("C:\\Users\\Lenovo\\Desktop\\demo.docx");
        FileOutputStream fos = new FileOutputStream(resultFile);
        fos.write(resultByte);
        fos.close();
    }

四、運(yùn)行結(jié)果

五、注意事項(xiàng)

在編輯word域代碼時(shí),有時(shí)會(huì)有隱藏的代碼導(dǎo)致填充失敗

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

出現(xiàn)以上錯(cuò)誤或者想查看域代碼,按如下操作

在word中依次點(diǎn)擊「文件→選項(xiàng)→高級(jí)」,在「顯示文檔內(nèi)容」區(qū)域勾選「顯示域代碼而非域值」,找到報(bào)錯(cuò)域代碼后刪除,重新添加域就解決了。

以上就是使用Java填充Word模板的操作指南的詳細(xì)內(nèi)容,更多關(guān)于Java填充Word模板的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 手?jǐn)]一個(gè)Spring?Boot?Starter并上傳到Maven中央倉(cāng)庫(kù)

    手?jǐn)]一個(gè)Spring?Boot?Starter并上傳到Maven中央倉(cāng)庫(kù)

    本文主要介紹了手?jǐn)]一個(gè)Spring?Boot?Starter并上傳到Maven中央倉(cāng)庫(kù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • 簡(jiǎn)述IDEA集成Git在實(shí)際項(xiàng)目中的運(yùn)用

    簡(jiǎn)述IDEA集成Git在實(shí)際項(xiàng)目中的運(yùn)用

    這篇文章主要介紹了IDEA集成Git在實(shí)際項(xiàng)目中的運(yùn)用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • 完全解析Java編程中finally語(yǔ)句的執(zhí)行原理

    完全解析Java編程中finally語(yǔ)句的執(zhí)行原理

    這篇文章主要深度介紹了Java編程中finally語(yǔ)句的執(zhí)行原理,細(xì)致講解了finally在異常處理中的流程控制作用,需要的朋友可以參考下
    2015-11-11
  • 解決接口調(diào)用報(bào)錯(cuò)newSocketStream(..)failed:Too?many?open?files問(wèn)題

    解決接口調(diào)用報(bào)錯(cuò)newSocketStream(..)failed:Too?many?open?files問(wèn)題

    這篇文章主要介紹了解決接口調(diào)用報(bào)錯(cuò)newSocketStream(..)failed:Too?many?open?files問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 最全LocalDateTime、LocalDate、Date、String相互轉(zhuǎn)化的方法

    最全LocalDateTime、LocalDate、Date、String相互轉(zhuǎn)化的方法

    大家在開(kāi)發(fā)過(guò)程中必不可少的和日期打交道,對(duì)接別的系統(tǒng)時(shí),時(shí)間日期格式不一致,每次都要轉(zhuǎn)化,本文為大家準(zhǔn)備了最全的LocalDateTime、LocalDate、Date、String相互轉(zhuǎn)化方法,需要的可以參考一下
    2023-06-06
  • Hibernate基于ThreadLocal管理Session過(guò)程解析

    Hibernate基于ThreadLocal管理Session過(guò)程解析

    這篇文章主要介紹了Hibernate基于ThreadLocal管理Session過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Maven打包后找不到class文件的問(wèn)題

    Maven打包后找不到class文件的問(wèn)題

    本文主要介紹了Maven打包后找不到class文件的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Java實(shí)現(xiàn)Markdown圖片批量本地化處理工具

    Java實(shí)現(xiàn)Markdown圖片批量本地化處理工具

    在日常使用Markdown時(shí),我們常通過(guò)遠(yuǎn)程URL引用圖片,所以本文小編就為大家詳細(xì)介紹一下如何使用Java實(shí)現(xiàn)Markdown圖片批量本地化處理吧
    2025-07-07
  • SpringBoot3利用AOP實(shí)現(xiàn)IP黑名單功能

    SpringBoot3利用AOP實(shí)現(xiàn)IP黑名單功能

    在Web應(yīng)用開(kāi)發(fā)中,控制對(duì)特定IP地址的訪(fǎng)問(wèn)權(quán)限是一個(gè)常見(jiàn)的需求,通過(guò)實(shí)現(xiàn)IP黑白名單功能,我們可以允許某些IP地址訪(fǎng)問(wèn)應(yīng)用,同時(shí)拒絕其他IP地址的訪(fǎng)問(wèn),本文將詳細(xì)介紹SpringBoot3利用AOP實(shí)現(xiàn)IP黑名單功能,并附上相應(yīng)的代碼片段,需要的朋友可以參考下
    2024-09-09
  • Serializable接口的作用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Serializable接口的作用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了java中Serializable接口的作用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05

最新評(píng)論

齐齐哈尔市| 隆昌县| 喀喇| 阿鲁科尔沁旗| 聊城市| 乌拉特中旗| 许昌县| 石台县| 黄平县| 宜兰县| 青岛市| 乡城县| 炎陵县| 福泉市| 宣化县| 正阳县| 微山县| 肃宁县| 达孜县| 武威市| 肃南| 庆云县| 永兴县| 延津县| 扎兰屯市| 长白| 临桂县| 自贡市| 厦门市| 冀州市| 湘潭县| 海晏县| 南江县| 金山区| 邢台市| 资阳市| 嵊州市| 金乡县| 沭阳县| 罗江县| 乐山市|