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

Java通過freemarker生成Word文檔導(dǎo)出的方式詳解

 更新時(shí)間:2025年03月04日 10:48:40   作者:Dawn  
本文詳細(xì)介紹了如何使用FreeMarker模板生成Word文檔,包括制作FTL模板、在Java中使用FreeMarker生成文檔以及處理動(dòng)態(tài)數(shù)據(jù)和合并單元格等內(nèi)容,需要的朋友可以參考下

1.制作ftl模板

在Word中制作模板,制作完后以XML格式導(dǎo)出

 新建WORD文件,將所需參數(shù)用特殊符號(hào) ${} 配置,如下圖:

注意:freemarker中的占位符是${},例如:這里使用的是【${name}】的形式,那么傳遞的數(shù)據(jù)中就需要有一個(gè)叫做【name】的字段。

導(dǎo)出時(shí)選擇.xml格式導(dǎo)出

用編譯器(notepad++)打開看一下動(dòng)態(tài)參數(shù)是否正確,并修改后綴名為ftl

導(dǎo)出XML文件之后,打開這個(gè)文件,此時(shí)你會(huì)看到里面都是XML標(biāo)簽,首先格式化一下,這樣看起來會(huì)舒服些,可以檢查一下你的占位符內(nèi)容是否滿足freemarker語法。因?yàn)橛行r(shí)候,我們導(dǎo)出的XML文件中,可能會(huì)將【${xxx}】分隔成兩行,從而導(dǎo)致占位符失效,所以有時(shí)候需要手動(dòng)修改一下占位符。導(dǎo)出的Word XML文件內(nèi)容大致如下所示:

2.pom文件引入freemarke依賴,安裝依賴

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>

3.java代碼實(shí)現(xiàn)

3.1 將ftl模板移入項(xiàng)目中

3.2  創(chuàng)建Freemarker工具類

引入freemarker依賴之后,就可以使用Freemarker編寫一個(gè)工具類,專門用于處理文件的導(dǎo)出和數(shù)據(jù)渲染。

import freemarker.template.Configuration;
import freemarker.template.Template;
 
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Map;
 
/**
 * @version 1.0.0
 * @Date: 2025/2/14 15:05
 * @Author SYG
 * @Description: Freemarker 工具類
 */
public class FreemarkerUtil {
 
    /**
     * 使用 Freemarker 生成 Word 文件并導(dǎo)出
     * @param templateName 模板文件路徑名稱
     * @param fileName 生成的文件路徑以及名稱
     * @param dataModel 填充的數(shù)據(jù)對(duì)象
     * @param response HttpServletResponse 對(duì)象
     */
    public static void exportWord(String templateName, String fileName, Map<String, Object> dataModel, Object obj, HttpServletResponse response) {
        generateFile(templateName, fileName, dataModel, obj, response);
    }
 
    /**
     * 使用 Freemarker 生成指定文件并導(dǎo)出
     * @param templateName 模板文件路徑名稱
     * @param fileName 生成的文件路徑以及名稱
     * @param dataModel 填充的數(shù)據(jù)對(duì)象
     * @param obj 基準(zhǔn)類對(duì)象
     * @param response HttpServletResponse 對(duì)象
     */
    private static void generateFile(String templateName, String fileName, Map<String, Object> dataModel, Object obj, HttpServletResponse response) {
        try {
            // 1、創(chuàng)建配置對(duì)象
            Configuration config = new Configuration(Configuration.VERSION_2_3_30);
            config.setDefaultEncoding("utf-8");
            //設(shè)置了模板文件的加載類和路徑,使得Freemarker可以從指定的類路徑下的/templates目錄中加載模板文件。
            config.setClassForTemplateLoading(obj.getClass(), "/templates");
            // 2、獲取模板文件
            Template template = config.getTemplate(templateName);
            // 3、設(shè)置響應(yīng)頭
            response.setContentType("application/msword");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            // 4、創(chuàng)建寫入器
            Writer writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8));
            // 5、渲染模板文件
            template.process(dataModel, writer);
            // 6、關(guān)閉寫入器
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}

3.3 測(cè)試案例代碼

 
public class ExportWordDemo {
    public static void main(String[] args) {
        String templateName = "opinionCollect.ftl";
        String fileName = "opinionCollect.docx";
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("orgName", "測(cè)試機(jī)構(gòu)02141151");
        dataModel.put("data", "2025-02-14");
        // 執(zhí)行導(dǎo)出
        FreemarkerUtil.exportWord(templateName, fileName, dataModel,this,response);
    }
}

