Java根據Freemarker模板生成Word檔案

1。 準備模板

模板 + 資料 = 模型

1、將準備好的Word模板檔案另存為。xml檔案(PS:建議使用WPS來建立Word檔案,不建議用Office)

Java根據Freemarker模板生成Word檔案

Java根據Freemarker模板生成Word檔案

2、將。xml檔案重新命名為。ftl檔案

Java根據Freemarker模板生成Word檔案

3、用文字編輯器開啟。ftl檔案,將內容複製出來,格式化一下,再覆蓋原來的內容

(PS:格式化一下是為了方便查詢並設定變數/佔位符,當然設定好模板引數變數以後可以再壓縮後再寫會。ftl檔案)

另外,強烈不建議在word檔案中去編輯設定模板變數,因為。docx檔案在另存為。xml檔案後,原先好好的一個變數可能就被拆開了,建議另存為之後再用文字編輯器開啟去編輯。

Java根據Freemarker模板生成Word檔案

4、設定模板引數(變數/佔位符)

Java根據Freemarker模板生成Word檔案

2。 程式碼實現

pom。xml

<?xml version=“1。0” encoding=“UTF-8”?> 4。0。0 org。springframework。boot spring-boot-starter-parent 2。7。3 <!—— lookup parent from repository ——> com。example demo920 0。0。1-SNAPSHOT demo920 demo920 1。8 org。springframework。boot spring-boot-starter-freemarker org。springframework。boot spring-boot-starter-web cn。hutool hutool-core 5。8。7 com。itextpdf itextpdf 5。5。13。3 <!—— com。aspose aspose-words 22。9 jdk17 ——> org。projectlombok lombok true org。springframework。boot spring-boot-starter-test test org。springframework。boot spring-boot-maven-plugin org。projectlombok lombok

寫個類測試一下

package com。example。demo920;import com。example。demo920。domain。LoanReceipt;import freemarker。template。Configuration;import freemarker。template。Template;import org。junit。jupiter。api。Test;import org。springframework。boot。test。context。SpringBootTest;import java。io。BufferedWriter;import java。io。File;import java。io。FileOutputStream;import java。io。OutputStreamWriter;import java。math。BigDecimal;import java。nio。file。Path;import java。nio。file。Paths;import java。time。LocalDateTime;import java。time。format。DateTimeFormatter;import java。util。HashMap;import java。util。Locale;import java。util。Map;@SpringBootTestclass Demo920ApplicationTests { private DateTimeFormatter DTF = DateTimeFormatter。ofPattern(“yyyyMMddHHmmss”, Locale。CHINA); @Test void contextLoads() { } @Test void testGenerateWord() throws Exception { Configuration configuration = new Configuration(Configuration。VERSION_2_3_31); configuration。setDefaultEncoding(“UTF-8”); configuration。setClassForTemplateLoading(this。getClass(), “/templates”); Template template = configuration。getTemplate(“借條。ftl”); Path path = Paths。get(“tmp”,“contract”); File fileDir = path。toFile(); if (!fileDir。exists()) { fileDir。mkdirs(); } String filename = “借條” + “_” + LocalDateTime。now()。format(DTF) + “。docx”; filename = path。toFile() + File。separator + filename; BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename)));// template。process(getDataMap(), writer); template。process(getData(), writer); writer。flush(); writer。close(); } Map getDataMap() { Map dataMap = new HashMap<>(); dataMap。put(“borrowerName”, “李白”); dataMap。put(“borrowerIdCard”, “421302199001012426”); dataMap。put(“lenderName”, “杜甫”); dataMap。put(“amount”, 100); dataMap。put(“amountInWords”, “壹佰”); dataMap。put(“startDate”, “2022年8月15日”); dataMap。put(“endDate”, “2022年11月11日”); dataMap。put(“borrowingMonths”, 3); dataMap。put(“interestRate”, “1。23”); dataMap。put(“guarantorName”, “白居易”); dataMap。put(“guarantorIdCard”, “421302199203152412”); return dataMap; } LoanReceipt getData() { LoanReceipt receipt = new LoanReceipt(); receipt。setBorrowerName(“狄仁傑”); receipt。setBorrowerIdCard(“421302198710121234”); receipt。setBorrowingMonths(6); receipt。setLenderName(“李元芳”); receipt。setAmount(new BigDecimal(“101”)); receipt。setAmountInWords(“壹佰零壹”); receipt。setInterestRate(new BigDecimal(“0。6”)); receipt。setStartDate(“2022年1月1日”); receipt。setEndDate(“2022年6月30日”); receipt。setGuarantorName(“武則天”); receipt。setGuarantorIdCard(“421302199101014567”); return receipt; }}

