使用freemarker循环图片(附demo)

使用freemarker循环图片

一.效果展示(word文档)

在这里插入图片描述
今天重点讲解图片部分,基础数据展示不做讲解,要求对freemarker有一定的基础,
详看使用Freemarker输出word文档到浏览器与本地

今天为什么要单独讲解图片循环呢?因为在word生成的过程中,word的生成策略运用了比较多的关联,最重要的是使用freemarker你找不到循环体,所以今天特别写了这篇文章,demo放在最后,大家可自行下载

首先先讲一下word的生成策略:word转xml文件之后打开

1.数据源
2.关联
2.正文
先看数据源的位置:pkg:binaryData二进制数据

在这里插入图片描述因为有两张图片所以有两个二进制数据源
在这里插入图片描述图片样式统一处理,忽略掉

再看关联部分Relationships

在这里插入图片描述

<Relationships>有两部分,一部分是word文件相关,另一部分是外部数据源相关,我们只考虑外部数据源相关部分,<Relationships>的Id要与正文的数据地址相对应

最后看正文部分w:document

在这里插入图片描述因未有两张图片,所以与图片相关的有两个

忽略单个图片的样式后,循环图片的核心就是这三大部分了,所以我们要对这三部分数据进行循环和拼接,在拼接的过程中要指定正确的Relationship id

二:代码部分

一:创建maven工程

目录结构如下:
在这里插入图片描述

二:引入pom.xml依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>freemarkerDemo</groupId>
    <artifactId>freemarkerDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

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

        <!-- Spring框架基本的核心工具 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <version>2.2.6.RELEASE</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.1</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13-beta-3</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>
    
</project>

三:核心代码

package com;

import cn.hutool.core.io.FileUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

//@SpringBootTest
@RunWith(JUnit4.class)
public class FreemarkerDemo {