案例所使用的ftl文件共有兩個(gè)變量data和orgName,若map集合里只給data或orgName一個(gè)變量賦值(例如我們只給data賦值        

dataModel.put("data", "2025-02-14");
),則會(huì)報(bào)錯(cuò):

FreeMarker template error:
The following has evaluated to null or missing:

==> orgName [in template "payment.ftl" at line 3, column 23752]

為解決當(dāng)前異常,這里有倆種方案:

  • 給orgName賦一個(gè)空值,即dataModel.put("orgName", ""); 
  • (推薦)修改模板,根據(jù)數(shù)據(jù)結(jié)構(gòu)字段,將需要填充數(shù)據(jù)的地方,修改為EL表達(dá)式。${()!} 加括號(hào)!號(hào)表示可以為null ,也可以解決上述問題,如圖所示:

3.4 解析

config.setClassForTemplateLoading(obj.getClass(), "/templates"); 中的第一個(gè)參數(shù) obj.getClass() 是用于指定模板加載的基準(zhǔn)類。具體作用如下:

確定類路徑:FreeMarker 根據(jù)傳入的類來確定模板文件所在的類路徑。這里使用 obj.getClass() 表示以 obj 所屬類的類路徑為基準(zhǔn)。加載模板資源:FreeMarker 會(huì)從該類所在的類路徑下查找并加載模板文件,路徑為 /templates。

簡(jiǎn)而言之,第一個(gè)參數(shù)決定了 FreeMarker 在哪里查找模板文件。

此處ftl文件和OpinionCollectController是在同一個(gè)工程目錄下,同一個(gè)target目錄下,所以可以直接傳OpinionCollectController的對(duì)象本身,如果ftl文件和FreemarkerUtil工具類在同一個(gè)工程目錄下,我們也可以將config.setClassForTemplateLoading(obj.getClass(), "/templates");改成config.setClassForTemplateLoading(FreemarkerUtil.class, "/templates");

3.5  運(yùn)行代碼

運(yùn)行測(cè)試案例的代碼,可以看到文件正常導(dǎo)出,且變量已經(jīng)被替換

4.使用模板導(dǎo)出word勾選框

實(shí)際業(yè)務(wù)需求需要根據(jù)業(yè)務(wù)勾選上對(duì)應(yīng)的項(xiàng)目類型,同時(shí)導(dǎo)出的文件需要有點(diǎn)擊方框自動(dòng)勾選的功能,我們可以先在word模板里實(shí)現(xiàn)該功能,然后導(dǎo)出成xml格式的文件

打開xml文件,為了方便查看,我們需要安裝XMLTools的插件

安裝完插件之后,我們可以通過notepad查看xml文件

如圖所示,找到方框的位置,將方框替換為變量

添加代碼對(duì)test1和test2進(jìn)行賦值

public class ExportWordDemo {
    public static void main(String[] args) {
        String templateName = "opinionCollect.ftl";
        String fileName = "opinionCollect.docx";
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("orgName", "測(cè)試機(jī)構(gòu)02141151");
        dataModel.put("data", "2025-02-14");
        //? □
        dataModel.put("test1", "□");
        dataModel.put("test2", "?");
        
        // 執(zhí)行導(dǎo)出
        FreemarkerUtil.exportWord(templateName, fileName, dataModel,this,response);
    }
}

執(zhí)行代碼我們可以看到導(dǎo)出的文件如下圖,同時(shí)方框也可以點(diǎn)擊勾選或取消勾選

5.生成動(dòng)態(tài)列表格

模板如下圖所示,具體業(yè)務(wù)需求如下:

1、一個(gè)任務(wù)編號(hào)下綁定的有多個(gè)直屬單位

2、每個(gè)直屬單位下需要匯總供應(yīng)商管理部門、質(zhì)量部門、技術(shù)部門、檢測(cè)部門、其他相關(guān)意見的審核意見

5.1 list標(biāo)簽

//whyc 是集合(collection)的表達(dá)式,yc是循環(huán)變量的名字,不能是表達(dá)式
<#list whyc as yc>
 需要循環(huán)的部分 變量用${(yc.supplierReasonDesc)!}
</#list>

首先修改ftl文件,找到我們需要循環(huán)的部門,進(jìn)行添加<#list></#list>標(biāo)簽

此處我們要循環(huán)的是companyName及其其對(duì)應(yīng)的征求部門的意見,我們?cè)趂tl文件找到“備注”這一行結(jié)束的位置,${companyName}這一行開始的位置,添加 <#list whyc as yc>

