freemarker 模板导出docx 及合并
//添加目录 public static void generateTOC(XWPFDocument document) throws InvalidFormatException, FileNotFoundException, IOException { String findText = "toc";//word模板段落标识(在此标识处生成目录) String replaceText = ""; for (XWPFParagraph p : document.getParagraphs()) { for (XWPFRun r : p.getRuns()) { int pos = r.getTextPosition(); String text = r.getText(pos); System.out.println(text); if (text != null && text.contains(findText)) { text = text.replace(findText, replaceText); r.setText(text, 0); addField(p, "TOC \\o \"1-3\" \\h \\z \\u"); // addField(p, "TOC \\h"); break; } } } } private static void addField(XWPFParagraph paragraph, String fieldName) { CTSimpleField ctSimpleField = paragraph.getCTP().addNewFldSimple(); ctSimpleField.setInstr(fieldName); ctSimpleField.setDirty(STOnOff.TRUE); ctSimpleField.addNewR().addNewT().setStringValue("<<fieldName>>"); }
前提
word.docx 模板更改后缀为zip
打开zip 获取 word 文件夹种document.xml
在document.xml 种填充所需参数${}格式,循环添加<#list items as item></#list>
document.xml 放入项目templates 文件夹中
工具代码
public class FreeMarkUtils { private static Logger logger = LoggerFactory.getLogger(FreeMarkUtils.class); public static Configuration getConfiguration() { // 创建配置实例 Configuration configuration = new Configuration(Configuration.VERSION_2_3_28); // 设置编码 configuration.setDefaultEncoding("utf-8"); configuration.setClassForTemplateLoading(FreeMarkUtils.class, "/templates");// 换成自己对应的目录 return configuration; } /** * 获取模板字符串输入流 * * @param dataMap * 参数 * @param templateName * 模板名称 * @return */ public static ByteArrayInputStream getFreemarkerContentInputStream(Map<String, Object> dataMap, String templateName) { ByteArrayInputStream in = null; try { // 获取模板 Template template = getConfiguration().getTemplate(templateName); StringWriter swriter = new StringWriter(); // 生成文件 template.process(dataMap, swriter); in = new ByteArrayInputStream(swriter.toString().getBytes("utf-8"));// 这里一定要设置utf-8编码 // 否则导出的word中中文会是乱码 } catch (Exception e) { logger.error("", e); } return in; } public static void createDocx(Map<String, Object> dataMap, OutputStream outputStream, String zipPath) { ZipOutputStream zipout = null; try { /* * //图片配置文件模板 ByteArrayInputStream documentXmlRelsInput = * FreeMarkUtils.getFreemarkerContentInputStream(dataMap, * documentXmlRels); */ // 内容模板 ByteArrayInputStream documentInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, "document.xml"); // 最初设计的模板 // File docxFile = new // File(WordUtils.class.getClassLoader().getResource(template).getPath()); File docxFile = new File(zipPath);// 换成自己的zip路径 if (!docxFile.exists()) { docxFile.createNewFile(); } @SuppressWarnings("resource") ZipFile zipFile = new ZipFile(docxFile); Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries(); zipout = new ZipOutputStream(outputStream); // 开始覆盖文档------------------ int len = -1; byte[] buffer = new byte[1024]; while (zipEntrys.hasMoreElements()) { ZipEntry next = zipEntrys.nextElement(); InputStream is = zipFile.getInputStream(next); if (next.toString().indexOf("media") < 0) { zipout.putNextEntry(new ZipEntry(next.getName())); if ("word/document.xml".equals(next.getName())) {// 如果是word/document.xml由我们输入 if (documentInput != null) { while ((len = documentInput.read(buffer)) != -1) { zipout.write(buffer, 0, len); } documentInput.close(); } } else { while ((len = is.read(buffer)) != -1) { zipout.write(buffer, 0, len); } is.close(); } } } } catch (Exception e) { System.out.println("word导出失败:" + e.getStackTrace()); logger.error("TET", e); } finally { if (zipout != null) { try { zipout.close(); } catch (IOException e) { System.out.println("io异常"); } } if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { System.out.println("io异常"); } } } } // 两个对象进行追加 public static XWPFDocument mergeWord(XWPFDocument document, XWPFDocument doucDocument2) throws Exception { XWPFDocument src1Document = document; XWPFParagraph p = src1Document.createParagraph(); // 设置分页符 p.setPageBreak(true); CTBody src1Body = src1Document.getDocument().getBody(); XWPFDocument src2Document = doucDocument2; CTBody src2Body = src2Document.getDocument().getBody(); // XWPFParagraph p2 = src2Document.createParagraph(); XmlOptions optionsOuter = new XmlOptions(); optionsOuter.setSaveOuter(); String appendString = src2Body.xmlText(optionsOuter); String srcString = src1Body.xmlText(); String prefix = srcString.substring(0, srcString.indexOf(">") + 1); String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<")); String sufix = srcString.substring(srcString.lastIndexOf("<")); String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<")); CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix); src1Body.set(makeBody); return src1Document; } }
业务代码
单个word导出
@RequestMapping("/export") public void export(@RequestBody JSONObject json, HttpServletResponse res) throws Exception { JSONObject detail = taskService.detail(json); Map<String, Object> beanParams = new HashMap<>(); beanParams.put("userTestName", detail.getString("user_test_name")); beanParams.put("postName", detail.getString("post_name")); beanParams.put("deptName", detail.getString("dept_name")); beanParams.put("testDate", DateUtils.formatDateDay(detail.getDate("test_date"))); beanParams.put("testUserName", detail.getString("test_user_name")); beanParams.put("remarks", StringUtils.isEmpty(detail.getString("remarks_")) ? "" : detail.getString("remarks_")); beanParams.put("responsibilitys", detail.getJSONArray("responsibility_ids")); beanParams.put("zf", detail.getInteger("zf"));
// 读到流中 File outFile = new File(ConfigUtils.getConfigValue("responsibility", "") + ".docx"); try { FreeMarkUtils.createDocx(beanParams, new FileOutputStream(outFile), ConfigUtils.getConfigValue("responsibility", "") + ".zip"); } catch (FileNotFoundException e) { e.printStackTrace(); } InputStream inStream = new FileInputStream(outFile);// 文件的存放路径 // 设置输出的格式 res.setContentType("application/octet-stream; charset=utf-8"); res.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode("安全生产责任制.doc")); res.setCharacterEncoding("utf-8"); // 循环取出流中的数据 byte[] b = new byte[100]; int len; try { while ((len = inStream.read(b)) > 0) res.getOutputStream().write(b, 0, len); inStream.close(); } catch (IOException e) { e.printStackTrace(); } }
合并多个word导出
@RequestMapping("/exports") public void exports(@RequestBody JSONObject json, HttpServletResponse res) throws Exception { json.put("enabled_state_id", "1"); List<JSONObject> taskList = taskService.findAllList(json); if (taskList != null && taskList.size() > 0) { XWPFDocument docs = null; for (JSONObject task : taskList) { json.put("id_", task.getString("id_")); JSONObject detail = taskService.detail(json); Map<String, Object> beanParams = new HashMap<>(); beanParams.put("userTestName", detail.getString("user_test_name")); beanParams.put("postName", detail.getString("post_name")); beanParams.put("deptName", detail.getString("dept_name")); beanParams.put("testDate", DateUtils.formatDateDay(detail.getDate("test_date"))); beanParams.put("testUserName", detail.getString("test_user_name")); beanParams.put("remarks", StringUtils.isEmpty(detail.getString("remarks_")) ? "" : detail.getString("remarks_")); beanParams.put("responsibilitys", detail.getJSONArray("responsibility_ids")); beanParams.put("zf", detail.getInteger("zf"));
//导出指定文件 File outFile = new File("d:/test.docx");
//指定修改word后缀为zip路径 try { FreeMarkUtils.createDocx(beanParams, new FileOutputStream(outFile),"d:/test.zip"); } catch (FileNotFoundException e) { e.printStackTrace(); } if (taskList.indexOf(task) == 0) { docs = new XWPFDocument(new FileInputStream(outFile)); } if (taskList.indexOf(task) == 1) { docs = FreeMarkUtils.mergeWord(docs, new XWPFDocument(new FileInputStream(outFile))); } if (taskList.indexOf(task) > 1) { docs = FreeMarkUtils.mergeWord(docs, new XWPFDocument(new FileInputStream(outFile))); } } if (docs != null) { docs.write(res.getOutputStream()); docs.close(); } // 设置输出的格式 res.setContentType("application/octet-stream; charset=utf-8"); res.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode("安全生产责任制.doc")); res.setCharacterEncoding("utf-8"); } else { } }