FreeMarker的入门使用

刘白猪
2021-05-08 / 0 评论 / 89 阅读
温馨提示:
本文最后更新于2021-05-08,若内容或图片失效,请留言反馈。

引入依赖

maven中介仓库

<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.30</version>
</dependency>

或者

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

java-web 生成word-doc样例

@RequestMapping(path="/test",produces="application/msword;charset=UTF-8")
    public void  test(HttpServletRequest request, HttpServletResponse resp) {
        File file = null;
        InputStream fin = null;
        ServletOutputStream out = null;
        Map<String,Object> map = Maps.newHashMap();
        map.put("prjName","N999-测试");
        try {
            // 调用工具类WordGenerator的createDoc方法生成Word文档
            file = FreeMarkerGenerator.createDoc(map, "");

            fin = new FileInputStream(file);

            //resp.setCharacterEncoding("utf-8");
             //resp.setContentType("application/msword");
            // 设置浏览器以下载的方式处理该文件默认名为resume.doc
            resp.addHeader("Content-Disposition", "attachment;filename=resume.doc");

            out = resp.getOutputStream();
            byte[] buffer = new byte[512];	// 缓冲区
            int bytesToRead = -1;
            // 通过循环将读入的Word文件的内容输出到浏览器中
            while((bytesToRead = fin.read(buffer)) != -1) {
                out.write(buffer, 0, bytesToRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            if (fin != null){
                try {
                    fin.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if(file != null){
                    // 删除临时文件
                    file.delete();
                }

            }
        }

   private String fileNameHandle(HttpServletRequest request, String fileName) throws IOException{
        String userAgent = request.getHeader("User-Agent");
        byte[] bytes = userAgent.contains("MSIE") ? fileName.getBytes() : fileName.getBytes("UTF-8");
        // 各浏览器基本都支持ISO编码
        String name = new String(bytes, "ISO-8859-1");
        return name;
    }

    }

public class FreeMarkerGenerator {

    private static Configuration configuration = null;
    private static Map<String, Template> allTemplates = null;

    static {
        configuration = new Configuration(Configuration.VERSION_2_3_30);
        configuration.setDefaultEncoding("utf-8");
        configuration.setClassForTemplateLoading(FreeMarkerGenerator.class, "/template/");
        allTemplates = new HashMap<>();
        try {
            allTemplates.put("资管四部保险金信托信托管理报告", configuration.getTemplate("资管四部保险金信托信托管理报告.ftl"));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private FreeMarkerGenerator() {
        throw new AssertionError();
    }

    /**
     *  生成docx
     * @param dataMap
     * @param type
     * @return
     */
    public static File createDoc(Map<?, ?> dataMap, String type) {
        String name = "temp" + (int) (Math.random() * 100000) + ".docx";
        File f = new File(name);
        Template t = allTemplates.get(type);
        try {
            // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
            Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
            t.process(dataMap, w);
            w.close();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
        return f;
    }




}

根据模板doc 制作生成目标doc:

doc模板填充 ${} -->另存为 open2003xml -> 格式化xml,修改${}处的错乱格式 -->修改后缀为ftl

生成docx

package com.ct.wms.util;

/**
 * Copyright  Citic Trust, 2021 中信信托有限公司,版权所有 2021
 * tae5Le2Choh5see2rieshaiQuooGhe7eeth0yahg3ud6eeb1ahsha6eloh2aiYai
 *
 * @date: 2021/7/1
 * @author: liuqiang
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;

import java.io.*;

import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Snowflake;
import lombok.extern.slf4j.Slf4j;

/**
 * https://blog.csdn.net/yuchenff/article/details/103660953
 * 生成docx后缀的文档
 */
@Slf4j
public class Xml2DocxUtil {

    private static Snowflake snowflake = new Snowflake(1,1);
    /**
     * @param outFile          输出文件
     * @param dataMap          数据
     * @param document         模板文件
     * @param documentXmlRels  模板关联文件
     * @param originalTemplate 模板原始docx文件
     * @return 是否成功 true :success & false:fail ;
     */
    public static boolean Xml2Docx(File outFile, Map<String, Object> dataMap, String document, String documentXmlRels, File originalTemplate) {

        ZipOutputStream zipout = null;
        OutputStream outputStream = FileUtil.getOutputStream(outFile);
        try {
            //图片配置文件模板
            ByteArrayInputStream documentXmlRelsInput = FreeMarkerGenerator.getFreemarkerContentInputStream(dataMap, documentXmlRels);
            //内容模板
            ByteArrayInputStream documentInput = FreeMarkerGenerator.getFreemarkerContentInputStream(dataMap, document);
            ZipFile zipFile = new ZipFile(originalTemplate);
            Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
            zipout = new ZipOutputStream(outputStream);
            //开始覆盖文档------------------
            int len = -1;
            byte[] buffer = new byte[1024];
            while (zipEntrys.hasMoreElements()) {
                ZipEntry next = zipEntrys.nextElement();
                InputStream is = zipFile.getInputStream(next);
                zipout.putNextEntry(new ZipEntry(next.getName()));
                if (next.getName().indexOf("document.xml.rels") > 0) { //如果是document.xml.rels由我们输入
                    if (documentXmlRelsInput != null) {
                        while ((len = documentXmlRelsInput.read(buffer)) != -1) {
                            zipout.write(buffer, 0, len);
                        }
                        documentXmlRelsInput.close();
                    }
                } else if ("word/document.xml".equals(next.getName())) {//如果是word/document.xml由我们输入
                    if (documentInput != null) {
                        while ((len = documentInput.read(buffer)) != -1) {
                            zipout.write(buffer, 0, len);
                        }
                        documentInput.close();
                    }
                } else {
                    while ((len = is.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    is.close();
                }

            }
        } catch (Exception e) {
            e.getStackTrace();
            return false;
        } finally {
            if (zipout != null) {
                try {
                    zipout.close();
                } catch (IOException e) {
                    e.getStackTrace();
                    return false;
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.getStackTrace();
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * @param dataModel          数据
     * @return 文件
     */
    public static File Xml2Docx(Object dataModel, String templateName) {

        String dataModelStr = JSON.toJSONString(dataModel, SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.WriteNullListAsEmpty);
        log.info("dateModelJsonStr:{}",dataModelStr);
        //字符串转map
        JSONObject jsonObject = JSONObject.parseObject(dataModelStr);
        Map<String,Object> dataMap = (Map<String,Object>)jsonObject;

        String name = "temp" + snowflake.nextId() + ".doc";
        File outFile = new File(name);

        ZipOutputStream zipout = null;
        OutputStream outputStream = FileUtil.getOutputStream(outFile);
        try {
            //图片配置文件模板
            ByteArrayInputStream documentXmlRelsInput = FreeMarkerGenerator.getFreemarkerContentInputStream(dataMap, templateName + ".xml.rels");
            //内容模板
            ByteArrayInputStream documentInput = FreeMarkerGenerator.getFreemarkerContentInputStream(dataMap, templateName + ".xml");
            ClassLoader classLoader = Xml2DocxUtil.class.getClassLoader();
            URL url = classLoader.getResource("template/" + templateName + ".docx");
            /**
             * url.getFile() 得到这个文件的绝对路径
             */
            File originalTemplate = new File(url.getFile());
            ZipFile zipFile = new ZipFile(originalTemplate);
            Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
            zipout = new ZipOutputStream(outputStream);
            //开始覆盖文档------------------
            int len = -1;
            byte[] buffer = new byte[1024];
            while (zipEntrys.hasMoreElements()) {
                ZipEntry next = zipEntrys.nextElement();
                InputStream is = zipFile.getInputStream(next);
                zipout.putNextEntry(new ZipEntry(next.getName()));
                if (next.getName().indexOf("document.xml.rels") > 0) { //如果是document.xml.rels由我们输入
                    if (documentXmlRelsInput != null) {
                        while ((len = documentXmlRelsInput.read(buffer)) != -1) {
                            zipout.write(buffer, 0, len);
                        }
                        documentXmlRelsInput.close();
                    }
                } else if ("word/document.xml".equals(next.getName())) {//如果是word/document.xml由我们输入
                    if (documentInput != null) {
                        while ((len = documentInput.read(buffer)) != -1) {
                            zipout.write(buffer, 0, len);
                        }
                        documentInput.close();
                    }
                } else {
                    while ((len = is.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    is.close();
                }
            }
        } catch (Exception e) {
            e.getStackTrace();
            return outFile;
        } finally {
            if (zipout != null) {
                try {
                    zipout.close();
                } catch (IOException e) {
                    e.getStackTrace();
                    return outFile;
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.getStackTrace();
                    return outFile;
                }
            }
        }
        return outFile;
    }
}