之前寫過一篇利用Freemarker模板生成doc的博客,不過那個博客有點缺陷,不支持生成docx格式的文檔。所以,這里補充一篇,生成docx或doc格式的文檔以具體的docx模板或者doc模板為主。這里以docx為例。
具體思路:
把docx文檔修改為ZIP格式(修改.docx后綴名為.zip)獲取zip里的document.xml文檔以及_rels文件夾下的document.xml.rels文檔把內容填充到document.xml里,以及圖片配置信息填充至document.xml.rels文檔里在輸入docx文檔的時候把填充過內容的的 document.xml、document.xml.rels用流的方式寫入zip(詳見下面代碼)。把圖片寫入zip文件下word/media文件夾中輸出docx文檔
docx模板修改成zip格式后的信息如下(因為word文檔本身就是ZIP格式實現的)
- document.xml里存放主要數據
- media存放圖片信息
- _rels里存放配置信息
注意:如果docx模板里的圖片帶有具體路徑的話,則圖片的格式不受限制。
如果docx模板里里圖片信息不帶路徑,則模板僅支持和模板圖片類型一致的圖片。
交代了這么多,下面就可以干貨。
準備好docx模板
把docx文檔修改為ZIP格式(修改.docx后綴名為.zip)
獲取zip文件里的word文件夾下的document.xml以及_rels文件夾里的document.xml.rels文件作為模板。
注意:這里圖片配置信息是根據 rId來獲取的。docx模板總的${img_warn}就是rId的具體值。
為了避免重復,我的圖片rId從17開始(在我沒有修改之前,里面最大的rId是rId17)。
填充模板信息、寫入圖片信息。
String temp_path = File.separator+"template"+File.separator+"test";
// HttpServletRequest request = new MockHttpServletRequest();
// String base_path = request.getSession().getServletContext().getRealPath(File.separator)+temp_path+File.separator;
// System.out.println(base_path);Map<String,Object> data_map = new HashMap<>();// 1) 總體環比分析List<String> res = new ArrayList<>();res.add("本周報警總數環比上周上升5.62%,上周報警數20882,本周報警數22055。");data_map.put("data_all_summary_title",res);res = new ArrayList<>();res.add("本周高架總數環比上周上升16.55%,上周報警數2405,本周報警數2803。");data_map.put("data_all_content_title",res);res = new ArrayList<>();res.add("\uF06C\t本周斷面環比上周上升12.8%,上周報警數547,本周報警數617。");res.add("\uF06C\t本周上匝道環比上周上升17.5%,上周報警數1834,本周報警數2155。");res.add("\uF06C\t本周下匝道環比上周上升29.17%,上周報警數24,本周報警數31。");data_map.put("data_all_content",res);res = new ArrayList<>();res.add("本周路口環比上周上升4.19%,上周報警數18477,本周報警數19252。");data_map.put("data_all_end",res);String output_path = "D:/export/";String output_file_name = System.currentTimeMillis()+"_freemarker_word.docx";// FreemarkerWordUtils.createDocx(data_map,file_name,"document.xml",output_path, output_path+file_name);/**** @param dataMap 參數數據* @param docxTemplate docx模板名稱* @param xmltemplateName xml模板名稱* @param xmltConfigemplateName xml配置主模板名稱 一般用來配置圖片、樣式信息* @param temp_path 模板存放路徑* @param output_path 產出路徑* @param template_rir 模板文件下的子文件夾* @param output_file_name 產出文件名稱*/List<String> picNameList = new ArrayList<>();picNameList.add("pic1.png");Map<String,String> picFiles = new HashMap<>();picFiles.put("pic1.png","D:\\export\\png\\pic1.png");picNameList.add("pic2.png");picFiles.put("pic2.png","D:\\export\\png\\pic2.png");picNameList.add("pic3.png");picFiles.put("pic3.png","D:\\export\\png\\pic3.png");picNameList.add("pic4.png");picFiles.put("pic4.png","D:\\export\\png\\pic4.png");picNameList.add("pic5.png");picFiles.put("pic5.png","D:\\export\\png\\pic5.png");picNameList.add("pic6.png");picFiles.put("pic6.png","D:\\export\\png\\pic6.png");picNameList.add("summary_pic7.png");picFiles.put("summary_pic7.png","D:\\export\\png\\summary_pic7.png");picNameList.add("summary_pic8.png");picFiles.put("summary_pic8.png","D:\\export\\png\\summary_pic8.png");picNameList.add("summary_pic9.png");picFiles.put("summary_pic9.png","D:\\export\\png\\summary_pic9.png");data_map.put("picNameList",picNameList);data_map.put("picFiles",picFiles);String base_path = "D:\\idea_workspace\\alarm\\alarm\\src\\main\\resources\\template\\test\\";FreemarkerWordUtils.createDocx(data_map, "ptbjjcxbg.doc", "document.xml","document.xml.rels", temp_path,base_path, output_path, output_file_name);
/*** 生成主數據模板xml* @param dataMap 數據參數* @param templateName 模板名稱* @param pathPrefix 模板路徑* @param filePath 生成路徑*/public static void createTemplateXml(Map dataMap, String templateName, String pathPrefix ,String filePath){try {//創建配置實例Configuration configuration = new Configuration();//設置編碼configuration.setDefaultEncoding("UTF-8");//ftl模板文件統一放至 com.lun.template 包下面
// configuration.setDirectoryForTemplateLoading(new File("D:/idea_workspace/alarm/alarm/src/main/resources/template/"));
// configuration.setClassForTemplateLoading(FreemarkerWordUtils.class,"/template/doc");configuration.setClassForTemplateLoading(FreemarkerWordUtils.class,pathPrefix);//獲取模板Template template = configuration.getTemplate(templateName);//輸出文件File outFile = new File(filePath);//如果輸出目標文件夾不存在,則創建if (!outFile.getParentFile().exists()){outFile.getParentFile().mkdirs();}//將模板和數據模型合并生成文件Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));//生成文件template.process(dataMap, out);//關閉流out.flush();out.close();} catch (Exception e) {e.printStackTrace();}}
/**** @param dataMap 參數數據* @param docxTemplate docx模主板名稱* @param xmltemplateName xml主模板名稱* @param xmltConfigemplateName xml配置主模板名稱 一般用來配置圖片、樣式信息* @param temp_path 模板存放路徑* @param base_path 模板實際路徑* @param output_path 產出路徑* @param output_file_name 產出文件名稱*/public static void createDocx(Map dataMap,String docxTemplate, String xmltemplateName,String xmltConfigemplateName,String temp_path,String base_path,String output_path,String output_file_name){try {try {//================================拼裝生成xml配置文檔================================String xml_config_output_path = output_path+System.currentTimeMillis()+".xml.rels";createTemplateXml(dataMap,xmltConfigemplateName,temp_path,xml_config_output_path);File xmlConfigFile = new File(xml_config_output_path);//讀取 xmlConfigFile 文件 并獲取rId 與 圖片的關系String xmlConfigFile_content = getFreemarkerContent(dataMap,xmltConfigemplateName,temp_path);System.out.println("===========================xmlConfigFile_content================================");System.out.println(xmlConfigFile_content);System.out.println("===========================xmlConfigFile_content================================");Document document = DocumentHelper.parseText(xmlConfigFile_content);Element rootElt = document.getRootElement(); // 獲取根節點Iterator iter = rootElt.elementIterator() ;// 獲取根節點下的子節點headList<String> warn_img_list = new ArrayList<>();List<String> warn_summary_img_list = new ArrayList<>();// 遍歷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){
// System.out.println("id>>>"+id+" >>>"+target);
// id>>>rId18 >>>media/pic1if(target.indexOf("summary")>0){warn_summary_img_list.add(id);}else{warn_img_list.add(id);}}}dataMap.put("warn_img_list",warn_img_list);if(!warn_summary_img_list.isEmpty()){dataMap.put("img_sum_warn_o",warn_summary_img_list.get(0));dataMap.put("img_sum_warn_t",warn_summary_img_list.get(1));dataMap.put("img_sum_warn_tt",warn_summary_img_list.get(2));}
// dataMap.put("","");//================================拼裝生成xml配置文檔================================//================================拼裝生成主模板xml文檔================================String xml_output_path = output_path+System.currentTimeMillis()+".xml";createTemplateXml(dataMap,xmltemplateName,temp_path,xml_output_path);File xmlFile = new File(xml_output_path);//================================拼裝生成主模板xml文檔================================File docxFile = new File(base_path+docxTemplate);if(!docxFile.exists()){docxFile.createNewFile();}ZipFile zipFile = new ZipFile(docxFile);Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(output_path+output_file_name));int len = -1;byte[] buffer = new byte[1024];//------------------追加新圖片------------------
// List<String> picList = new ArrayList<>();Map<String,String> picFiles = (Map<String, String>) dataMap.get("picFiles");if(picFiles!=null && !picFiles.isEmpty()){for(String fileName :picFiles.keySet()){ZipEntry next = new ZipEntry("word"+File.separator+"media"+File.separator+fileName);zipout.putNextEntry(new ZipEntry(next.toString()));InputStream in = new FileInputStream(picFiles.get(fileName));while ((len = in.read(buffer)) != -1) {zipout.write(buffer, 0, len);}in.close();}}//------------------追加新圖片------------------len = -1;while (zipEntrys.hasMoreElements()) {ZipEntry next = zipEntrys.nextElement();InputStream is = zipFile.getInputStream(next);// 把輸入流的文件傳到輸出流中 如果是word/document.xml由我們輸入zipout.putNextEntry(new ZipEntry(next.toString()));System.out.println(">>>>>>>>>"+next.isDirectory());System.out.println(">>>>>>>>>>>>>>>>>"+next.toString());System.out.println(">>>>>>>>>>>>>>>>>"+next.isDirectory());if ("word/document.xml".equals(next.toString())) {InputStream in = new FileInputStream(xmlFile);while ((len = in.read(buffer)) != -1) {zipout.write(buffer, 0, len);}in.close();} else if(next.toString().indexOf("document.xml.rels")>0){InputStream in = new FileInputStream(xmlConfigFile);while ((len = in.read(buffer)) != -1) {zipout.write(buffer, 0, len);}in.close();}else{while ((len = is.read(buffer)) != -1) {zipout.write(buffer, 0, len);}is.close();}}zipout.close();} catch (Exception e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}}public static String getFreemarkerContent(Map dataMap, String templateName,String temp_path){String ret_str = "";try {//創建配置實例Configuration configuration = new Configuration();//設置編碼configuration.setDefaultEncoding("UTF-8");//ftl模板文件統一放至 com.lun.template 包下面
// configuration.setDirectoryForTemplateLoading(new File("D:/idea_workspace/alarm/alarm/src/main/resources/template/"));configuration.setClassForTemplateLoading(FreemarkerWordUtils.class,temp_path);//獲取模板Template template = configuration.getTemplate(templateName);//輸出文件//File outFile = new File(filePath);//如果輸出目標文件夾不存在,則創建
// if (!outFile.getParentFile().exists()){
// outFile.getParentFile().mkdirs();
// }//將模板和數據模型合并生成文件
// Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));StringWriter swriter = new StringWriter();//生成文件template.process(dataMap, swriter);ret_str = swriter.toString();} catch (Exception e) {e.printStackTrace();}return ret_str;}/*** 刪除文件* @param listFiles*/public static void delFiles(List<String> listFiles){if(listFiles!=null && !listFiles.isEmpty()){for(String file_temp_path:listFiles){File file_temp = new File(file_temp_path);if(file_temp.exists()){file_temp.delete();}}}}
輸出具體的docx文檔。
項目地址:https://gitee.com/wahnn/JavaUtilsProject
主工具類是:
https://gitee.com/wahnn/JavaUtilsProject/blob/master/src/main/java/com/sl/utils/office/word/WordUtils.java
總結
以上是生活随笔為你收集整理的java利用Freemarker模板生成格式友好的doc或者docx文档的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。