背景:根据word模板下载word。word里面需要填充数据,格式是固定的。首先在word中给数据起个变量名称
需要更换的数据改成${变量名!},必须是英文的,加感叹号是为了防止null,如果数据是null,文档下载下来后会直接显示null,加上感叹号就不会,没数据就是空。也可以不加感叹号,在代码设置下属性即可,后面会说到。变量名结束后把word另存为xml
然后复制到项目中,我用的是idea,打开后会发现就几行,后面老长了
然后format下ctrl+alt+L(快捷键仅供参考,本人是这样的),就会
这些红色不影响,不用管它。在文件中搜索${,被搜到的都是起变量的地方,有的地方是会分离的
这就需要手动帮他们破镜重圆了,剪切下即可
这种应该比较多,手动改下就行。改完后保存,改为.ftl文件。下面是代码
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.*;
import java.util.Map;
public class ExportController {
public void download(WeeklyTask weeklyTask, HttpServletResponse response) {
try {
//加入模板的数据
Map<String, Object> data = new HashMap<>();
data.put("key", value);
String outFileName = "测试.docx";
//模板相对路径
String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
path = path + "templates/";
//linux
if ("/".equals(File.separator)) {
path = path.replaceAll("\\\\", "/");
}
File outFile = createDoc(data, outFileName, path, "模板.ftl");
if (null != outFile) {
response.reset();
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(outFile.getName(), "UTF-8"));
//获取文件输入流
InputStream in = new FileInputStream(outFile);
byte[] buffer = new byte[1024];
OutputStream out = response.getOutputStream();
int len = 0;
while ((len = in.read(buffer)) > 0) {
//将缓冲区的数据输出到客户端浏览器
out.write(buffer, 0, len);
}
in.close();
out.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static File createDoc(Map<String, Object> dataMap, String outFileName, String templatePath, String templateFileName) throws IOException {
//设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
Configuration configuration = new Configuration();
//设置null转为空串
configuration.setClassicCompatible(true);
configuration.setDefaultEncoding("UTF-8");
configuration.setDirectoryForTemplateLoading(new File(templatePath));
Template t = null;
try {
//test.ftl为要装载的模板
t = configuration.getTemplate(templateFileName, "UTF-8");
t.setOutputEncoding("UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
//输出文档路径及名称
File outFile = new File(outFileName);
if (!outFile.exists()) {
outFile.createNewFile();
}
Writer out = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outFile);
OutputStreamWriter oWriter = new OutputStreamWriter(fos, "UTF-8");
//这个地方对流的编码不可或缺,使用main()单独调用时,应该可以,但是如果是web请求导出时导出后word文档就会打不开,并且包XML文件错误。主要是编码格式不正确,无法解析。
// out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
out = new BufferedWriter(oWriter);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
t.process(dataMap, out);
out.close();
fos.close();
return outFile;
} catch (TemplateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
我的模板文件放在
下,我是springBoot,前后端分离的maven。获取模板路径视情况而定。
//设置null转为空串
configuration.setClassicCompatible(true);
这个设置下就可以不加感叹号了。然后模板获取数据是根据你起的变量名称和Map的key对应来获取值的,即使模板里面的变量名称加了感叹号,key也不用加感叹号。然后就可以下载了。如果下载后发现有错位现象,多了空格或者换行,比如这种
下载的文件前面肯定多了很多空格或者回车,把多余的删除即可
还有是循环,塞数据的map要put成
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> m = new HashMap<>();
m.put(“anzlsz01”,value);
list .add(m);
data.put(“TABLE1”, list);模板要这样
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://lebron.blog.csdn.net/article/details/124940139
内容来源于网络,如有侵权,请联系作者删除!