最主要的是下面兩行

// 載入模板Template template = configuration。getTemplate(“借條。ftl”);// 填充資料template。process(getData(), writer);

資料可以是Map也可以是一個物件

改進一下,將生成檔案的操作單獨寫成一個工具方法

package com。example。demo920。util;import cn。hutool。core。io。IoUtil;import freemarker。template。Configuration;import freemarker。template。Template;import freemarker。template。TemplateException;import java。io。*;public class FreemarkerUtils { /** * 生成Word * @param templateDir 模板所在的目錄 * @param templateName 模板檔名稱 * @param filename 生成的檔案(含路徑) * @param dataModel 模板引數資料 */ public static void generateWord(File templateDir, String templateName, String filename, Object dataModel) { BufferedWriter writer = null; Configuration configuration = new Configuration(Configuration。VERSION_2_3_31); configuration。setDefaultEncoding(“UTF-8”); try { configuration。setDirectoryForTemplateLoading(templateDir); Template template = configuration。getTemplate(templateName); writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename))); template。process(dataModel, writer); writer。flush(); } catch (IOException e) { throw new RuntimeException(e); } catch (TemplateException e) { throw new RuntimeException(e); } finally { IoUtil。close(writer); } }}

再測試一下

package com。example。demo920;import cn。hutool。core。io。IoUtil;import com。example。demo920。util。FreemarkerUtils;import com。example。demo920。util。PdfUtils;import org。junit。jupiter。api。Test;import org。springframework。util。ResourceUtils;import java。io。*;import java。nio。file。Files;import java。nio。file。Path;import java。nio。file。Paths;import java。time。LocalDateTime;import java。util。HashMap;import java。util。Map;public class WordTest { /** * 1、從檔案伺服器下載模板檔案 * 2、根據業務型別獲取需要填充模板的資料 * 3、模板+資料 再經過處理生成新的檔案 * 4、將生成後的檔案上傳到檔案伺服器,並返回一個檔案ID * 5、業務可以儲存這個檔案ID或者檔案的路徑 */ @Test void testGenerateWordV1() throws Exception { Path tempPath = Paths。get(“tmp”, “contract2”); File path = tempPath。toFile(); if (!path。exists()) { path。mkdirs(); } File tempFile = Files。createTempFile(tempPath, “qiantiao”, “。docx”)。toFile(); System。out。println(tempFile。getParent()); System。out。println(tempFile。getName()); FileOutputStream fos = new FileOutputStream(tempFile); File templateFile = ResourceUtils。getFile(“classpath:templates/借條。ftl”); FileInputStream fis = new FileInputStream(templateFile); IoUtil。copy(fis, fos); String filename = “借條” + “_” + System。currentTimeMillis() + “。docx”; filename = “tmp/contract” + File。separator + filename; FreemarkerUtils。generateWord(new File(tempFile。getParent()), tempFile。getName(), filename, getDataMap()); } /** * 獲取資料 */ Map getDataMap() { Map dataMap = new HashMap<>(); dataMap。put(“borrowerName”, “李白2”); dataMap。put(“borrowerIdCard”, “421302199001012426”); dataMap。put(“lenderName”, “杜甫”); dataMap。put(“amount”, 100); dataMap。put(“amountInWords”, “壹佰”); dataMap。put(“startDate”, “2022年8月15日”); dataMap。put(“endDate”, “2022年11月11日”); dataMap。put(“borrowingMonths”, 3); dataMap。put(“interestRate”, “1。23”); dataMap。put(“guarantorName”, “白居易”); dataMap。put(“guarantorIdCard”, “421302199203152412”); return dataMap; } @Test void testGenerateWord2() throws Exception { File templateDir = ResourceUtils。getFile(ResourceUtils。CLASSPATH_URL_PREFIX + “templates”); String templateName = “借條。ftl”; String destFilename = “借條” + System。currentTimeMillis() + “。docx”; Map data = getDataMap(); FreemarkerUtils。generateWord(templateDir, templateName, destFilename, data); }}

