FreeMark 根據模板生成文件

 

前言

前因

公司項目電子化項目部的新功能添加了根據施工項目文檔模板,用戶輸入可變變量,生成用戶所需文件的功能

方案記錄

空指針問題:https://www.cnblogs.com/Weagle/p/5417947.html,似乎沒用用

FreeMarker生成Word筆記整理

流程

1 模板處理

1.1 拿到word文檔模板

,將文檔需要手動生成的地方用變量替換,並將變量名記錄下來!!!!

!!一定要檢查好沒有遺漏問題在進行下一步

變量起名風格:最好將文本,表格,單圖片,多圖片等不同格式的文本起名做標記

如:${textxxxxx},${imgxxxxx},${tablexxxxxx},${tablexxxx}

              

 

1.2 其word文檔模板另存爲xml格式

                

 

1.3 將xml文件後綴名直接修改爲ftl,【.ftl】類型的文件是FreeMarker文件

              

 

1.4 將.ftl文件用開發軟件打開,並將代碼格式化(Intellij IDEA快捷鍵Ctrl+Alt+L)

            

 

  • 格式化以前

         

 

  • 格式化以後

          

 

1.5 修改代碼版模板

糾正錯誤

需要遍歷的內容添加<#list></#list>標籤,如表格,圖片等

圖片變量替換(在文檔中無法用變量替換圖片,只能在代碼替換)

  • 糾正錯誤

用查找自己定義的變量的方式快速定位自己定義的變量,檢查轉換過程中是否語法出錯。Intellij IDEA ,查找快捷鍵 Ctrl+F,替換快捷鍵 Ctrl+R

找到有錯誤的代碼,將被分割開的變量中間的代碼全部刪除

                 

                 

                    

 

  • 需要遍歷的內容添加<#list></#list>標籤,如表格,圖片等

 

             

        

 

 

  • 圖片變量替換(在文檔中無法用變量替換圖片,只能在代碼替換)圖片放入表格進行遍歷更方便                           
  •            
  •  
  •  
  •  

替換BASE64編碼的圖片

    1. 中遍歷list獲取索引值
      <#list currentPathList as path>
          <#if path_index == 0>
          </#if>
      </#list>

 

 

 

 

 

