前言
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名称对应。
如需完整模板请留言邮箱地址!