使用Freemarker导出Word文档(包含图片)代码实现及总结

本篇是关于利用FreeMarker导出Word的实现步骤。采用FreeMarker非常的灵活,能够按照自己指定的样式设置并输出内容,操作简单方便,代码实现也容易。

下面是实现的效果图:

下面是实现步骤:

1.添加FreeMarker需要的jar包(这里用的是2.3.28版本,从网上的maven仓库中获取的)

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

2.然后制作需要导出的Word模板。先利用office工具生成导出怎样的word样式,如图是我绘制的模板:

3.制作好了基本的样式之后,然后另存为.xml格式文档,如:

4.打开这个text.xml文件,在相应的地方填入${xx}表达式:

5.填好后,使用其Notepad++或Sublime工具打开文件,能够看到xml的内容如下:

如果有可能${}与 telephone 分离,则删除分离后${},然后在telephone上添加${}后保存。另一种最安全的方式是:不删除分离的${},先在telephone上添加${},保存后,用word工具打开test.xml,将原来分离的${}删除即可。

6.成功修改后,将文件重命名为.ftl格式的文件。然后将文件放置在项目中或其他路径。这里我是将其拷贝至包中

 7.接下来是代码层的实现

package com.myHelloWorld;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;

import freemarker.core.ParseException;
import freemarker.log.Logger;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateNotFoundException;
import sun.misc.BASE64Encoder;

/**
 * @Description 利用FreeMarker导出Word
 * 2018年12月15日  下午10:23:40
 * @Author Huang Xiaocong
 */
public class ExportMyWord {

    private Logger log = Logger.getLogger(ExportMyWord.class.toString());
    private Configuration config = null;

    public ExportMyWord() {
        config = new Configuration(Configuration.VERSION_2_3_28);
        config.setDefaultEncoding("utf-8");
    }
    /**
     * FreeMarker生成Word
     * @param dataMap 数据
     * @param templateName 目标名
     * @param saveFilePath 保存文件路径的全路径名(路径+文件名)
     * @Author Huang Xiaocong 2018年12月15日 下午10:19:03
     */
    public void createWord(Map<String, Object> dataMap, String templateName, String saveFilePath) {
        //加载模板(路径)数据
        config.setClassForTemplateLoading(this.getClass(), "");
        //设置异常处理器 这样的话 即使没有属性也不会出错 如:${list.name}...不会报错
        config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
        Template template = null;
        if(templateName.endsWith(".ftl")) {
            templateName = templateName.substring(0, templateName.indexOf(".ftl"));
        }
        try {
            template = config.getTemplate(templateName + ".ftl");
        } catch (TemplateNotFoundException e) {
            log.error("模板文件未找到", e);
            e.printStackTrace();
        } catch (MalformedTemplateNameException e) {
            log.error("模板类型不正确", e);
            e.printStackTrace();
        } catch (ParseException e) {
            log.error("解析模板出错,请检查模板格式", e);
            e.printStackTrace();
        } catch (IOException e) {
            log.error("IO读取失败", e);
            e.printStackTrace();
        }
        File outFile = new File(saveFilePath);
        if(!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }
        Writer out = null;
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(outFile);
        } catch (FileNotFoundException e) {
            log.error("输出文件时未找到文件", e);
            e.printStackTrace();
        }
        out = new BufferedWriter(new OutputStreamWriter(fos));
        //将模板中的预先的代码替换为数据
        try {
            template.process(dataMap, out);
        } catch (TemplateException e) {
            log.error("填充模板时异常", e);
            e.printStackTrace();
        } catch (IOException e) {
            log.error("IO读取时异常", e);
            e.printStackTrace();
        }
        log.info("由模板文件:" + templateName + ".ftl" + " 生成文件 :" + saveFilePath + " 成功!!");
        try {
            out.close();
        } catch (IOException e) {
            log.error("关闭Write对象出错", e);
            e.printStackTrace();
        }
    }
    /**
     * 获得图片的Base64编码
     * @param imgFile
     * @return
     * @Author Huang Xiaocong 2018年12月15日 下午10:15:10
     */
    public String getImageStr(String imgFile) {
        InputStream in = null;
        byte[] data = null;
        try {
            in = new FileInputStream(imgFile);
        } catch (FileNotFoundException e) {
            log.error("加载图片未找到", e);
            e.printStackTrace();
        }
        try {
            data = new byte[in.available()];
            //注:FileInputStream.available()方法可以从输入流中阻断由下一个方法调用这个输入流中读取的剩余字节数
            in.read(data);
            in.close();
        } catch (IOException e) {
            log.error("IO操作图片错误", e);
            e.printStackTrace();
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(data);

    }
}

下面是测试类:

public static void main(String[] args) {
        ExportMyWord emw = new ExportMyWord();
        Map<String, Object> dataMap = new HashMap<String, Object>();
        dataMap.put("name", "黄xx");
        dataMap.put("age", 26);
        dataMap.put("blog", "sun_flower火柴客");
        dataMap.put("email", "[email protected]");
        dataMap.put("gender", "男");
        dataMap.put("imgheader", emw.getImageStr("D:\\picture\\23.jpg"));
        dataMap.put("telephone", "123456789101");
        dataMap.put("address", "深圳");
        dataMap.put("naturework", "全职");
        dataMap.put("industry", "IT");
        dataMap.put("aplication", "Java开发");
        dataMap.put("time", "2013年-2017年");
        dataMap.put("schoolname", "南昌大学");
        dataMap.put("education", "本科");
        dataMap.put("projectname", "电子证照xxxx");
        dataMap.put("projecttime", "2017年3月");
        dataMap.put("projectcontent", "我们除了有视、听、味、嗅、触这些外感系统之外,人类还有一个非常重要的内感系统,就是我们情绪和情感的世界。"
                + "这种感受是那样地细腻、微妙、强烈、深沉;看不见、摸不着,说不清、道不明。...");
        emw.createWord(dataMap, "test.ftl", "E:/简历.doc");
    }

