最近用户有个导出word的需求,看了很多导出word的例子,有poi,itex导出,PageOffice在线编辑导出,freemaker导出等等。
我这只需动态生成word并导出,所以选择了freemaker导出,优点是不用像poi等那样一个一个写入word内容,代码较少且简单
目录
1.pom.xml 引入freemaker的maven依赖,版本自行选择
3.word模板编辑好后,将word文件另存为xml格式,再将xml格式文件的后缀改为 .ftl
开发步骤
引入jar包,生成一个freemaker文件
1.pom.xml 引入freemaker的maven依赖,版本自行选择
<!--freemaker--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency>
2.选择你要生成的word模板,如图,动态值用${}标记
3.word模板编辑好后,将word文件另存为xml格式,再将xml格式文件的后缀改为 .ftl
至此,这样我们一个freemaker模板文件就已经完成了,接下来就是在java中将值绑定到模板里面并导出了
在java程序中简单测试功能是否通过(可跳过)
package com.***.test;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
/**
* @author YinHaiBo
* @create 2021/4/29 14:56
*/
public class FreemakerTest1 {
public static void main(String[] args) throws IOException, TemplateException {
//1.创建配置实例Cofiguration
Configuration cfg = new Configuration();
cfg.setDefaultEncoding("utf-8");
//2.设置模板文件目录
cfg.setDirectoryForTemplateLoading(new File("D:\\template"));
//获取模板(template)
Template template = cfg.getTemplate("cpdbReport.ftl");
//建立数据模型(Map)
Map<String, String> map = new HashMap<String, String>();
map.put("brandNo", "B50P130");
map.put("age", "25");
//获取输出流(指定到控制台(标准输出))
Writer out = new OutputStreamWriter(System.out);
//数据与模板合并(数据+模板=输出)
template.process(map, out);
out.flush();
}
}
为什么要先在main方法里面先测试?因为我一开始是直接在web中加入功能,然后遇到了一些坑,比如模板找不到等情况。所以首先最好在main方法里测试一下程序是否能执行再放到对应功能模块中使用
servlet编写导出word功能
package com.***.**.qc.sg.servlet;
import com.baosight.gxzl.qc.sg.service.ServiceQCSG06;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class ServletQCSG06 extends HttpServlet {
@SuppressWarnings({"rawtypes" })
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
Configuration cfg = new Configuration();
cfg.setDefaultEncoding("utf-8");
//ServiceQCSG06这个类是我用来定位找resource路径的,你只需填成自己的service类即可
final String path = ServiceQCSG06.class.getClassLoader().getResource("META-INF/resources/YF/XC/template").getPath();
cfg.setDirectoryForTemplateLoading(new File(path));
Map map = new HashMap();
map.put("BRAND_NO", "B50P130");
String fileName = "测试.doc";
File file = null;
InputStream fis = null;
ServletOutputStream out = null;
try {
file = new File(fileName);
Template t = cfg.getTemplate("cpdbReport.ftl");
Writer writer = new OutputStreamWriter(new FileOutputStream(file), "utf-8");
t.process(map, writer);
writer.close();
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/msword");
resp.addHeader("Content-Disposition", "attachment;filename="+fileName);
fis = new FileInputStream(file);
out = resp.getOutputStream();
byte[] buffer = new byte[512];
int bytesToRead = -1;
// 通过循环将读入的Word文件的内容输出到浏览器中
while((bytesToRead = fis.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
} catch (TemplateException e) {
throw new ServletException("Error while processing FreeMarker template", e);
} finally {
if(fis != null){
fis.close();
}
if(out != null){
out.close();
}
if(file != null){
file.delete();
}
}
}
}
下图为我项目存放freemaker模板文件的目录
注意:在向word插入base64格式图片时,需要去掉前面的data:image/png;base64,
代码很简单,为了方便观看,我已经把所有内容整合到一个方法里面了。祝好