參考:https://my.oschina.net/u/3737136/blog/2958421?tdsourcetag=s_pcqq_aiomsg
具體思路
1.創建一個docx文檔模板,其中的英文是根據自己需要填充的內容。
2.把docx文檔修改為ZIP格式(修改.docx后綴名為.zip),然后把zip解壓到當前目錄
3.修改word目錄下document.xml文檔,把如下原來是time改為${time},改好后放入項目中,用於后邊內容填充。【有時候一個單詞可能會被拆分,自己要做相應的調整】
<#list minuteList as minute></#list> 可用於循環填充,相當於 for (Minute minte:minuteList),示列如下:
<#list minuteList as minute> <w:p w14:paraId="3BB7AF6B" w14:textId="2AD2E958" w:rsidR="00D80192" w:rsidRDefault="00C4552D" w:rsidP="00E47882"> <w:pPr> <w:pStyle w:val="a6"/> <w:numPr> <w:ilvl w:val="0"/> <w:numId w:val="2"/> </w:numPr> <w:ind w:firstLineChars="0"/> </w:pPr> <w:proofErr w:type="spellStart"/> <w:r w:rsidRPr="00C4552D"> <w:t>${minute.meeting_decision_content}</w:t> </w:r> <w:proofErr w:type="spellEnd"/> <w:r> <w:t xml:space="preserve"> </w:t> </w:r> <w:bookmarkStart w:id="0" w:name="_GoBack"/> <w:bookmarkEnd w:id="0"/> <w:r> <w:rPr> <w:rFonts w:hint="eastAsia"/> </w:rPr> <w:t>交由</w:t> </w:r> <w:proofErr w:type="spellStart"/> <w:r w:rsidRPr="00C4552D"> <w:t>${minute.meeting_decision_executor} </w:t> </w:r> <w:proofErr w:type="spellEnd"/> <w:r> <w:rPr> <w:rFonts w:hint="eastAsia"/> </w:rPr> <w:t>負責,在</w:t> </w:r> <w:proofErr w:type="spellStart"/> <w:r w:rsidRPr="00C4552D"> <w:t>${minute.meeting_decision_deadline} </w:t> </w:r> <w:proofErr w:type="spellEnd"/> <w:r> <w:rPr> <w:rFonts w:hint="eastAsia"/> </w:rPr> <w:t>前完成。</w:t> </w:r> </w:p> </#list>
---------下邊思路在代碼中實現------------
4..把內容填充到document.xml里
5.在輸入docx文檔的時候把填充過內容的的 document.xml用流的方式寫入zip(詳見下面代碼)。
6.輸出docx文檔
docx模板修改成zip格式后的信息如下(因為word文檔本身就是ZIP格式實現的)
注:【在文檔里邊加入圖片須進行rels文檔的相關操作,我這里沒用到,如有需要可以查看上邊的參考鏈接】
---------代碼部分------------
pom中導入依賴:
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> </dependency>
項目結構:【箭頭指向才是用到的,其他部分的測試目前沒有刪】
FreeMarkUtils類
import freemarker.template.Configuration; import freemarker.template.Template; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.StringWriter; import java.util.Map; 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/wordTemplates");//換成自己對應的目錄 return configuration; } /** * 獲取模板字符串輸入流 * @param dataMap 參數 * @param templateName 模板名稱 * @return */ public static ByteArrayInputStream getFreemarkerContentInputStream(Map 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("模板生成錯誤!"); } return in; } }
FreemarkerTest類
import com.example.meeting.util.FreeMarkUtils; import java.io.*; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; public class FreemarkerTest { private static String document="document.xml"; //outputStream 輸出流可以自己定義 瀏覽器或者文件輸出流 public static void createDocx(Map dataMap, OutputStream outputStream) { ZipOutputStream zipout = null; try { /*//圖片配置文件模板 ByteArrayInputStream documentXmlRelsInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, documentXmlRels);*/ //內容模板 ByteArrayInputStream documentInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, document); //最初設計的模板 //File docxFile = new File(WordUtils.class.getClassLoader().getResource(template).getPath()); File docxFile = new File("xxxx\\會議紀要.zip");//換成自己的zip路徑 if (!docxFile.exists()) { docxFile.createNewFile(); } 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(); }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 void main(String arg[]){ Map dataMap=new HashMap(); ArrayList minuteList=new ArrayList(); MinuteTest minuteTest1=new MinuteTest(); minuteTest1.setMeeting_decision_content("決策1"); minuteTest1.setMeeting_decision_executor("執行者1"); minuteTest1.setMeeting_decision_deadline("截至日期1"); minuteList.add(minuteTest1); MinuteTest minuteTest2=new MinuteTest(); minuteTest2.setMeeting_decision_content("決策2"); minuteTest2.setMeeting_decision_executor("執行者2"); minuteTest2.setMeeting_decision_deadline("截至日期2"); minuteList.add(minuteTest2); dataMap.put("meeting_name", "如何使象牙山發展得更加美好"); dataMap.put("time", "2019-09-15 15:30"); dataMap.put("site", "會議室212"); dataMap.put("organizer", "張三"); dataMap.put("department", "策划部"); dataMap.put("attendee", "謝大腳、謝廣坤、劉能"); dataMap.put("meeting_content", "關於象牙山發展中的每個人的義務"); dataMap.put("recorder", "王五"); dataMap.put("checker", "大老板"); dataMap.put("minuteList",minuteList); //指定輸出docx路徑 File outFile = new File("xxx\\test.docx") ; try { createDocx(dataMap,new FileOutputStream(outFile)); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
MinuteTest實體類
public class MinuteTest { private String meeting_decision_content; private String meeting_decision_executor; private String meeting_decision_deadline; public String getMeeting_decision_content() { return meeting_decision_content; } public void setMeeting_decision_content(String meeting_decision_content) { this.meeting_decision_content = meeting_decision_content; } public String getMeeting_decision_executor() { return meeting_decision_executor; } public void setMeeting_decision_executor(String meeting_decision_executor) { this.meeting_decision_executor = meeting_decision_executor; } public String getMeeting_decision_deadline() { return meeting_decision_deadline; } public void setMeeting_decision_deadline(String meeting_decision_deadline) { this.meeting_decision_deadline = meeting_decision_deadline; } }
在FreemarkerTest中運行后結果: