
java使用freemarker操作word(携带动态表格,图片)
java使用freemarker操作word(携带动态表格,图片)循环数据嵌入多张照片进行导出
java使用freemarker操作word(携带动态表格,图片)
一.介绍
这一天公司安排,让我套用模板,数据库转存到word,还要按照给定的模板进行套用
二.准备
1.导入依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
2.先看word文档
这里我新建一个A.docx的word文档进行测试,内容如下(因为有的模板涉及到图片,这里就也加一个图片)文字模板要是
${}
格式的
注意:如果是要按照这个,下面两个图片不能一样,不然他返回的地址就是一样的
如果是offic的可以按住F12
然后另存为xml
格式的文件
3、格式化
xml文件的代码如果没有结构可以去菜鸟进行格式化
菜鸟格式化地址:https://c.runoob.com/front-end/710/
格式化玩进行查看,有的人这里格式会不对注意一下(最好的就是在word写一个好的注释,然后换成xml之后在进行加上${}
的格式)
3.1、普通替换
下面看图片,搜索<pkg:binaryData>
,会看到下面的byte码,这边修改一下就可以(把<pkg:binaryData></pkg:binaryData>
里面的内容图换位占位符就可以了)这里的image1.png
是上面那个暂无图片,image2.png
是表格里面的图片,后缀根据自己上传的有所区别
想要证实哪个是哪个,可以搜索image1.png
,搜索之后可以查看到类似下面的结果
然后在进行搜索Id
也就是rId4
,然后就能看到descr的值和文件名重合
这里先修改img,表格里的在下面进行修改
3.2、表格替换
表格的具体位置也就是
<w:tr>
,因为太长就不截全了,也就是下面这个
这里表格变成动态的,就需要在<w:tr></w:tr>
标签外部加入<#list table as item></#list>
这里的table是后台定义的参数,跟test和img一样,item也是重命名的没有啥要求
图片这里可以看到也有图片 就类似表格和img的结合,继续搜索<pkg:binaryData>
先找到image2.png
(根据自己的后缀进行修改)
具体修改看图,和修改表格一样,需要加入<#list table as item></#list>
,还需要${item.pic1}
替换图片,注意,也需要加入${item_index}
定义索引
然后搜索
image2.png
具体修改如下,替换的和上面的一样
然后搜索
rId5
具体修改如下,这里只需要替换一个rId就可以了
然后就可以保存,将文件的后缀改为.ftl
三.代码
插播一下,获取下项目
resources
文件路径,以resources/static
为例
如果下面有文件a.doc
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
ResourceLoader resourceLoader = new DefaultResourceLoader();
String inputStream1 = resourceLoader.getResource("classpath:static").getURL().getPath();
String inputStream1 = resourceLoader.getResource("classpath:static/a.doc").getURL().getPath();
1.这里为了方便我就直接在启动类进行写了,后期对接数据库什么的直接赋值就可,这里直接写死先
public class TestApplication {
private static String Path = "C:\\picture\\";
public static void main(String[] args) {
// SpringApplication.run(TestApplication.class, args);
importWord();
}
public static void importWord() {
Writer out = null;
try {
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("test", new SimpleDateFormat("yyyy年MM月dd日").format(new Date()));
String s1 = PicConvert.getImageUrlStr(Path + "a.jpg");
String s2 = PicConvert.getImageUrlStr("https://img1.baidu.com/it/u=1966616150,2146512490&fm=253&fmt=auto&app=138&f=JPEG?w=751&h=500");
dataMap.put("img", s1);
// dataMap.put("img", s2);
// 动态表格数据
List<ExportSupervision3> list = new ArrayList<>();
list.add(new ExportSupervision3(1,"我是第一行",s1));
list.add(new ExportSupervision3(2,"我是第二行",""));
list.add(new ExportSupervision3(2,"我是第三行",s2));
dataMap.put("table", list);
Configuration configuration = new Configuration(new Version("2.3.0"));
configuration.setDefaultEncoding("utf-8");
configuration.setDirectoryForTemplateLoading(new File(Path));//ftl文件目录
//输出文档路径及名称
File outFile = new File(Path + "A.doc");
Template template = configuration.getTemplate("A.ftl", "utf-8");
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240);
template.process(dataMap, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (out != null){
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
工具类
import sun.misc.BASE64Encoder;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
public class PicConvert {
//图片地址
public static String getImageUrlStr(String imgFile) {
InputStream in = null;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
if (imgFile.startsWith("http://")||imgFile.startsWith("https://")){
in = getInputStream(imgFile);
}else {
in = new FileInputStream(imgFile);
}
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(out.toByteArray());
}
public static InputStream getInputStream(String picUrl) {
InputStream in = null;
HttpURLConnection connection = null;
try {
// 使用正则表达式统一处理路径分隔符
String separatorRegex = "[/\\\\]"; // 匹配 / 或 \
String[] parts = picUrl.split(separatorRegex);
// 获取文件名部分
String fileName = parts[parts.length - 1];
String encodedFilename = URLEncoder.encode(fileName, "UTF-8");
// 构建完整的URL
StringBuilder baseUrl = new StringBuilder();
for (int i = 0; i < parts.length - 1; i++) {
baseUrl.append(parts[i]).append("/");
}
String fullUrl = baseUrl.toString() + encodedFilename;
URL url = new URL(fullUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(10000);
connection.setDoInput(true);
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
if (responseCode == 200) {
in = connection.getInputStream();
}
} catch (Exception e) {
e.printStackTrace();
}
return in;
}
}
四、拓展
导出图片为
4.1、具体样式
如果一个表格里还需要多张图片,也就是
list
嵌套
或者说是:两个<#list table as item></#list>
嵌套
从3.2
的基础上继续写(用复杂图片为例子),这里是后期遇到的所以没有模板了,思路都差不多,反正以后都能cv
之前定义索引是${item_index}
定义的,现在我们需要在最外层进行一个嵌套所以需要在原来的基础上加上一个${pics_index}
,参数都是跟随你定义的<#list>
而改变的,如图:
4.2解释
原本只是使用一个<#list table as item></#list>
就可以了,现在在table里面还有一组需要循环的,所以就在原来的基础上,加入了<#list item.pic1 as pics></#list>
,因为是动态参数,所以防止出现为空的的情况这里使用了<#if item.pic1?exists><#else></#if>
(这里的if和else与代码有些不同,如果是普通的数值,可以不使用if else
直接在后台替换就可以了,我这里是图片,所以使用其进行替换格式)
4.3代码如下
1、最外层的集合
<#list table as item>
2、判断数值是否为空,如果不为空则进入
<#if item.pic1?exists>
3、不为进入,再次执行循环
<#list item.pic1 as pics>
4、具体操作
</#list>
3、如果为空走else
<#else>
4、具体操作
</#if>
</#list>
4.4使用参数
1、这个table是后台传输给模版的值
<#list table as item>
</#list>
2、这里的item.pic1其实就是table.pic1,参数也是后台定义的
我这里定义的是
private List<ExportPic> pic1;
,实体类如下
<#list item.pic1 as pics>
</#list>
3、这里的if和else使用的参数也同上面一样
<#if item.pic1?exists>
<#else>
</#if>
更多推荐
所有评论(0)