做了一个导出Word功能,记录下遇见的坑和技术
一开始我用的poi
文章目录
1.模板准备
1.1将你需要导出的word模板填写部分用字段去代理 ${data?if_exists}
注意:${data}需按顺序写,否则生成xml文档会分开。如果导出需要用到图片在word文档中先插入图片占位.?if_exists空判断
1.2保存成xml文档
1.3将xml放入项目中的Resource/wordTemplate目录下面,然后修改文件后缀名为ftl
1.4 将ftl文件中的这长串字符选中,替换成图片字段${image}
注意:如果在文件中出现中文乱码或者导出成功之后乱码的情况,先在wordTemplate目录下创建一个ftl文件,然后将做好的数据复制到新的ftl里面即可。
ftl中会出现很多报红,这个无需处理,如果有强迫症的需要将一条条报红信息添加到idea配置中
2.导入依赖
<!-- 引入 freemarker 模板依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
3.创建wordUtils工具类
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Encoder;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Map;
/**
* word导出工具
*/
public class WordUtils {
//配置信息,代码本身写的还是很可读的,就不过多注解了
private static Configuration configuration;
//这里注意的是利用WordUtils的类加载器动态获得模板文件的位置
// private static final String templateFolder = WordUtils.class.getClassLoader().getResource("../../").getPath() + "WEB-INF/templetes/";
// private static final String templateFolder = "H:/web/src/main/webapp/WEB-INF/templates";
static {
configuration = new Configuration(Configuration.VERSION_2_3_28);
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(WordUtils.class, "/wordTemplate");
// configuration.setDirectoryForTemplateLoading(new File(templateFolder));
}
private WordUtils() {
throw new AssertionError();
}
public static void exportMillCertificateWord(HttpServletRequest request, HttpServletResponse response, Map map, String title, String ftlFile) throws IOException {
Template freemarkerTemplate = configuration.getTemplate(ftlFile);
File file = null;
InputStream fin = null;
ServletOutputStream out = null;
try {
// 调用工具类的createDoc方法生成Word文档
file = createDoc(map, freemarkerTemplate);
fin = new FileInputStream(file);
response.setCharacterEncoding("utf-8");
response.setContentType("application/msword");
// 设置浏览器以下载的方式处理该文件名
String fileName = title + ".doc";
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
out = response.getOutputStream();
byte[] buffer = new byte[512]; // 缓冲区
int bytesToRead = -1;
// 通过循环将读入的Word文件的内容输出到浏览器中
while ((bytesToRead = fin.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
} finally {
if (fin != null) fin.close();
if (out != null) out.close();
if (file != null) file.delete(); // 删除临时文件
}
}
private static File createDoc(Map<?, ?> dataMap, Template template) {
String name = "WordTemplate.doc";
File f = new File(name);
Template t = template;
try {
// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
t.process(dataMap, w);
w.close();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
return f;
}
/**
* 将图片内容转换成Base64编码的字符串
*
* @param imageFile 图片文件的全路径名称
* @return 转换成Base64编码的图片内容字符串
*/
public static String getImageBase64String(String imageFile) {
if (StringUtils.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();
} catch (IOException e) {
e.printStackTrace();
}
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);
}
}
这块是网上找来直接用到
4.Controller
@GetMapping("/word/download")
@AnonymousAccess
public void wordDownload(Long id, HttpServletRequest request, HttpServletResponse response){
service.wordDownload(id,request,response);
}
5.Service
/**
* 导出异常详情word文档
*
* @param id
*/
@Override
public void wordDownload(Long id, HttpServletRequest request, HttpServletResponse response) {
try {
if (id == null) {
throw new PtException("请求参数错误!");
}
//模板数据
Map<String, Object> data = new HashMap<>();
data.put("data", id);//key:${data} value :值
data.put("image", WordUtils.getImageBase64String(file.getFilePath()));//查询出来的地址
WordUtils.exportMillCertificateWord(request,response,data,"详情","displayScreenException.ftl");
} catch (Exception e) {
throw new PtException("操作异常", e);
}
}