使用freemarker导出Word遇到的问题,文件损坏,手机打不开,本地下载可以打开,服务器打不开等问题。。。
至于流程和步骤就不写了,主要是记录我导出时粗心遇到的问题
本地导出xml格式的文件
原因是因为获取xml文件方式不同,我一开始是用的改后缀为zip格式然后找到xml文件再改成ftl文件,但是那样获取的xml文件会缺少特别特别多的样式,以至于xml里的内容只有百多行,正确的流程应该是:第一步,单击文件,选择另存为:
然后选择xml格式保存:
保存完之后就可以修改xml文件后缀为ftl,用于生成ftl文件了,不过要注意的是xml文件里的内容格式可能会有少许异常,需要手动调整
手机,office打不开文件,但是wps可以打开
其实就是文件格式问题。。。。不过也有可能是我自己的问题哈哈哈,不过我试了很多方法,都打开不了生成的docx文件,只有wps能打开,改成doc后缀就可以打开了。
本地导出的文件可以打开,但是代码提交到tomcat服务器上,再导出的文件就打不开,文件损坏,改成xml格式发现里面的中文乱码了,这个需要修改tomcat的配置文件
需要在tomcat的bin目录下的catalina.bat里加一条语句:
编辑,写入语句再进行重启,再导出就没有问题了
set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MaxPermSize=1024m -Dfile.encoding=UTF-8
要注意的是,freemarker里的填充值是不允许为空的,每次填充都需要进行空判断,如果有null值就会报错
<#if list ??>
<#list list as data>
<#if data.schoolName??>${data.schoolName}</#if>
</#list>
</#if>
这里是工具类代码,复制后修改一下模板路径可直接使用。
controller层:
@GetMapping("/exportWord")
public void exportWord(HttpServletResponse response) throws IOException {
//获取数据
Map<String,Object> data=data.exportWord();
wordUtil.exportWord(response,data,"test.doc", "test.ftl");
}
工具类:
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: linFeng
* @Date: 2019/12/10 15:11
*/
@Slf4j
public class WordUtil {
private Configuration configuration = new Configuration(Configuration.VERSION_2_3_29);
private final String ENCODING="UTF-8";
private final String FTL_PATH="filefolder/ftl";
/**
* 导出word方法
* @param response
* @param data 要导入的数据
* @param wordName word名称
* @param ftlName ftl模板名称
* @throws IOException
*/
public void exportWord(HttpServletResponse response, Object data, String wordName, String ftlName) throws IOException {
File file = null;
InputStream fin = null;
ServletOutputStream out = null;
try {
// createDoc方法生成Word文档
file = createDoc(data, ftlName, wordName);
fin = new FileInputStream(file);
response.setCharacterEncoding(ENCODING);
response.setContentType("application/msword");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(wordName, ENCODING))));
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();
}
}
}
/**
* 生成word文件
* @param dataMap 数据
* @param ftlName ftl模板名
* @param wordName word文件名
* @return
*/
public File createDoc(Object dataMap,String ftlName,String wordName) {
configuration.setDefaultEncoding(ENCODING);
// 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
try {
//这里获取的是resources/filefolder/ftl里的文件
configuration.setDirectoryForTemplateLoading(
new File(
URLDecoder.decode(
Thread.currentThread().getContextClassLoader().getResource(
FTL_PATH).getPath(), ENCODING)
)
);
} catch (IOException e) {
log.error("createDoc获取文件夹失败",e);
e.printStackTrace();
}
Template t = null;
try {
//要装载的模板
t = configuration.getTemplate(ftlName,ENCODING);
} catch (IOException e) {
e.printStackTrace();
}
if(t==null){
return null;
}
// 输出文档名称
File outFile = new File(wordName);
Writer out =null;
try {
out =new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
} catch (Exception e1) {
e1.printStackTrace();
}
if(out==null){
return null;
}
try {
t.process(dataMap, out);
out.close();
} catch ( IOException | TemplateException e) {
log.error("createDoc生成word失败",e);
e.printStackTrace();
}
return outFile;
}
/**
* 注意dataMap里存放的数据Key值要与模板中的参数相对应
*
*/
@SuppressWarnings("unchecked")
public Map<String,Object> getData() {
Map<String,Object>dataMap=new HashMap<>();
// 添加假数据
List<Map<String, String>> list = new ArrayList<>();
for (int i =0;i < 30; i++){
Map<String,String> map = new HashMap<>();
map.put("stName", "学生姓名"+i);
map.put("schoolName", "学校名称"+i);
list.add(map);
}
dataMap.put("schoolName","学校名称");
dataMap.put("now", LocalDateTime.now());
dataMap.put("userName","用户姓名");
dataMap.put("list",list);
return dataMap;
}
public static void main(String[] args) throws Exception {
WordUtil wordReporter = new WordUtil();
//wordReporter.createDoc();
}
}