最近好多项目都有word导出功能,觉得有必要整理一下知识点
wps可以兼容office,所以最好要用offfice建的doc文件转xml
。两边的格式是不一样的。
标签含义感觉html的有点相似,当然还有许多坑需要自己摸索
正文
依赖
主要是freemark
<!--word模板-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
制作ftl模板
制作ftl文件
另存为word 2003 xml格式的xml,然后xmll文件改后缀,xxx.xml->xxx.ftl
ftl文件模板内容
文字
- word 样式:
- 转成ftl
正文在w:body 标签下
其中${},是占位符,world是属性名
- 代码
/**
引入的包
**/
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
//文字
public void createWord(){
//输出的文件
File file = new File( "E:\\data\\image\\word\\world.doc" );
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 设置编码
configuration.setDefaultEncoding("UTF-8");
// 设置处理空值
configuration.setClassicCompatible(true);
// 设置ftl模板文件加载方式(我是将ftl模板文件放在项目中/resources/templates包下的)
configuration.setClassForTemplateLoading(this.getClass(), "/templates");
// 将模板和数据模型合并生成文件
try {
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
// 获取模板
// wps转的
// Template template = configuration.getTemplate("wold.ftl");
Template template = configuration.getTemplate("wold-office.ftl");
// 映射数据
Map<String, Object> report = new HashMap<>();
report.put("world","测试");
template.process(report,out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
- 结果
列表
- word
注意:属性名上莫名被加了红色波浪,这个转xml的时候,要把多余的去掉
- ftl
w:tab 是表格标签,w:tr是列
用#list 标签循环
//表格
public void createTable(){
File file = new File( "E:\\data\\image\\word\\table.doc" );
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 设置编码
configuration.setDefaultEncoding("UTF-8");
// 设置处理空值
configuration.setClassicCompatible(true);
// 设置ftl模板文件加载方式(我是将ftl模板文件放在项目中/resources/templates包下的)
configuration.setClassForTemplateLoading(this.getClass(), "/templates");
// 将模板和数据模型合并生成文件
try {
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
// 获取模板
Template template = configuration.getTemplate("table-office.ftl");
// 映射数据
Map<String, Object> report = new HashMap<>();
report.put("tableName","测试表格");
ArrayList<Map> maps = new ArrayList<>();
HashMap hashMap = new HashMap();
hashMap.put("id","112312");
hashMap.put("name","王大双");
hashMap.put("age","11");
hashMap.put("sex","男");
maps.add(hashMap);
HashMap hashMap1 = new HashMap();
hashMap1.put("id","19371");
hashMap1.put("name","王小双");
hashMap1.put("age","13");
hashMap1.put("sex","男");
maps.add(hashMap1);
report.put("table",maps);
template.process(report,out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
- 结果
图片
- ftl
//图片
public void createImage(){
File file = new File( "E:\\data\\image\\word\\image.doc" );
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 设置编码
configuration.setDefaultEncoding("UTF-8");
// 设置处理空值
configuration.setClassicCompatible(true);
// 设置ftl模板文件加载方式(我是将ftl模板文件放在项目中/resources/templates包下的)
configuration.setClassForTemplateLoading(this.getClass(), "/templates");
// 将模板和数据模型合并生成文件
try {
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
// 获取模板
// Template template = configuration.getTemplate("image.ftl");
Template template = configuration.getTemplate("image-office.ftl");
// 映射数据
Map<String, Object> report = new HashMap<>();
ArrayList<Map> maps = new ArrayList<>();
// for (int i = 10; i < 15; i++) {
// HashMap hashMap = new HashMap();
// hashMap.put("title",i);
// hashMap.put("name","cesimage"+i);
// hashMap.put("id",i);
// hashMap.put("base64Url",getImgBase("E:\\data\\image\\word\\nkt.jpg"));
// maps.add(hashMap);
// }
HashMap hashMap = new HashMap();
hashMap.put("title",1111);
hashMap.put("name","图一1");
hashMap.put("id",12121);
hashMap.put("base64Url",getImgBase("E:\\data\\image\\word\\nkt.jpg"));
maps.add(hashMap);
HashMap hashMap1 = new HashMap();
hashMap1.put("title",2211);
hashMap1.put("name","cesimagea");
hashMap1.put("id",8);
hashMap1.put("base64Url",getImgBase("E:\\data\\image\\word\\U001.jpg"));
maps.add(hashMap1);
report.put("images",maps);
report.put("iamgeName","ssssssfsf");
template.process(report,out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将图片转换成Base64编码
* @param imgFile 待处理图片地址
* @return
*/
public String getImgBase(String imgFile) {
// 将图片文件转化为二进制流
InputStream in = null;
byte[] data = null;
// 读取图片字节数组
try {
in = new FileInputStream(imgFile);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
// 图片头
//String imghead = "data:image/jpeg;base64,";
return Base64.encodeBase64String(data);
}
- 结果
附录
- 异常
For “#{…}” content: Expected a number, but this has evaluated to a string${…},而不是 #{…}
- image-office.ftl
<w:body>
<wx:sect>
<#list images as image>
<w:p wsp:rsidR="001861B0" wsp:rsidRDefault="001861B0" wsp:rsidP="0089750E">
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
<w:t>${image.name}</w:t>
</w:r>
</w:p>
<w:p wsp:rsidR="001861B0" wsp:rsidRDefault="001861B0" wsp:rsidP="0089750E"/>
<w:p wsp:rsidR="0089750E" wsp:rsidRDefault="001861B0" wsp:rsidP="0089750E">
<w:r>
<w:pict>
<w:binData w:name="wordml://${image.id}.jpg" xml:space="preserve">
${image.base64Url}
</w:binData>
<v:shape id="${image.id}" type="#_x0000_t75" style="width:415.5pt;height:199.5pt">
<v:imagedata src="wordml://${image.id}.jpg" o:title="${image.id}"/>
</v:shape>
</w:pict>
</w:r>
</w:p>
</#list>
<w:p wsp:rsidR="0089750E" wsp:rsidRDefault="0089750E" wsp:rsidP="0089750E"/>
<w:p wsp:rsidR="001861B0" wsp:rsidRDefault="001861B0" wsp:rsidP="0089750E"/>
<w:p wsp:rsidR="0089750E" wsp:rsidRDefault="0089750E" wsp:rsidP="0089750E">
<w:pPr>
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
</w:pPr>
</w:p>
<w:p wsp:rsidR="0072263A" wsp:rsidRDefault="0072263A"/>
<w:sectPr wsp:rsidR="0072263A" wsp:rsidSect="0012095E">
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992"
w:gutter="0"/>
<w:cols w:space="425"/>
<w:docGrid w:type="lines" w:line-pitch="312"/>
</w:sectPr>
</wx:sect>
</w:body>
``
* table-office.ftl
```java
<w:body>
<wx:sect>
<w:p wsp:rsidR="00010FCD" wsp:rsidRDefault="00010FCD" wsp:rsidP="00010FCD">
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
</w:rPr>
<w:t>表格</w:t>
</w:r>
</w:p>
<w:p wsp:rsidR="00010FCD" wsp:rsidRDefault="00010FCD" wsp:rsidP="00010FCD">
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
<w:t></w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
</w:rPr>
<w:t>表格</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
<w:t>${tableName}</w:t>
</w:r>
</w:p>
<w:tbl>
<w:tblPr>
<w:tblW w:w="0" w:type="auto"/>
<w:tblBorders>
<w:top w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:left w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:bottom w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:right w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:insideH w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:insideV w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
</w:tblBorders>
<w:tblLook w:val="04A0"/>
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="1704"/>
<w:gridCol w:w="1704"/>
<w:gridCol w:w="1704"/>
<w:gridCol w:w="1705"/>
</w:tblGrid>
<w:tr wsp:rsidR="00000000" wsp:rsidTr="00010FCD">
<w:tc>
<w:tcPr>
<w:tcW w:w="1704" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00010FCD" wsp:rsidRPr="00010FCD" wsp:rsidRDefault="00010FCD"
wsp:rsidP="00B761A6">
<w:pPr>
<w:rPr>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00010FCD">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
<w:t>序号</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1704" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00010FCD" wsp:rsidRPr="00010FCD" wsp:rsidRDefault="00010FCD"
wsp:rsidP="00B761A6">
<w:pPr>
<w:rPr>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00010FCD">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
<w:t>姓名</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1704" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00010FCD" wsp:rsidRPr="00010FCD" wsp:rsidRDefault="00010FCD"
wsp:rsidP="00B761A6">
<w:pPr>
<w:rPr>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00010FCD">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
<w:t>年龄</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1705" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00010FCD" wsp:rsidRPr="00010FCD" wsp:rsidRDefault="00010FCD"
wsp:rsidP="00B761A6">
<w:pPr>
<w:rPr>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00010FCD">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
<w:t>性别</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
<#list table as item>
<w:tr wsp:rsidR="00000000" wsp:rsidTr="00010FCD">
<w:tc>
<w:tcPr>
<w:tcW w:w="1704" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00010FCD" wsp:rsidRPr="00010FCD" wsp:rsidRDefault="00010FCD"
wsp:rsidP="00B761A6">
<w:pPr>
<w:rPr>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00010FCD">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
<w:t>${item.id}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1704" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00010FCD" wsp:rsidRPr="00010FCD" wsp:rsidRDefault="00010FCD"
wsp:rsidP="00B761A6">
<w:pPr>
<w:rPr>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00010FCD">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
<w:t>${item.name}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1704" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00010FCD" wsp:rsidRPr="00010FCD" wsp:rsidRDefault="00010FCD"
wsp:rsidP="00B761A6">
<w:pPr>
<w:rPr>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00010FCD">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
<w:t>${item.age}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1705" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00010FCD" wsp:rsidRPr="00010FCD" wsp:rsidRDefault="00010FCD"
wsp:rsidP="00B761A6">
<w:pPr>
<w:rPr>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00010FCD">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:kern w:val="0"/>
<w:sz w:val="20"/>
</w:rPr>
<w:t>${item.sex}</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</#list>
</w:tbl>
<w:p wsp:rsidR="0072263A" wsp:rsidRDefault="0072263A"/>
<w:sectPr wsp:rsidR="0072263A">
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992"
w:gutter="0"/>
<w:cols w:space="425"/>
<w:docGrid w:type="lines" w:line-pitch="312"/>
</w:sectPr>
</wx:sect>
</w:body>
- word-office.ftl
<w:body>
<wx:sect>
<w:p wsp:rsidR="00B4513D" wsp:rsidRDefault="00B4513D" wsp:rsidP="00B4513D">
<w:pPr>
<w:listPr>
<w:ilvl w:val="0"/>
<w:ilfo w:val="1"/>
<wx:t wx:val="1,"/>
<wx:font wx:val="Times New Roman"/>
</w:listPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
</w:rPr>
<w:t>文字展示</w:t>
</w:r>
</w:p>
<w:p wsp:rsidR="00B4513D" wsp:rsidRDefault="00B4513D" wsp:rsidP="00B4513D">
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
</w:rPr>
<w:t>一段固定,一段动态</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
<w:t>${world}</w:t>
</w:r>
</w:p>
<w:p wsp:rsidR="0072263A" wsp:rsidRDefault="0072263A"/>
<w:sectPr wsp:rsidR="0072263A">
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992"
w:gutter="0"/>
<w:cols w:space="425"/>
<w:docGrid w:type="lines" w:line-pitch="312"/>
</w:sectPr>
</wx:sect>
</w:body>