Spring Boot集成Freemarker导出word文档以及图片


前言

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。
在这里插入图片描述FreeMarker最初的设计,是被用来在MVC模式的Web开发框架中生成HTML页面的,它没有被绑定到 Servlet或HTML或任意Web相关的东西上。它也可以用于非Web应用环境中。而我们下面要做的是怎么生成freemaker模板并导出成word文档。

最终效果

在这里插入图片描述


一、使用步骤

1.引入库

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

import freemarker.template.Configuration;
import freemarker.template.Template;

2.准备数据

public void exportPmnReport(String requestNo, HttpServletResponse response) throws Exception {
        // 1.设置 freeMarker的版本和编码格式
        Configuration configuration = new Configuration();
        configuration.setDefaultEncoding("UTF-8");
        // 模板所在目录
        String templateDir = "D:\\root\\ZSMART_HOME\\upload\\export\\";
        // 2.设置 freeMarker生成Word文档,所需要的模板的路径
        configuration.setDirectoryForTemplateLoading(new File(templateDir));
        //模板名称
        String templateName = "test.ftl";
        // 3.设置 freeMarker生成Word文档所需要的模板 ---> xxx.ftl
        Template t = null;
        try {
            // 模板文件名称
            t = configuration.getTemplate(templateName);
        } catch (IOException e) {
            throw new IOException("获取 ftl模板失败!" + e.getMessage());
        }

        // 4.生成 Word文档的全路径名称
        File outFile = new File(templateDir + "test.doc");

        // 5.创建一个 Word文档的输出流
        Writer writer = null;
        try {
            writer = new OutputStreamWriter(new FileOutputStream(outFile), "utf-8");
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }

        try {
            List<Map<String, Object>> itemlist = new ArrayList<>();
            List<Map<String, String>> attachList = new ArrayList<>();
            Map<String, String> attach = new HashMap<>();
            Map<String, Object> itemMap = new HashMap<>();
            attach.put("fileId", "000969221124111200000456");
            attach.put("imgTypeName", "1668585059188.PHOTOS.jpg");
            attach.put("url", "图片远程地址");
            //获取图片的base64编码
            attach.put("baseCode", this.getImgBase64String("图片路径如:(root/temp/image/test.png)"));
            attachList.add(attach);
            itemMap.put("itemAttachment", attachList);
            itemMap.put("catalogName", "test54645");
            itemMap.put("itemName", "test");
            itemMap.put("itemResult", "test 2342");
            itemMap.put("itemRemarks", "test54643");
            itemlist.add(itemMap);
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("ProjectName", "Abu Salim - 01 - Monthly Inspection, siteName=GRYN036");
            data.put("completeDate", "2022-11-30 14:56:53");
            data.put("createDate", "2022-11-30 14:56:53");
            data.put("requestNo", "PMN202209175972");
            data.put("HandlerOrg", "HandlerOrg");
            data.put("HandlerStaff", "admin");
            data.put("Area", "Abu Salim");
            data.put("siteName", "GRYN036");
            data.put("listItem", itemlist);
            logger.debug("CorePerformanceService data:" + data);
            // 6.装载数据
            t.process(data, writer);

            response.setCharacterEncoding("utf-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + "test.doc");
            response.setContentType("application/force-download");

            // 7.读取生成好的 Word文档
            File file = new File(templateDir + "test.doc");
            FileInputStream is = new FileInputStream(file);
            OutputStream os = response.getOutputStream();
            byte[] b = new byte[1024];
            int length;
            while ((length = is.read(b)) > 0) {
                os.write(b, 0, length);
            }
            os.flush();
            os.close();
            writer.flush();
            writer.close();
        } catch (IOException e) {
            throw new IOException(e.getMessage());
        } finally {
            deleteTempFile(templateDir + "test.doc");
        }
    }
/**
     * 获取图片base64编码
     * @param imageFile
     * @return
     * @throws UnsupportedEncodingException
     */
    public String getImgBase64String(String imageFile) throws UnsupportedEncodingException {
        if (StringUtil.isEmpty(imageFile)) {
            return "";
        }
        File file = new File(imageFile);
        if (!file.exists()) {
            return "";
        }
        InputStream is = null;
        byte[] data = null;
        try {
            is = new FileInputStream(file);
            data = new byte[is.available()];
            is.read(data);
            is.close();
            is = null;
        }
        catch (IOException e) {
            logger.error("50600001", "Failed to transfer a image", e);
        }
        finally {
            if (null != is) {
                try {
                    is.close();
                }
                catch (IOException e) {
                    logger.error("50600001", "Failed to close the input", e);
                }
            }
        }

        byte[] encoder = Base64.encodeBase64(data, true);
        return new String(encoder, "UTF-8");
    }

二、配置模板

**

  • 准备doc模板

**
在这里插入图片描述

  • 另存为xml文件

在这里插入图片描述

  • 修改名为test.ftl后拷贝文件到相应的文件夹如(D:\root\ZSMART_HOME\upload)’
    在这里插入图片描述
  • 修改test.ftl文件
<Relationship Id="rId4" 
		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
        Target="media/image1.jpeg"/>
   **修改为:**
- <Relationship Id="rId${m.fileId}png"
     	Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
      	Target="media/image${m.fileId}.png"/>

```java
<w:pict>
    <v:shape id="_x0000_i1027" o:spt="75" alt="1654849444488" type="#_x0000_t75"
                                                     style="height:114pt;width:110.35pt;" filled="f"
                                                     o:preferrelative="t" stroked="f" coordsize="21600,21600">
        <v:path/>
        <v:fill on="f" focussize="0,0"/>
        <v:stroke on="f"/>
        <v:imagedata r:id="rId4" o:title="1654849444488"/>
        <o:lock v:ext="edit" aspectratio="t"/>
        <w10:wrap type="none"/>
        <w10:anchorlock/>
    </v:shape>
</w:pict>
	**修改为:**
<w:pict>
    <v:shape id="_x0000_i1025" o:spt="75" alt="${m.imgTypeName}"
                                                             type="#_x0000_t75" style="height:99.85pt;width:62.4pt;"
                                                             filled="f" o:preferrelative="t" stroked="f"
                                                             coordsize="21600,21600">
        <v:path/>
        <v:fill on="f" focussize="0,0"/>
        <v:stroke on="f"/>
        <v:imagedata r:id="rId${m.fileId}png"
                                                                     o:title="${m.imgTypeName}"/>
        <o:lock v:ext="edit" aspectratio="t"/>
        <w10:wrap type="none"/>
        <w10:anchorlock/>
    </v:shape>
</w:pict>
//base64编码
<pkg:part pkg:name="/word/media/image1.jpeg" pkg:contentType="image/jpeg">
    <pkg:binaryData>/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a...
            
    </pkg:binaryData>
</pkg:part>
	**修改为:**
<pkg:part pkg:name="/word/media/image${m.fileId}.png" pkg:contentType="image/png">
    <pkg:binaryData>${m.baseCode}</pkg:binaryData>
</pkg:part>

总结

祝你好运,还是细心,注意标签闭合,模板中数据要做好空判断如(${emp.name?default(“xxx”)} )以及image名称对应。
如需完整模板请留言邮箱地址!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拉霍拉卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值