所需依賴
<!--生成word文檔所需-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
制作模板的步驟參見上篇博客,有一點需要注意的是document.xml中圖片路徑保存成本地路徑格式以支持各種圖片格式寫入至文檔。

這里的路徑搞了好長時間,簡單記錄一下:

這里的文件名要使用這種格式才能在xml文件中保存為全路徑名稱,不知道是不是我wps的問題,最后是使用了這種方法完成的。
下面記錄一下使用的主要代碼:
FreeMarker工具類:
public class FreeMarkerUtil { public static Configuration getConfiguration() throws IOException{ //創建配置實例 Configuration configuration = new Configuration(Configuration.VERSION_2_3_28); //設置編碼 configuration.setDefaultEncoding("utf-8"); //設置模板加載文件夾(模板路徑) String pathName = ConstantFactory.me().getFilePath()+"templates"+File.separator; configuration.setDirectoryForTemplateLoading(new File(pathName)); return configuration; } /** * 獲取模板字符串 * @param dataMap 參數 * @param templateName 模板名稱 * @return */ public static String getFreemarkerContent(Map dataMap, String templateName) { String result = ""; try { Configuration configuration = getConfiguration(); //獲取模板 Template template = configuration.getTemplate(templateName,"utf-8"); StringWriter swriter = new StringWriter(); //生成文件 template.process(dataMap, swriter); result = swriter.toString(); } catch (Exception e) { e.printStackTrace(); } return result; } /** * 獲取模板字符串輸入流 * @param dataMap 參數 * @param templateName 模板名稱 * @return */ public static ByteArrayInputStream getFreemarkerContentInputStream(Map dataMap, String templateName) { ByteArrayInputStream in = null; try { Configuration configuration = getConfiguration(); //獲取模板 Template template = configuration.getTemplate(templateName,"utf-8"); StringWriter swriter = new StringWriter(); //生成文件 template.process(dataMap, swriter); in = new ByteArrayInputStream(swriter.toString().getBytes("utf-8")); } catch (Exception e) { e.printStackTrace(); } return in; } }
word工具類:
生成本地文件時更改outputStream 輸出流形式即可
public class WordUtil { private final static String separator = File.separator; private final static String xmlDocument = "document.xml"; private final static String xmlDocumentXmlRels = "document.xml.rels"; private final static String xmlContentTypes = "[Content_Types].xml"; /** * 生成評價數據word文檔 * @param outputStream 瀏覽器輸出流 * @param dataMap 填充數據 * @param templateDocxPathName docx模板全路徑名稱 * @return * @author xWang * @Date 2020-06-17 */ public void createDocx(OutputStream outputStream,Map dataMap, String templateDocxPathName) { try { //獲取 document.xml 輸入流 ByteArrayInputStream documentInput = FreeMarkerUtil.getFreemarkerContentInputStream(dataMap, xmlDocument); //獲取 document.xml.rels 輸入流 String xmlDocumentXmlRelsComment = FreeMarkerUtil.getFreemarkerContent(dataMap, xmlDocumentXmlRels); ByteArrayInputStream documentXmlRelsInput = new ByteArrayInputStream(xmlDocumentXmlRelsComment.getBytes("utf-8")); //獲取 header1.xml 輸入流 //ByteArrayInputStream headerInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, xmlHeader, templatePath); //獲取 [Content_Types].xml 輸入流 ByteArrayInputStream contentTypesInput = FreeMarkerUtil.getFreemarkerContentInputStream(dataMap, xmlContentTypes); //讀取 document.xml.rels 文件 並獲取rId 與 圖片的關系 (如果沒有圖片 此文件不用編輯直接讀取就行了) Document document = DocumentHelper.parseText(xmlDocumentXmlRelsComment); Element rootElt = document.getRootElement(); // 獲取根節點 Iterator iter = rootElt.elementIterator();// 獲取根節點下的子節點head List<Map> titleList = JSON.parseArray(JSON.toJSONString(dataMap.get("titleList")), Map.class); for (Map<String,Object> map:titleList ) { List<Map> list = JSON.parseArray(JSON.toJSONString(map.get("optionsList")), Map.class); // 遍歷Relationships節點 while (iter.hasNext()) { Element recordEle = (Element) iter.next(); String id = recordEle.attribute("Id").getData().toString(); String target = recordEle.attribute("Target").getData().toString(); if (target.indexOf("media") == 0) { for (Map<String, String> picMap : list) { if (target.endsWith(picMap.get("name"))) { picMap.put("rId", id); } } } } } File docxFile = new File(templateDocxPathName); if (!docxFile.exists()) { docxFile.createNewFile(); } ZipFile zipFile = new ZipFile(docxFile); Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries(); ZipOutputStream 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 (next.getName().equals("[Content_Types].xml")) { if (contentTypesInput != null) { while ((len = contentTypesInput.read(buffer)) != -1) { zipout.write(buffer, 0, len); } contentTypesInput.close(); } } else if (next.getName().indexOf("document.xml.rels") > 0) { //寫入主數據配置信息 if (documentXmlRelsInput != null) { while ((len = documentXmlRelsInput.read(buffer)) != -1) { zipout.write(buffer, 0, len); } documentXmlRelsInput.close(); } } else if ("word/document.xml".equals(next.getName())) { //寫入主數據信息 if (documentInput != null) { while ((len = documentInput.read(buffer)) != -1) { zipout.write(buffer, 0, len); } documentInput.close(); } } else if ("word/header1.xml".equals(next.getName())) { //寫入頁眉信息 // if (headerInput != null) { // while ((len = headerInput.read(buffer)) != -1) { // zipout.write(buffer, 0, len); // } // headerInput.close(); // } } else { while ((len = is.read(buffer)) != -1) { zipout.write(buffer, 0, len); } is.close(); } } } //寫入新圖片 for (Map<String,Object> map:titleList ) { List<Map> picList = JSON.parseArray(JSON.toJSONString(map.get("optionsList")), Map.class); len = -1; if (picList != null && !picList.isEmpty()) { for (Map<String, String> pic : picList) { ZipEntry next = new ZipEntry("word" + separator + "media" + separator + pic.get("name")); zipout.putNextEntry(new ZipEntry(next.toString())); InputStream in = new FileInputStream(pic.get("path")); while ((len = in.read(buffer)) != -1) { zipout.write(buffer, 0, len); } in.close(); } } } zipout.close(); } catch (Exception e) { // System.err.println(e.getMessage()); e.getStackTrace(); } }