需要遍歷的圖片有三部分的代碼需要逐一修改(https://www.cnblogs.com/w-yu-chen/p/11402098.html)

  • 替換BASE64編碼的圖片,添加<#list></#list>標籤,佔位變量${img_projectManagerCerti}
  1. #list img_projectManagerCertiList as img_projectManagerCerti>
    1.     <pkg:part pkg:name="/word/media/manager${img_projectManagerCerti_index+1}.png" pkg:contentType="image/png">
              <pkg:binaryData>${img_projectManagerCerti}</pkg:binaryData>
          </pkg:part>
      </#list>

 

        • 第二大部分:根據之前圖片的名字快捷查找

                           

          • 修改第二大部分

 

 

  •  根據修改前的rid找到第三部分需要修改的內容
  •             

                   

 

 

 

 此處是存放圖片的格式信息,找到存放圖片的表格標籤的開頭和結尾

 

                     

 

 

  • 第三部分修改後
  •           

                

 

                   

 

 

1.5 保存文件,將文件存放在項目可以找到的地方

2 編寫程序,封裝爲工具類調用

package com.zzdy.project.manager.system.gen.modular.program.util;

import com.alibaba.fastjson.JSONObject;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Encoder;

import java.io.*;

/**
 * WordUtil.java
 * User: Monica Jia
 * Email: kyrd@qq.com
 * Date: 2020/1/14  Time: 16:49
 * Description:
 */
@Component
public class WordUtil {

    // freemarker 版本爲2.3.28,Configuration對象不推薦直接new Configuration()
    // 仔細看Configuration.class文件會發現,推薦的是 Configuration(Version incompatibleImprovements) 這個構造方法,具體這個構造方法裏面傳的就是Version版本類,而且版本號不能低於2.3.0
    private Configuration configuration = new Configuration(new Version("2.3.0"));
    @Value("${logging.path}")
    private String basePath;

    /**
     * @method  readWord
     * @description 裝載文件模板供文件生成
     * @date: 2020/3/18 19:32
     * @author: Monica J
     * @param fileNme
     * @return freemarker.template.Template
     */
    private Template readWord(String fileNme,String tempFilePath){
//web工程還可以使用加載方法configuration.setServletContextForTemplateLoading(Object servletContext, String path);
        configuration.setDefaultEncoding("UTF-8");
        Template tempWord = null;
        try {
// 加載文檔模板FTL文件所存在的位置
            configuration.setDirectoryForTemplateLoading(new File( tempFilePath));
// 獲取模板信息
            tempWord = configuration.getTemplate(fileNme+".ftl");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tempWord;

    }

    // 填充模板參數
    private JSONObject getFillData() {

        JSONObject dataMap = new JSONObject();
// 根據模板中的參數填充內容,可以不按順序,參數名稱要對上
        dataMap.put("companyName", "國家電網");
        dataMap.put("projectName", "10Kv");

// list的內容對應表格,表格行數與list的size對應,正常應用中list數據從數據庫獲取,本示例設置一個size=5的list
/*       <List> wordList = new ArrayList >();
        for (int i = 0; i < 5; i++) {
            Map map = new HashMap();
            map.put('para', i);
            map.put('type', '參數' + i);
            if(4 == i){
                map.put('empty', '可空');
            }else{
                map.put('empty', '不可空');
            }
            wordList.add(map);
        }
        dataMap.put('wordList', wordList);*/
        return dataMap;
    }

    /**
     * @method  createWord
     * @description 根據用戶傳入的模板文件路徑,生成word / rtf 文件
     * @date: 2020/3/18 19:20
     * @author: Monica J
     * @param data, fileNme, fileSuffix, outPath
     * @return com.alibaba.fastjson.JSONObject
     */
    public JSONObject createWord(JSONObject data,String fileNme,String tempPath,String outPath) {
        //文件後綴
//        String fileSuffix="rtf";
        String fileSuffix="doc";
        String pdfFileUrl;
        String docFileUrl;
        JSONObject dataRet;
        JSONObject  result;
        //文件輸出路徑
        String fileUrl=outPath+fileNme+"/";
        MyFileUtil.makeDir(Constants.BASE_PATH+fileUrl);
        // 組裝填充模板數據
        // JSONObject dataMap= getFillData();
        // 文檔輸出目錄
        File outFile = new File(Constants.BASE_PATH+fileUrl+fileNme+"."+fileSuffix);
        Writer out = null;
        try {
            out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(outFile)));
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        }
        try {
            // 讀取模板內容並填充變量值,生成文件
            readWord(fileNme,Constants.BASE_PATH+tempPath).process(data, out);
            dataRet=new JSONObject();
            //存儲生成文件的路徑
            docFileUrl=fileUrl+fileNme+"."+fileSuffix;
            //放到響應體中
            dataRet.put("docFileUrl",docFileUrl);
            pdfFileUrl=fileUrl+fileNme+"."+"pdf";
             //將文件轉換爲PDF
            this.doc2pdf2(docFileUrl,pdfFileUrl);
            dataRet.put("pdfFileUrl",pdfFileUrl);
            result=JUtil.getJson(true,dataRet,"文檔生成成功!");
            return result;
        } catch (Exception e) {
            JUtil.exceptionPrint("文檔生成工具(WordUtil)",e);
            result=JUtil.getJson(false,null,"文檔生成失敗,請聯繫研發人員處理!");
            return result;
        }
    }
    /**
     * @method  getImageStr
     * @description 根據圖片的本地絕對路徑將圖片轉換爲base64編碼形式
     * @date: 2020/3/18 19:31
     * @author: Monica J
     * @param imagePath
     * @return java.lang.String
     */
    public String getImageStr(String imagePath) {
        InputStream in ;
        byte[] data = null;
        try {
            in = new FileInputStream(imagePath);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(data);
    }
    

    public void doc2pdf2(String inPath,String outPath){
        ActiveXComponent app = null;

        System.out.println("DOC-PDF開始轉換...");
        // 開始時間
        long start = System.currentTimeMillis();
        try {
            // 打開word
            app = new ActiveXComponent("Word.Application");
            // 設置word不可見,很多博客下面這裏都寫了這一句話,其實是沒有必要的,因爲默認就是不可見的,如果設置可見就是會打開一個word文檔,對於轉化爲pdf明顯是沒有必要的
            //app.setProperty("Visible", false);
            // 獲得word中所有打開的文檔
            Dispatch documents = app.getProperty("Documents").toDispatch();
            System.out.println("打開文件: " +Constants.BASE_PATH+ inPath);
            // 打開文檔
            Dispatch document = Dispatch.call(documents, "Open", Constants.BASE_PATH+inPath, false, true).toDispatch();
            // 如果文件存在的話,不會覆蓋,會直接報錯,所以我們需要判斷文件是否存在
            File target = new File(Constants.BASE_PATH+outPath);
            if (target.exists()) {
                target.delete();
            }
            System.out.println("另存爲: " +Constants.BASE_PATH+ outPath);
            // 另存爲,將文檔報錯爲pdf,其中word保存爲pdf的格式宏的值是17
            Dispatch.call(document, "SaveAs", Constants.BASE_PATH+outPath, 17);
            // 關閉文檔
            Dispatch.call(document, "Close", false);
            // 結束時間
            long end = System.currentTimeMillis();
            System.out.println("轉換成功,用時:" + (end - start) + "ms");
        }catch(Exception e) {
            e.getMessage();
            System.out.println("轉換失敗"+e.getMessage());
        }finally {
            // 關閉office
            app.invoke("Quit", 0);
        }
    }
}

可調用的接口(根據實際情況優化)

    @RequestMapping("/genDocB")
    @ResponseBody
    public JSONObject genDocB(){
        JSONObject data=new JSONObject();
        //數據填充,格式參考MyJsonUtil.getWordTemplateJson()
        data.put("text_year","2019");

        data.put("text_fileNo3_1","12");
        data.put("text_fileNo3_2","13");
        data.put("text_fileNo3_3","3");


        data.put("text_projectName","息縣配電網2019年第六批工程新開工項目");
        data.put("text_proDeptName","息縣10千伏配電網工程施工項目部");


        data.put("text_dateCh","二○一九年十月十五日");
        data.put("text_date","2019年10月15日");

        data.put("text_proManName","陳偉");
        data.put("text_safetyName","[安全員名字]");
        data.put("text_techName","[技術員名字]");
        data.put("text_QCName","[質檢員名字]");
        data.put("text_costName","羅衝");
        data.put("text_infoName","萬久梅");

        List table_managerEmpList=new ArrayList();
        JSONObject managerEmp1=new JSONObject();
        managerEmp1.put("text_position","項目經理");
        managerEmp1.put("text_name","陳偉");
        managerEmp1.put("text_certiName","二級建造師");
        managerEmp1.put("text_certiNo","豫2411414590887");
        managerEmp1.put("text_certiUsefulLife","2015--2019");
        table_managerEmpList.add(managerEmp1);
        JSONObject managerEmp2=new JSONObject();
        managerEmp2.put("text_position","項目總工");
        managerEmp2.put("text_name","萬久梅");
        managerEmp2.put("text_certiName","工程師");
        managerEmp2.put("text_certiNo","C17910970900086");
        managerEmp2.put("text_certiUsefulLife","長期有效");
        table_managerEmpList.add(managerEmp2);
        data.put("table_managerEmpList",table_managerEmpList);

        data.put("img_contractorStamp", wordUtil.getImageStr("E:\\epms_files\\file_template\\華祥公章.png"));

          List  img_projectManagerCertiList=new ArrayList();
         img_projectManagerCertiList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\項目經理_陳偉1.png"));
         img_projectManagerCertiList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\項目經理_陳偉2.png"));
         img_projectManagerCertiList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\項目經理_陳偉3.png"));
         data.put("img_projectManagerCertiList",img_projectManagerCertiList);

          List  img_chiefEngineerList=new ArrayList();
        img_chiefEngineerList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\項目總工_萬久梅1.png"));
         data.put("img_chiefEngineerList",img_chiefEngineerList);

          List  img_technicianCertiList=new ArrayList();
        img_technicianCertiList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\技術員_王剛1.png"));
        img_technicianCertiList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\技術員_王剛2.png"));
         data.put("img_technicianCertiList",img_technicianCertiList);

          List  img_QCCertiList=new ArrayList();
        img_QCCertiList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\質檢員_丁凱1.png"));
         data.put("img_QCCertiList",img_QCCertiList);

          List  img_safetyCertiList=new ArrayList();
        img_safetyCertiList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\安全員_王軍1.png"));
         data.put("img_safetyCertiList",img_safetyCertiList);

        List  img_budgeterCertiList=new ArrayList();
        img_budgeterCertiList.add(wordUtil.getImageStr("E:\\epms_files\\file_template\\項目預算員_羅衝1.png"));
        data.put("img_budgeterCertiList",img_budgeterCertiList);
        
        JSONObject dataMap= MyJsonUtil.getWordTemplateJson(data);

        JSONObject result=wordUtil.createWord(dataMap,"施工項目部組織機構成立文件", Constants.TEMPLATE_FILE_PATH,Constants.PRO_FILE_BASE_PATH+"XM001/");
        return result;
    }

附錄:java:WORD轉換PDF

https://www.cnblogs.com/mh-study/p/10342246.html?tdsourcetag=s_pcqq_aiomsg

所用文件位置:

鏈接:1網盤 https://pan.baidu.com/s/143HqfThKw1nWO7KrH-fA-g
         提取碼:9epf

1藍奏雲地址:https://www.lanzous.com/ianh9nc

jdk環境:jdk8.0.1310.1164 (64位)

1.引入pom文件(或者推薦直接在項目中添加依賴,不然協同開發同事配置麻煩)

<!-- word轉pdf(依賴windows本地的wps) -->
        <dependency>
            <groupId>com.jacob</groupId>
            <artifactId>jacob</artifactId>
            <version>1.18</version>
        </dependency>

2.下載jar文件,手動添加至maven倉庫(無法直接拉取)

cmd進入dos:

 進行以下命令操作,路徑進行對應修改

$ mvn install:install-file  -Dfile=C:\Users\MingHao\Downloads\jacob-1.18\jacob-1.18\jacob.jar   -DgroupId=com.jacob -DartifactId=jacob  -Dversion=1.18 -Dpackaging=jar

 解析:   -Dfile:本地jar包位置(未引入前)  -DgroupId:項目名 對應 com.jacob   -DartifactId:文件名 對應 jacob   -Dversion:版本號 對應 1.18

         

 

 

3.在jdk/bin目錄下引入.dll文件(64位:jacob-1.18-x64.dll 32位:jacob-1.18-x86.dll)

             

 資源文件雲盤備份:

4.準備java代碼

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import java.io.File;

public class Word2Pdf {


    public static void main(String args[]) {
        ActiveXComponent app = null;
        String wordFile = "e:/測試word.docx";
        String pdfFile = "e:/測試pdf.pdf";

        System.out.println("開始轉換...");
        // 開始時間
        long start = System.currentTimeMillis();
        try {
            // 打開word
            app = new ActiveXComponent("Word.Application");
            // 設置word不可見,很多博客下面這裏都寫了這一句話,其實是沒有必要的,因爲默認就是不可見的,如果設置可見就是會打開一個word文檔,對於轉化爲pdf明顯是沒有必要的
            //app.setProperty("Visible", false);
            // 獲得word中所有打開的文檔
            Dispatch documents = app.getProperty("Documents").toDispatch();
            System.out.println("打開文件: " + wordFile);
            // 打開文檔
            Dispatch document = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch();
            // 如果文件存在的話,不會覆蓋,會直接報錯,所以我們需要判斷文件是否存在
            File target = new File(pdfFile);
            if (target.exists()) {
                target.delete();
            }
            System.out.println("另存爲: " + pdfFile);
            // 另存爲,將文檔報錯爲pdf,其中word保存爲pdf的格式宏的值是17
            Dispatch.call(document, "SaveAs", pdfFile, 17);
            // 關閉文檔
            Dispatch.call(document, "Close", false);
            // 結束時間
            long end = System.currentTimeMillis();
            System.out.println("轉換成功,用時:" + (end - start) + "ms");
        }catch(Exception e) {
            e.getMessage();
            System.out.println("轉換失敗"+e.getMessage());
        }finally {
            // 關閉office
            app.invoke("Quit", 0);
        }
    }

}

 

5.準備word文檔 (格式:.docx)

 路徑:e:/測試word.docx

6.windows環境準備

 windows電腦安裝wps office,並且設置wps office爲默認啓動 。(最好不要使用microsoft word 微軟的需要激活,很麻煩,還不成功!)

注:jacb只能在windows系統使用,linux系統暫時無法解決

歡迎加入:前端開發羣

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章