    //请求响应方式
    public void printTroublerectifyAdvice(HttpServletResponse response) throws Exception{
        String content = exportFile();

        InputStream inputStream = IOUtils.toInputStream(content);
        ServletOutputStream out = null;
        try {
            response.setHeader("content-type", "application/octet-stream");
            response.setContentType("application/octet-stream;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(URLEncoder.encode("隐患整改通知书", "UTF-8")+ ".doc")));

            out = response.getOutputStream();
            byte[] buffer = new byte[1024]; // 缓冲区
            int bytesToRead = -1;
            // 通过循环将读入的Word文件的内容输出到浏览器中
            while((bytesToRead = inputStream.read(buffer)) != -1) {
                out.write(buffer, 0, bytesToRead);
            }
        }catch (Exception e){
            throw new RuntimeException("导出word失败,请联系网站管理员!");
        }finally {
            out.flush();
            out.close();
            inputStream.close();
        }
    }

    /**
     * 单元测试
     * @throws Exception
     */
    @Test
    public void printTroublerectifyAdviceTest() throws Exception {
        byte[] buff=new byte[]{};
        String content = exportFile();
        buff=content.getBytes();
        FileOutputStream out=new FileOutputStream("D://scan//out.doc");
        out.write(buff,0,buff.length);

    }


    public String exportFile() throws Exception{
        //创建配置类
        Configuration configuration = new Configuration(Configuration.getVersion());
        String classPath = this.getClass().getResource("/").getPath();
        configuration.setDirectoryForTemplateLoading(new File(classPath+"template/"));

//        //获取模板文件
        Template template = configuration.getTemplate("troublerectifyAdvice.ftl");

        //随便添加几张图片
        BufferedInputStream in1 = FileUtil.getInputStream("D:/scan/test2_result.png");
        BufferedInputStream in2 = FileUtil.getInputStream("D:/scan/ucharts.png");
        BufferedInputStream in3 = FileUtil.getInputStream("D:/scan/IMG_2884.jpg");
        BufferedInputStream in4 = FileUtil.getInputStream("D:/scan/2019-09-04_105944.jpg");
        List<InputStream> list = new ArrayList<InputStream>();
        list.add(in1);
        list.add(in2);
        list.add(in3);
        list.add(in4);

        Map<String, Object> data = new HashMap<String, Object>();
        data.put("number","20200817111106");
        data.put("checkedTime", "2020-09-30");
        data.put("checkedProjectName", "安全生产项目");
        data.put("checkedUser", "张三");
        data.put("rectifyPerson", "李四");
        data.put("rectifyedDate", "2020-08-07");
        data.put("troubleInfo", "详细信息");
        data.put("troubleResult", "整改结果详细");
        data.put("notarizePersion", "王五");

        //处理图片
        String beforePicStart = "<pkg:part pkg:name=\"/word/media/image";
        String afterPicStart = "<pkg:part pkg:name=\"/word/media/image";
        String picBeforeString = "";
        String picAfterString = "";

        String picStrEnd = ".jpeg\" pkg:contentType=\"image/jpeg\" pkg:compression=\"store\"><pkg:binaryData>";
        String picStrEnd2 = "</pkg:binaryData></pkg:part>";
        StringBuffer stringPicBufferBefore = new StringBuffer();
        StringBuffer stringPicBufferAfter = new StringBuffer();
        //处理Relation
        String beforeRelationStart = "<Relationship Id=\"rId";
        String afterRelationEnd = "\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"media/image";
        String afterRelationEnd2 = ".jpeg\"/>";
        String relationStringBefore = "";
        String relationStringAfter = "";
        StringBuffer stringrelationshipBufferBefore = new StringBuffer();
        StringBuffer stringrelationshipBufferAfter = new StringBuffer();

        //处理rsidR
        String rsidStart = "<w:r><w:rPr><w:rFonts w:hint=\"eastAsia\"/><w:noProof/></w:rPr><w:drawing><wp:inline distT=\"0\" distB=\"0\" distL=\"114300\" distR=\"114300\"><wp:extent cx=\"1302589\" cy=\"1302589\"/><wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/><wp:docPr id=\"1\" name=\"图片 1\" descr=\"weixinceshi\"/><wp:cNvGraphicFramePr><a:graphicFrameLocks noChangeAspect=\"1\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"/></wp:cNvGraphicFramePr><a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"><a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"><pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"><pic:nvPicPr><pic:cNvPr id=\"1\" name=\"图片 1\" descr=\"weixinceshi\"/><pic:cNvPicPr><a:picLocks noChangeAspect=\"1\"/></pic:cNvPicPr></pic:nvPicPr><pic:blipFill><a:blip r:embed=\"rId";
        String rsidEnd = "\"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"1304474\" cy=\"1304474\"/></a:xfrm><a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>";
        String rsidAfterString = "";
        String rsidBeforeString = "";
        StringBuffer stringRsidBufferBefore = new StringBuffer();
        StringBuffer stringRsidBufferAfter = new StringBuffer();

        for (int i = 0; i < list.size(); i++) {
            String beforePic = FileToBase64(list.get(i));
            picBeforeString = beforePicStart + (i + 40) + picStrEnd + beforePic + picStrEnd2;
            relationStringBefore = beforeRelationStart + (i + 40) + i + afterRelationEnd + (i + 40) + afterRelationEnd2;
            rsidBeforeString = rsidStart + (i + 40) + i + rsidEnd;
            stringPicBufferBefore.append(picBeforeString);
            stringrelationshipBufferBefore.append(relationStringBefore);
            stringRsidBufferBefore.append(rsidBeforeString);
        }


        data.put("picDataBefore", stringPicBufferBefore.toString());
        data.put("picDataAfter", stringPicBufferAfter.toString());
        data.put("relationshipBefore", stringrelationshipBufferBefore.toString());
        data.put("relationshipAfter", stringrelationshipBufferAfter.toString());
        data.put("beforeRsid", stringRsidBufferBefore.toString());
        data.put("afterRsid", stringRsidBufferAfter.toString());

        String model="yyyy-MM-dd";  //指定格式化的模板
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(model);
        String date = simpleDateFormat.format(new Date());
        String[] split = date.split("-");
        data.put("year", split[0]);
        data.put("month", split[1]);
        data.put("day", split[2]);
        String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);

        return content
    }

    //文件转base编码
    public String FileToBase64(InputStream in) throws IOException {
        byte[] bytes = IOUtils.toByteArray(in);
        String encoded = Base64.getEncoder().encodeToString(bytes);
        return encoded;
    }
}


四:模板文件.ftl

太大了,百度云盘下载吧
链接:https://pan.baidu.com/s/1MRdyrknW4DHOLKsrSQu2HA
提取码:1111

项目地址https://gitee.com/marion1060/freemarkerDemo

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值