Java根據Freemarker模板生成Word檔案

3。 PDF檔案加水印

有時候,生成或者從伺服器下載的檔案是需要加水印的,比如標識這個檔案是誰下載的之類的

pdf加水印還是比較方便的,用itext元件可以輕鬆實現

另外,如果最終需要pdf檔案,建議直接生成pdf檔案,跳過word轉pdf的步驟

package com。example。demo920。util;import cn。hutool。core。io。IoUtil;import com。aspose。words。Document;import com。aspose。words。SaveFormat;import com。itextpdf。text。BaseColor;import com。itextpdf。text。DocumentException;import com。itextpdf。text。Element;import com。itextpdf。text。Image;import com。itextpdf。text。pdf。*;import java。io。File;import java。io。FileInputStream;import java。io。FileOutputStream;import java。io。IOException;import java。time。LocalDateTime;/** * @author chengjiansheng * @date 2022/09/21 */public class PdfUtils { /** * Word轉PDF * https://www。aspose。com/ * 注意:Aspose。Words 這個元件是收費的,如果購買的話生成的PDF會有水印。 * 可以去找相應的破解版本,但是我感覺完全可以跳過Word直接生成PDF。 * 比如,可以透過Freemarker直接生成PDF,或者利用iText透過模板生成PDF * @param src * @param dest */ public static void wordToPdf(String src, String dest) { File file = new File(src); if (!file。exists()) { throw new RuntimeException(“檔案不存在”); } FileInputStream fis = null; try { fis = new FileInputStream(file); Document wpd = new Document(fis); wpd。save(dest, SaveFormat。PDF); } catch (Exception e) { throw new RuntimeException(e); } finally { IoUtil。close(fis); } } /** * 加水印 * @param src 原始檔 * @param dest 目標檔案 * @param text 文字 * @param imagePath 圖片地址 */ public static void addWatermark(String src, String dest, String text, String imagePath) { try { // 待加水印的檔案 PdfReader reader = new PdfReader(src); // 加完水印的檔案 PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); // 字型 BaseFont baseFont = BaseFont。createFont(“STSong-Light”, “UniGB-UCS2-H”, BaseFont。NOT_EMBEDDED); // 透明度 PdfGState gs = new PdfGState(); gs。setFillOpacity(0。4f); // PDF檔案總頁數 int total = reader。getNumberOfPages() + 1; // 迴圈對每一頁都加水印 PdfContentByte content; for (int i = 1; i < total; i++) { // 水印在文字之上 content = stamper。getOverContent(i); content。setGState(gs); if (null != imagePath) { Image image = Image。getInstance(imagePath);// image。setAbsolutePosition(150, 150);// image。scaleToFit(300,300);// content。addImage(image); for (int x = 0; x < 700; x = x + 300) { for (int y = 0; y < 900; y = y + 200) { image。setAbsolutePosition(x+50, y+50); image。scaleToFit(100,100); content。addImage(image); } } } if (null != text) { content。beginText(); content。setColorFill(BaseColor。RED); content。setFontAndSize(baseFont, 20);// content。showTextAligned(Element。ALIGN_CENTER, text, 50, 50, 45); for (int x = 0; x < 700; x = x + 300) { for (int y = 0; y < 900; y = y + 200) { //水印內容和水印位置 content。showTextAligned(Element。ALIGN_CENTER, “哈哈哈哈哈”, x - 20, y + 10, 30); content。showTextAligned(Element。ALIGN_CENTER, LocalDateTime。now()。toString(), x, y, 30); } } content。endText(); } } stamper。close(); reader。close(); } catch (IOException e) { throw new RuntimeException(e); } catch (DocumentException e) { throw new RuntimeException(e); } }}

跑一下

@Testvoid testWatermark() { String src2 = “D:\\借條_2。pdf”; String dest2 = “D:\\借條_3。pdf”; String imagePath = “D:\\1。jpg”; PdfUtils。addWatermark(src2, dest2, “哈哈哈哈哈”, imagePath);}

加完水印後效果如圖

Java根據Freemarker模板生成Word檔案

最後,示例專案結構如圖

Java根據Freemarker模板生成Word檔案

原文連結:https://www。cnblogs。com/cjsblog/p/16715294。html?utm_source=tuicool&utm_medium=referral