如下圖所示:

注意: list一定要放在要循環(huán)開始的位置,即前一行結(jié)束的位置

然后我們需要找到循環(huán)結(jié)束的位置,本案例是到相關(guān)意見的 ${otherReasonDesc}處結(jié)束,找到這一行結(jié)束的位置,添加 </#list> 標(biāo)簽,如圖所示:

添加完<#list></#list>標(biāo)簽后,我們需要調(diào)整變量名,將要?jiǎng)討B(tài)生成的變量改為 循環(huán)變量.變量

本案例中,以供應(yīng)商管理部門為例,我們需要將 ${supplierOpinion}改為{yc.supplierOpinion}, ${supplierSituationDesc}改為{yc.supplierSituationDesc}, ${supplierReasonDesc}改為{yc.supplierReasonDesc},質(zhì)量部門、技術(shù)部門等的變量相同方式修改,如圖所示:

5.2 相關(guān)代碼實(shí)現(xiàn)

    public void exportWord(@RequestBody OpinionCollectFeedbackQueryVO query, HttpServletResponse response) throws Exception {
        String templateName = "problemSummary.ftl";
        String fileName = "problemSummary.docx";
        Map<String, Object> dataModel = new HashMap<>();
        Map<String, Object> dataModel1 = new HashMap<>();
        Map<String, Object> dataModel2 = new HashMap<>();
        Map<String, Object> dataModel3 = new HashMap<>();
        List<Map<String, Object>> list = new ArrayList<>();
        dataModel.put("aptitudeTaskCode","202502211035");
        dataModel.put("companyName","com20250221");
        dataModel.put("supplierOpinion","供應(yīng)商管理部門審核意見");
        dataModel.put("supplierSituationDesc","供應(yīng)商管理部門情況描述");
 
        dataModel1.put("companyName","com20250221001");
        dataModel1.put("supplierReasonDesc","供應(yīng)商管理部門原因11111");
        dataModel2.put("companyName","com20250221002");
        dataModel2.put("supplierReasonDesc","供應(yīng)商管理部門原因22222");
        dataModel3.put("companyName","com20250221003");
        dataModel3.put("supplierReasonDesc","供應(yīng)商管理部門原因33333");
 
        list.add(dataModel1);
        list.add(dataModel2);
        list.add(dataModel3);
        dataModel.put("whyc",list);
        // 執(zhí)行導(dǎo)出
        FreemarkerUtil.exportWord(templateName, fileName, dataModel,this,response);
    }

測(cè)試導(dǎo)出結(jié)果如下: 

由圖可見,我們實(shí)現(xiàn)了動(dòng)態(tài)生成且數(shù)據(jù)和我們測(cè)試類里填寫的數(shù)據(jù)一致 

5.3 合并單元格

要做到合并單元格,我們首先需要了解一下ftl文件一些屬性的含義,我們先看下圖:

單元格屬性設(shè)置:

<w:tcPr>:定義單元格的屬性。w:tcW:設(shè)置單元格寬度為1992單位(dxa類型)。w:vMerge:設(shè)置單元格為垂直合并的起始單元格(restart)。w:noWrap:設(shè)置單元格內(nèi)容不換行(0表示不啟用)。w:vAlign:設(shè)置單元格內(nèi)容垂直居中對(duì)齊(center)。

<w:vMerge w:val="continue"/>:設(shè)置單元格為垂直合并的延續(xù)部分(continue),表示該單元格與上方單元格合并。 

如果生成的ftl文件里沒有上述屬性,我們可以 在循環(huán)的部門的第一行放 <w:vMerge w:val="restart"/> 從第二行開始,所有要合并的單元格放<w:vMerge w:val="continue"/>

5.3.1 編輯ftl文件:

start和end的位置,一定要放在循環(huán)開始的<w:tcPr>中:

代碼可以這么處理:

    public List<Map<String, Object>> checkList(List<Map<String, Object>> list){
        String start = "<w:vMerge w:val=\"restart\"/>";
        String end = "<w:vMerge w:val=\"continue\"/>";
        list.get(0).put("start",start);
        for (int i = 1; i < list.size(); i++) {
            list.get(i).put("end",end);
        }
        return list;
    }

以上便可實(shí)現(xiàn)合并單元格 

