1. 需求
每周固定统计一些数据,然后通过 word 的形式将数据导出。
2. 思路
① 使用poi 的XWPFDocument 相关 api 操作 word 中的数据 。
* 存在的问题 : 在获取 XWPFRun 对象时,对于 run 区域的划分会有问题,有时候会把需要替换的字符 拆分 , 从而导致在替换时找不到而出错 。并没有找到解决的办法
② 使用 freemarker 对 ftl 模板文件中的特定字符串替换掉 ,采取此方法 freemarker 官网
3. 具体实现
★ gradle 引用 jar 包
compile (
'org.freemarker:freemarker:2.3.20',
)
★ 生成 ftl 模板文件 (idea 要作为资源文件存在 resource包中,方便freemarker获取)
首先是 .doc 的模板文件 , 将 .doc 中需要动态添加的字段 用特殊字符替换 (如11h等,这样可以防止在另存为ftl文件之后被拆分),然后另存为.xml 文件 ,另存为.ftl文件 ,使用编辑器编辑 ftl 文件 ,将之前特定字符替换成可以被替换的内容(形如${})
★ 相关代码
WordGenerator util 类
package com.vastio.util;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import static com.google.common.io.Resources.getResource;
/**
* Created by xlch on 2016/4/14.
*/
public class WordGenerator {
private Map<String,String> replaceMap = null;
private static Configuration config = null;
private static Map<String,Template> templateMap = null;
static {
config = new Configuration();
config.setDefaultEncoding("utf-8");
config.setClassForTemplateLoading(WordGenerator.class,"/com/vastio/ftl"); //官方给出三种方法获取模板文件
templateMap = new HashMap<String, Template>();
try {
Template template = config.getTemplate("report.ftl");
templateMap.put("template",template); //存储到map中
} catch (Exception e) {
e.printStackTrace();
}
}
public WordGenerator(Map<String, String> replaceMap) {
this.replaceMap = replaceMap;
}
public void exportWord(Writer out){
Template template = templateMap.get("template");
try {
template.process(replaceMap,out);
} catch (TemplateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//解决设置名称时的乱码
public static String processFileName(HttpServletRequest request, String fileNames) {
String codedfilename = null;
try {
String agent = request.getHeader("USER-AGENT");
if (null != agent && -1 != agent.indexOf("MSIE") || null != agent
&& -1 != agent.indexOf("Trident")) {// ie
String name = java.net.URLEncoder.encode(fileNames, "UTF8");
codedfilename = name;
} else if (null != agent && -1 != agent.indexOf("Mozilla")) {// 火狐,chrome等
codedfilename = new String(fileNames.getBytes("UTF-8"), "iso-8859-1");
}
} catch (Exception e) {
e.printStackTrace();
}
return codedfilename;
}
}
controller 请求 (下载word不可以用异步请求)
/**
* 下载word
*/
@RequestMapping(value = "/download",method = RequestMethod.POST)
public String export(HttpServletRequest request, HttpServletResponse response, @RequestParam("week")String week, RedirectAttributes redirectAttributes){
int isHasData = wordExportService.exportWord(request,response,week); //通过返回值判断数据库是否有数据是否需要下载 ,但是若可以下载这里往下走会有点问题
if (isHasData == 1){
return "redirect:/word/home";
}else{
redirectAttributes.addFlashAttribute("isHasData",isHasData);
redirectAttributes.addFlashAttribute("weekNow",week);
return "redirect:/word/home";
}
}
service 的 exportWord 方法
/**
* 生成word并导出
* @param request
* @param response
*/
public int exportWord(HttpServletRequest request, HttpServletResponse response,String week){
Calendar calendar = Calendar.getInstance();
calendar .setTime(DateTimeUtil.strToDate(week,"yyyyMMdd"));
calendar.add(Calendar.DAY_OF_MONTH,-6);
String lastWeekBegin = DateTimeUtil.dateToStr(calendar.getTime(),"yyyyMMdd");
String lastWeekEnd = week;
Map<String,String> fieldMap = this.modelReplace(lastWeekBegin,lastWeekEnd);
if (fieldMap == null || fieldMap.size()==0){
return 0;
}else{
WordGenerator generator = new WordGenerator(fieldMap);
String filename = WordGenerator.processFileName(request,"通报"+lastWeekBegin+"-"+lastWeekEnd+".doc");
try {
Writer out = response.getWriter();
response.reset();
response.setContentType("application/msword;charset=utf-8");
response.setHeader("Content-disposition","attachment;filename="+filename);
response.setBufferSize(1024);
generator.exportWord(out);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
return 1;
}
}
modelReplace 方法替换模板中的字符
private Map<String,String> modelReplace(String lastWeekBegin,String lastWeekEnd){
Map<String,String> fieldMap = new HashMap<String, String>();
//查询数据存放在map中
// 如 fieldMap.put("login_week_dpt", largePlatformAppStaEntity.getIntPf().toString()); //模板中有 形如 ${login_week_dpt},将会替换数据
}