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系统暂时无法解决

 

 

发布了137 篇原创文章 · 获赞 39 · 访问量 6万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 游动-白 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览