使用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