文檔地址:https://github.com/opensagres/xdocreport/wiki/DocxReportingQuickStart
本文采用XDocReport集合Freemaiker進行處理
1. 引入Maven依賴:
<dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>xdocreport</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency>
2. 創建Word模版
新建Word,在光標處通過快捷鍵Ctrl+F9 或 工具欄“插入”->“文檔部件或文本”->“域”
根據電腦系統不同出現的界面不同,但內容都差不多,${text} 這個text就是后期要替換的變量了。

3. Java代碼處理邏輯
1 String templateFilePath = request.getSession().getServletContext().getRealPath("/WEB-INF/templates/freemarkerTest.docx"); 2 File file = new File(templateFilePath); 3 InputStream in = new FileInputStream(file); 4 IXDocReport report; 5 String targetPath = basePath + lawDownDto.getLawsName() + ".docx"; 6 try { 7 report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker); 8 // 設置內容為HTML格式 9 FieldsMetadata metadata = report.createFieldsMetadata(); 10 metadata.addFieldAsTextStyling("text", SyntaxKind.Html); 11 12 // 創建內容-text為模版中對應都變量名稱 13 IContext context = report.createContext(); 14 context.put("text", content); 15 16 // 生成文件 17 OutputStream out = new FileOutputStream(targetPath); 18 report.process(context, out); 19 } catch (XDocReportException e) { 20 e.printStackTrace(); 21 }
文件下載:在生成文件邏輯后創建讀取流返回即可。
=============================================================
如果文件中有圖片需要處理:
圖片方案一:單個圖片且位置固定,可通過XDocReport配置模版處理
圖片方案二:多個圖片且位置不固定,可通過POI結合Freemarker進行處理
圖片方案一:
1. 在模版中插入臨時圖片,選中圖片並添加“書簽”,書簽名稱是后續作為替換的變量

2. 代碼中追加邏輯
在上面代碼10后追加
// logo為模版中標簽名稱 metadata.addFieldAsImage("logo"); report.setFieldsMetadata(metadata);
在上面代碼14行后追加
// IImageProvider可通過3種方式創建(File/IO流/ClassPath下文件)具體可參考頂部文檔-Dynamic Image IImageProvider logo = new FileImageProvider(new File("1950737_195902644.png")); context.put("logo", logo);
圖片方案二:
1. 在上面讀取模版之前進行數據替換
// 處理文本中的圖片,使用imgReplace變量替換 Map<String, Object> param = new HashMap<String, Object>(); if (StringUtils.isNotBlank(content)) { content = HtmlUtils.htmlUnescape(content); List<HashMap<String, String>> imgs = getImgStrContent(content); int count = 0; for (HashMap<String, String> img : imgs) { count++; //處理替換以“/>”結尾的img標簽 content = content.replace(img.get("img"), "${imgReplace" + count + "}"); //處理替換以“>”結尾的img標簽 content = content.replace(img.get("img1"), "${imgReplace" + count + "}"); Map<String, Object> header = new HashMap<String, Object>(); String result = ""; result = img.get("src"); //如果沒有寬高屬性,默認設置為 if(img.get("width") == null || img.get("height") == null) { header.put("width", 150); header.put("height", 150); }else { header.put("width", (int)(Double.parseDouble(img.get("width")))); header.put("height", (int) (Double.parseDouble(img.get("height")))); } if( StringUtils.isNotBlank(result) ){ String type1 = result.substring(result.lastIndexOf(".") , result.length()); header.put("type", type1); header.put("content",this.imageToInputStream(result)); } param.put("${imgReplace" + count + "}", header); } }
//獲取html中的圖片元素信息 private List<HashMap<String, String>> getImgStrContent(String htmlStr) { List<HashMap<String, String>> pics = new ArrayList<HashMap<String, String>>(); Document doc = Jsoup.parse(htmlStr); if( doc != null ){ Elements imgs = doc.select("img"); if( imgs != null && imgs.size() > 0 ){ for (Element img : imgs) { HashMap<String, String> map = new HashMap<String, String>(); if(!"".equals(img.attr("width"))) { map.put("width", img.attr("width")); } if(!"".equals(img.attr("height"))) { map.put("height", img.attr("height")); } map.put("img", img.toString().substring(0, img.toString().length() - 1) + "/>"); map.put("img1", img.toString()); map.put("src", img.attr("src")); pics.add(map); } } } return pics; }
// 讀取生成的文件 readStream = new FileInputStream(targetPath); ByteArrayOutputStream docxOs = new ByteArrayOutputStream(); int b = 0; byte[] buf = new byte[1024]; while ((b = readStream.read(buf)) != -1) { docxOs.write(buf, 0, b); } docxResponseStream = new ByteArrayInputStream(docxOs.toByteArray()); // 創建word 對象 XWPFDocument document = new XWPFDocument(docxResponseStream); newOS = new ByteArrayOutputStream(); if (document != null && param != null) { // 生成帶圖片的word(如需工具類請給我發郵件) XWPFDocument customXWPFDocument = WordUtil.getWord(param, document); // 設置表格邊框樣式(另外一片文章會介紹) // List<XWPFTable> list = formatTableBorder(customXWPFDocument); // 處理合並單元格(另外一片文章會介紹) // mergeCell(content, list); // 寫入輸出流返回 customXWPFDocument.write(newOS); document.close(); customXWPFDocument.close(); resultInpu = new ByteArrayInputStream(newOS.toByteArray()); }else{ resultInpu = docxResponseStream; }
以上內容即可完成Word中多圖片的動態展示。
后續會寫處理表格邊框、單元格合並及段落都相關內容。