以上就是Java通過freemarker生成Word文檔導(dǎo)出的方式講解的詳細(xì)內(nèi)容,更多關(guān)于Java freemarker生成Word導(dǎo)出的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot之控制器的返回值處理方式

    SpringBoot之控制器的返回值處理方式

    這篇文章主要介紹了SpringBoot之控制器的返回值處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 最新SpringCloud?Stream消息驅(qū)動(dòng)講解

    最新SpringCloud?Stream消息驅(qū)動(dòng)講解

    SpringCloud Stream 是一個(gè)構(gòu)建消息驅(qū)動(dòng)微服務(wù)的框架,通過 SpringCloud Stream 連接消息中間件,以實(shí)現(xiàn)消息事件驅(qū)動(dòng),這篇文章主要介紹了SpringCloud?Stream消息驅(qū)動(dòng),需要的朋友可以參考下
    2022-11-11
  • MyBatis-Plus 使用枚舉自動(dòng)關(guān)聯(lián)注入

    MyBatis-Plus 使用枚舉自動(dòng)關(guān)聯(lián)注入

    本文主要介紹了MyBatis-Plus 使用枚舉自動(dòng)關(guān)聯(lián)注入,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • SpringBoot整合redis+lettuce的方法詳解

    SpringBoot整合redis+lettuce的方法詳解

    這篇文章主要介紹了SpringBoot整合redis+lettuce的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • xxl-job的部署及springboot集成使用示例詳解

    xxl-job的部署及springboot集成使用示例詳解

    XXL-Job是一個(gè)分布式任務(wù)調(diào)度平臺(tái),可進(jìn)行任務(wù)調(diào)度、管理和監(jiān)控,并提供任務(wù)分片、失敗重試、動(dòng)態(tài)分配等功能,這篇文章主要介紹了xxl-job的部署及springboot集成使用,需要的朋友可以參考下
    2023-06-06
  • Java實(shí)現(xiàn)FTP文件的上傳和下載功能的實(shí)例代碼

    Java實(shí)現(xiàn)FTP文件的上傳和下載功能的實(shí)例代碼

    FTP 是File Transfer Protocol(文件傳輸協(xié)議)的英文簡(jiǎn)稱,而中文簡(jiǎn)稱為“文傳協(xié)議”。接下來通過本文給大家實(shí)例講解Java實(shí)現(xiàn)FTP文件的上傳和下載功能,需要的的朋友一起看看吧
    2016-11-11
  • java 虛擬機(jī)中對(duì)象訪問詳解

    java 虛擬機(jī)中對(duì)象訪問詳解

    這篇文章主要介紹了java 虛擬機(jī)中對(duì)象訪問詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • SpringCloud及Nacos服務(wù)注冊(cè)IP選擇問題解決方法

    SpringCloud及Nacos服務(wù)注冊(cè)IP選擇問題解決方法

    這篇文章主要介紹了SpringCloud及Nacos服務(wù)注冊(cè)IP選擇問題,為什么注冊(cè)的IP和真實(shí)IP不符合呢,原因是Nacos客戶端在注冊(cè)服務(wù)時(shí)會(huì)從機(jī)器網(wǎng)卡中選擇一個(gè)IP來注冊(cè),所以,當(dāng)注冊(cè)了的是非真實(shí)IP后,另一臺(tái)機(jī)器調(diào)用時(shí)是不可能調(diào)通的,知道問題原因就是解決方法,一起看看吧
    2024-01-01
  • 在SpringBoot中使用Logback管理記錄日志

    在SpringBoot中使用Logback管理記錄日志

    本篇文章主要介紹了在SpringBoot中使用Logback管理記錄日志,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • spark中使用groupByKey進(jìn)行分組排序的示例代碼

    spark中使用groupByKey進(jìn)行分組排序的示例代碼

    這篇文章主要介紹了spark中使用groupByKey進(jìn)行分組排序的實(shí)例代碼,本文通過實(shí)例代碼給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03

最新評(píng)論

景谷| 海阳市| 收藏| 卢氏县| 中阳县| 政和县| 通河县| 嘉荫县| 二手房| 云阳县| 健康| 淮安市| 玉溪市| 泸溪县| 阿拉善盟| 壶关县| 安达市| 永吉县| 金堂县| 当雄县| 和政县| 舒城县| 扎赉特旗| 大田县| 伊宁县| 铅山县| 扎囊县| 潜江市| 祥云县| 阳曲县| 扶余县| 延津县| 永昌县| 扬州市| 德惠市| 新河县| 凯里市| 邳州市| 聊城市| 抚宁县| 平顶山市|