前言:导出word的需要其实在日常工作中用到的中央还不少,于是想写一篇文章好好记录一下,在导出之前,须要理解一下对于浏览器如何解决servlet的后盾数据。具体能够理解一下http通信下载行为在servlet的实现。
==导出的工具类代码来源于网络,如有侵权能够分割我删除文章==
集体应用==ftl==作为word导出模板引擎,有很多模板引擎能够选,集体通过查阅材料发现ftl用的比拟多,所以抉择这一种
<!-- more -->
码云地址:文章牵扯代码比拟多,如果要看具操作能够查看我本人瞎弄的一个码云地址:
https://gitee.com/lazyTimes/i...
成果演示:给了一个测试页面,长期写了一些脚本,能够作为参考(后续会贴Html代码进去)
点击提交,导出内容, 导出word报告
导出之后,关上word内容为:
实现步骤 - 制作word模板第一步 新建word,制作成绩样板将须要导出word的内容,先粘贴到一个新建的word文件外面
第二步 转存格局 -> xml抉择文件“另存为”,将格局设置为xml格局
第三步 格式化文件将文件放到idea或者反对格式化的软件外面,进行格式化,保留:
留神占位符要匹配
第四步:模板数据替换占位符在word页面将须要导入数据的中央,替换占位符
须要留神内容解决的时候: ${ filename} 有可能被切割为多个局部,咱们须要把多个切割局部,改为上面的款式
肯定记得所有的改变之后,马上关上xml格局的word,确认是不是改崩了
下面的步骤实现,阐明有一个word模板做好了
第五步:制作ftl文件,word模板成型在我的项目外面新建一个ftl文件,同时须要在工具类中配置,同时把做好站位符操作的xml内容贴进去
代码实现 - 导出代码工具类的配置如下:WordGeneratorUtil.java:
/** * 模板常量类配置 */public static final class FreemarkerTemplate { public static final String REPORT = "report"; public static final String REC_RECOMMEND = "recRecommend"; // 减少你的模板文件名称:}在动态的代码块外面,须要注入对应的模板配置
// 留神初始化要载入对应模板allTemplates.put(FreemarkerTemplate.REPORT, configuration.getTemplate(FreemarkerTemplate.REPORT + ".ftl"));allTemplates.put(FreemarkerTemplate.REC_RECOMMEND,configuration.getTemplate(FreemarkerTemplate.REC_RECOMMEND + ".ftl"));在配置实现之后,导出的时候就能够找到对应的文件了建设一个通用的导出办法:/** * 创立doc 文档 * dataMap 数据,须要对应模板的占位符,否则会出错 * @param dataMap 数据 * @param wordName word 报表的名称 * @param freemarkerTemplateName 指定须要应用哪个freemarker模板 * @return */public static File createDoc(String freemarkerTemplateName, String wordName, Map<String, String> dataMap) { try { File f = new File(wordName); Template t = allTemplates.get(freemarkerTemplateName); // 这个中央不能应用FileWriter因为须要指定编码类型否则生成的Word文档会因为有无奈辨认的编码而无奈关上 Writer w = new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8); t.process(dataMap, w); w.close(); return f; } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException("生成word文档失败"); }}工具类残缺代码:package com.zxd.interview.export;import freemarker.template.Configuration;import freemarker.template.Template;import org.springframework.util.CollectionUtils;import java.io.*;import java.nio.charset.StandardCharsets;import java.util.HashMap;import java.util.Map;/** * <p> * 从网络上依据材料找到的一个工具类 * 次要以freemarker 为外围的模板生成word文档的工具类 * 这里默认配置了固定门路 * 须要依据门路取到对应模板 * 申请参数须要设置对应的模板名称 * @author * @className: WordGeneratorUtils * @description: 文档生成工具类 * </p> * version: V1.0.0 */public final class WordGeneratorUtil { private static Configuration configuration = null; private static Map<String, Template> allTemplates = null; private static final String TEMPLATE_URL = "/templates"; /** * 模板常量类配置 */ public static final class FreemarkerTemplate { public static final String Test = "test"; public static final String REPORT = "report"; public static final String REC_RECOMMEND = "recRecommend"; } static { configuration = new Configuration(Configuration.VERSION_2_3_28); configuration.setDefaultEncoding("utf-8"); configuration.setClassForTemplateLoading(WordGeneratorUtil.class, TEMPLATE_URL); allTemplates = new HashMap(4); try { // 留神初始化要载入对应模板 allTemplates.put(FreemarkerTemplate.Test, configuration.getTemplate(FreemarkerTemplate.Test + ".ftl")); allTemplates.put(FreemarkerTemplate.REPORT, configuration.getTemplate(FreemarkerTemplate.REPORT + ".ftl")); allTemplates.put(FreemarkerTemplate.REC_RECOMMEND, configuration.getTemplate(FreemarkerTemplate.REC_RECOMMEND + ".ftl")); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } private WordGeneratorUtil() { throw new AssertionError(); } /** * 创立doc 文档 * dataMap 数据,须要对应模板的占位符,否则会出错 * @param dataMap 数据 * @param wordName word 报表的名称 * @param freemarkerTemplateName 指定须要应用哪个freemarker模板 * @return */ public static File createDoc(String freemarkerTemplateName, String wordName, Map<String, String> dataMap) { try { File f = new File(wordName); Template t = allTemplates.get(freemarkerTemplateName); // 这个中央不能应用FileWriter因为须要指定编码类型否则生成的Word文档会因为有无奈辨认的编码而无奈关上 Writer w = new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8); t.process(dataMap, w); w.close(); return f; } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException("生成word文档失败"); } }}调用层:在业务层,将须要导出的数据,依据占位符的i信息进行赋值,留神不能漏,否则导出之后的文件会打不开@Overridepublic File exportQualityStep4Word(WordReportDTO exportWordRequest) { Map<String, String> datas = new HashMap(QualityConstants.HASH_MAP_INIT_VALUE); //主题目 datas.put("schoolName", exportWordRequest.getSchoolName()); datas.put("title1", exportWordRequest.getBaseSituation()); datas.put("title2", exportWordRequest.getLearningEnvRec()); datas.put("title3", exportWordRequest.getLearningEnvPro()); datas.put("title4", exportWordRequest.getDayLifeRec()); datas.put("title5", exportWordRequest.getDayLifePro()); datas.put("title6", exportWordRequest.getLearningActivityRec()); datas.put("title7", exportWordRequest.getLearningActivityPro()); datas.put("title8", exportWordRequest.getDevRecommend()); datas.put("base64_1", exportWordRequest.getBase64_1()); datas.put("base64_2", exportWordRequest.getBase64_2()); datas.put("base64_3", exportWordRequest.getBase64_3()); datas.put("base64_4", exportWordRequest.getBase64_4()); datas.put("base64_5", exportWordRequest.getBase64_5()); datas.put("base64_6", exportWordRequest.getBase64_6()); //导出 return WordGeneratorUtil.createDoc(WordGeneratorUtil.FreemarkerTemplate.REPORT, exportWordRequest.getWordName(), datas);}上面是生成报表导出的基本操作,能够在用到的中央复制过来改变即可/** * 生成报告的导出报表操作 * * @param request request * @param response 响应数据 * @param exportWordRequest 导出dto */@PostMapping("/quality/exportword")@ResponseBodypublic void povertyExportWord(HttpServletRequest request, HttpServletResponse response, WordReportDTO exportWordRequest) { File file = qualityReportService.exportQualityStep4Word(exportWordRequest); InputStream fin = null; OutputStream out = null; try { // 调用工具类WordGeneratorUtils的createDoc办法生成Word文档 fin = new FileInputStream(file); response.setCharacterEncoding(QualityConstants.UTF_8); response.setContentType(QualityConstants.CONTENT_TYPE_WORD); // 设置浏览器以下载的形式解决该文件 // 设置文件名编码解决文件名乱码问题 //取得申请头中的User-Agent String filename = exportWordRequest.getWordName(); String agent = request.getHeader(QualityConstants.USER_AGENT); String filenameEncoder = ""; // 依据不同的浏览器进行不同的判断 if (agent.contains(QualityConstants.MSIE)) { // IE浏览器 filenameEncoder = URLEncoder.encode(filename, QualityConstants.UTF_8); filenameEncoder = filenameEncoder.replace("+", " "); } else if (agent.contains(QualityConstants.FIREFOX)) { // 火狐浏览器 BASE64Encoder base64Encoder = new BASE64Encoder(); filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes(QualityConstants.UTF_8)) + "?="; } else { // 其它浏览器 filenameEncoder = URLEncoder.encode(filename, QualityConstants.UTF_8); } response.setHeader(QualityConstants.ACCESS_CONTROL_ALLOW_ORIGIN, "*");//所有域都能够跨 response.setHeader(QualityConstants.CONTENT_TYPE, QualityConstants.CONTENT_TYPE_STEAM);//二进制 流文件 response.setHeader(QualityConstants.CONTENT_DISPOSITION, "attachment;filename=" + filenameEncoder + ".doc");//下载及其文件名 response.setHeader(QualityConstants.CONNECTION, QualityConstants.CLOSE);//敞开申请头连贯 //设置文件在浏览器关上还是下载 response.setContentType(QualityConstants.CONTENT_TYPE_DOWNLOAD); out = response.getOutputStream(); byte[] buffer = new byte[QualityConstants.BYTE_512]; int bytesToRead = QualityConstants.NUM_MINUS_1; // 通过循环将读入的Word文件的内容输入到浏览器中 while ((bytesToRead = fin.read(buffer)) != QualityConstants.NUM_MINUS_1) { out.write(buffer, QualityConstants.NUM_ZERO, bytesToRead); } } catch (Exception e) { throw new RuntimeException(QualityConstants.FARIURE_EXPORT, e); } finally { try { if (fin != null) { fin.close(); } if (out != null) { out.close(); } if (file != null) { file.delete(); } } catch (IOException e) { throw new RuntimeException(QualityConstants.FARIURE_EXPORT, e); } }}导出实体dto上面写了一个导出的实体dto,实体对象能够本人定制:
...