7.效果图:

整个过程就是这样。

对于需要多条记录或循环的部分,只要在模板层的代码中添加标签:

<#list></list>

这里说下需要注意的点:

1.很多项目中采用的是Log4j或 Commons Logging日志形式。而Freemarker自带日志类型,即:

若导入的FreeMarker 2.3.x版本以下,可能回抛出Freemarker模版缓存问题:

Compiling FreeMarker template test.ftl[zh_CN,UTF-8,parsed] ....

Could not find template in cache

看官方解释:

2.插入图片的时候格外小心,因为可能导出后是一堆图片代码,那是因为模板未能识别这个图片。说明导出没有问题,而是模板有问题。解决方案就是在原来的地方随便插入一张图片,然后在ftl中删除图片代码就可以了。

原文地址:https://www.cnblogs.com/sun-flower1314/p/10126111.html

时间: 2024-10-09 20:38:35

使用Freemarker导出Word文档(包含图片)代码实现及总结的相关文章

Java 用Freemarker完美导出word文档(带图片)

Java  用Freemarker完美导出word文档(带图片) 前言 最近在项目中,因客户要求,将页面内容(如合同协议)导出成word,在网上翻了好多,感觉太乱了,不过最后还是较好解决了这个问题. 准备材料 1.word原件 2.编辑器(推荐Firstobject free XML editor) 实现步骤 1.用Microsoft Office Word打开word原件: 2.把需要动态修改的内容替换成***,如果有图片,尽量选择较小的图片几十K左右,并调整好位置: 3.另存为,选择保存类型

freemarker生成word文档

利用freemarker生成word文档步骤: 导入jar包:freemarker-2.3.20.jar 新建word模板,调整好样式, word模板另存为2003 xml格式, xml中需要替换的内容用${param}替换,param为参数名称,例如:${name } ,传入参数map.put("name","张三"); 编写java代码,替换xml文档,导出. 1 /** 2 *@文件名称: CreateWord.java 3 *@日期: 2016-5-19 4

java导出word文档

使用freemarker模板导出word文档,用的比较多.这里也是采用的这种方式. 1  编辑一个word文件的模板,用于在程序中需要读入填充在模板中的数据先用字母代替,注意word版本为word2003或高于这个版本: 如:test.doc 2 把模板另存为xml文件: 如:test.xml 3 在xml中查找之前用字母代替的值 加上${} ,如${test}  ${guojia},把文件名改为test.ftl; 4 在项目的WebContent目录下新建一个文件夹,把test.xml放进去:

Java Web项目中使用Freemarker生成Word文档

Web项目中生成Word文档的操作屡见不鲜,基于Java的解决方案也是很多的,包括使用Jacob.Apache POI.Java2Word.iText等各种方式,其实在从Office 2003开始,就可以将Office文档转换成XML文件,这样只要将需要填入的内容放上${}占位符,就可以使用像Freemarker这样的模板引擎将出现占位符的地方替换成真实数据,这种方式较之其他的方案要更为简单. 下面举一个简单的例子,比如在Web页面中填写个人简历,然后点击保存下载到本地,效果图如下所示. 打开下

C# 导出word文档及批量导出word文档(1)

这里用到了两个dll,一个是aspose.word.dll,另外一个是ICSharpCode.SharpZipLib.dll,ICSharpCode.SharpZipLib.dll是用于批量导出word文档的,通过把文件打包成压缩包,以文件流的方式输出下载.aspose.word.dll最好使用最新版的,14.5或者更高,我使用的是14.5版本,页面是采用mvc的语法.在这里感谢赵某人为我提供的帮助.         首先制作好word模板,使用模板可以避免在代码中对word进行排版,方便简单.

C# 导出word文档及批量导出word文档(3)

在初始化WordHelper时,要获取模板的相对路径.获取文档的相对路径多个地方要用到,比如批量导出时要先保存文件到指定路径下,再压缩打包下载,所以专门写了个关于获取文档的相对路径的类. 1 #region 获取文档的相对路径 2 public class WordFilePath 3 { 4 #region 返回文件带路径值 5 /// <summary> 6 /// 返回文件带路径值 7 /// </summary> 8 /// <param name="Fil

通过NPOI导出Word文档

1 XWPFDocument doc = new XWPFDocument(); 2 XWPFParagraph p0 = doc.CreateParagraph(); 3 p0.Alignment = ParagraphAlignment.LEFT; 4 5 XWPFRun r0 = p0.CreateRun(); 6 r0.FontFamily = "宋体"; 7 r0.FontSize = 18; 8 r0.IsBold = true; 9 r0.SetText("未登

C#,WPF使用word模板导出word文档

使用word模板导出word文档,首先需要在word模板中插入书签: 根据创建的书签名和位置,将需要写入的内容插入到word文件中. 需要引用  Microsoft.Office.Interop.Word;在添加引用-程序集中搜索可以找到. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Windows; usin

.NET通过调用Office组件导出Word文档

.NET通过调用Office组件导出Word文档 最近做项目需要实现一个客户端下载word表格的功能,该功能是用户点击"下载表格",服务端将该用户的数据查询出来并生成数据到Word模板中,再反馈给客户端下载. 实现思路如下: 利用微软提供的Office的组件来完成,在服务器端指定目录放置一个word模板(该模板中需要替换的数据信息用书签标记好),当请求过来的时候,读取模板信息并将书签内容替换成从数据库获得的信息在返回给客户端下载即可,代码如下: #region 根据申请单ID号和模板生