freemarker根据模板生成word文件实现导出功能
一、准备工作
1.创建一个03的word文档,动态的数据用占位符标志占位(如testname)。然后另存为word2003的xml文件。
2.格式化xml文件,占位符的位置用${testname}代替,若有多行格式相同数据等,用List循环。
注意:不要用Eclipse工具去格式化xml文件(会导致导出的word文件不能用office软件打开,但是PDF能打开,估计是pdf的容错率高于office),推荐使用firstObject工具格式化xml文件。
firstobject下载地址:http://www.firstobject.com/dn_editor.htm
3.将xml文件(也可以改成ftl格式)存放到项目中指定位置。
3.下载freemarker的jar包(到中央仓库即可下载)。
二、前端
前端页面添加一个导出按钮,然后按钮添加点击事件,事件中跳转到所请求的Controller层即可:
window.location.href='XXXController/XXXMethod';
如有参数,直接添加到后边即可。
三、后台
1.编写工具类
package io.renren.common.utils; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.Random; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import freemarker.template.Configuration; import freemarker.template.Template; /** * 文件导出工具类 * * @author zblwj * @email 351094262@qq.com * @date 2018年11月1日下午2:40:42 */ public class WordUtils { /** * 生成word文档 */ @SuppressWarnings("unchecked") public static File createWord(Map dataMap,String templateName,String filePath,String fileName){ try { //创建配置实例 Configuration configuration = new Configuration(); //设置编码 configuration.setDefaultEncoding("UTF-8"); //ftl模板文件 configuration.setClassForTemplateLoading(WordUtils.class,"/template"); //获取模板 Template template = configuration.getTemplate(templateName); //输出文件 File outFile = new File(filePath+File.separator+fileName); //如果输出目标文件夹不存在,则创建 if (!outFile.getParentFile().exists()){ outFile.getParentFile().mkdirs(); } //将模板和数据模型合并生成文件 Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8")); //生成文件 template.process(dataMap, out); //关闭流 out.flush(); out.close(); return outFile; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 生成文件名字 * @return */ public static String creatFileName() { /** 文件名称,唯一字符串 */ Random r = new Random(); SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd"); StringBuffer sb = new StringBuffer(); sb.append(sdf1.format(new Date())); sb.append("_"); sb.append(r.nextInt(100)); //文件唯一名称 String fileOnlyName = "机关党支部党员积分申报表" + sb + ".doc"; return fileOnlyName; } /** * 导出文件 * @throws IOException */ public static void exportMillCertificateWord( HttpServletResponse response, Map map,String filePath,String templateName) throws IOException { File file = null; InputStream fin = null; ServletOutputStream out = null; try { String fileName = WordUtils.creatFileName(); file = WordUtils.createWord(map, templateName, filePath,fileName); fin = new FileInputStream(file); response.setCharacterEncoding("utf-8"); response.setContentType("application/msword"); 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(); // 删除临时文件 } } }
2.Controller层
@RequestMapping("/exportSellPlan") @ResponseBody public void exportSellPlan(HttpServletResponse response,PageUtils page, NcPartydeclare partydeclare) { try { Map<String, Object> dataMap = partyDeclareService.exportWordFile(response,page, partydeclare); WordUtils.exportMillCertificateWord(response, dataMap, "D:/doc_f/","test.xml"); } catch (IOException e) { e.printStackTrace(); } }
3.Server层(主要是获取数据源)
/** * word文件导出 */ @Override public Map<String, Object> exportWordFile(HttpServletResponse response, PageUtils page, NcPartydeclare partydeclare) { partydeclare.setUserid( getCurrUser().getUserid()); //数据源 List<?> list = partydeclareMapper.selectPersonPage(page, page.getOrderByClause(), partydeclare); /** 用于组装word页面需要的数据 */ Map<String, Object> dataMap = new HashMap<String, Object>(); /** 组装数据 */ dataMap.put("realname", partydeclare.getRealname()); dataMap.put("zname", ""); dataMap.put("sname", ""); List<Map<String, Object>> listInfo = new ArrayList<Map<String, Object>>(); BigDecimal num = new BigDecimal ("0"); for (int i = 0; i < 10; i++) { Map<String, Object> map = new HashMap<String, Object>(); if(list.size() -1 < i) { map.put("index",""); map.put("sbtitle",""); map.put("add", ""); map.put("reduce",""); }else { NcPartydeclare entity = (NcPartydeclare)list.get(i); map.put("index",i+1); map.put("sbtitle",entity.getTitle()); map.put("add", entity.getBonusvalue()); map.put("reduce", entity.getSubtractionvalue()); //计算总共 num = num.add(entity.getBonusvalue()).subtract(entity.getSubtractionvalue()); } listInfo.add(map); } //计算总共分数 dataMap.put("total", num); dataMap.put("listInfo", listInfo); return dataMap; }
三、最终结果
四、个人总结
此方法还是很简单,但是由于第一次使用,废了不少功夫。导出过程中会生成一个临时的文件,然后利用response的输出流将文件读取到浏览器客户端,读取完成后将会删除生成的临时文件。个人踩坑的地方是用Eclipse格式化了xml文件,导致了导出的word文件不能用office工具打开。
个人学习随笔,如若转载,请标明出处。如有不懂之处,联系QQ:351094262