执法文书打印的实现(二):基于freemaker技术生成可打印的word文档
執法文書打印的實現(二)
????基于freemaker技術生成可打印的word文檔:
? ? 基于FreeMarker生成word.doc文檔是一項比較成熟的技術。前承上篇博客(),這個方案只能在windows下部署,不支持linux。這方面的示例網上已經很多了,我也簡單上下代碼好了(深入的話,我也不了解(汗)。
? ? 略過樣例測試,首先需要確定word模板。比如: 現場檢查筆錄.doc ,打開文件,把需要替換的內容加上標記 格式:${插值},并設置好頁眉等樣式:
? ? 其次:將word模板另存為xml 2003,并用xml編輯器打開,這里推薦使用XMLSPY ,這個工具打開xml的顯示易于查找和編輯。打開xml,編輯word另存為后插值分開的部分,重新合并(這個在上篇博客已經詳細描述,這里就不贅述了)。
最后把xcjc.xml修改為xcjc.ftl,模板文件也就準備好了,下面就需要添加具體的java代碼。
?
在項目中導入對應的jar包,書寫生成word.docx文檔的方法:
?
public String createWord(Map dataMap,String templateName){String fileName=UUID.randomUUID().toString()+".docx";try {//創建配置實例 Configuration configuration = new Configuration(Configuration.VERSION_2_3_21);//設置編碼configuration.setDefaultEncoding("UTF-8");//ftl模板文件統一放至com.sinosoft.zhifa.common.commonPrint.ftlFile.包下面//configuration.setClassForTemplateLoading(PrintUtil.class,"/com/sinosoft/zhifa/common/commonPrint/ftlFile/");//這種方法取不到已修改的模板//設置從文件系統中加載模板 ftlFilePath文件在系統的路徑configuration.setDirectoryForTemplateLoading(new File(ftlFilePath));//獲取模板 Template template = configuration.getTemplate(templateName);//輸出文件 File.separator分隔符unix為/ window為\\File outFile = new File(wordFilePath+File.separator+fileName);//如果輸出目標文件夾不存在,則創建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();}return fileName;} 生成word?
其中,dataMap是要替換的數據map,這個map的key是模板的插值,value是具體的數據,而且value不能為null,下面是示例:
?
Map dataMap=new HashMap();dataMap.put("被檢查單位",(String)scenMap.get("ENT_NAME")==null?" ":(String)scenMap.get("ENT_NAME"));//ENT_NAME 北京恩彼凱化肥廠dataMap.put("營業執照",(String)scenMap.get("BUSINESS_LICENSE")==null?" ":(String)scenMap.get("BUSINESS_LICENSE"));//BUSINESS_LICENSE 這是我們的營業執照BUSINESS_LICENSE 這是我們的營業執照dataMap.put("編號",(String)scenMap.get("BUSINESS_LICENSE_ID")==null?" ":(String)scenMap.get("BUSINESS_LICENSE_ID"));//BUSINESS_LICENSE_ID xxxxxxxdataMap.put("組織機構代碼",(String)scenMap.get("ORGANIZATION_CODE")==null?" ":(String)scenMap.get("ORGANIZATION_CODE"));//ORGANIZATION_CODE 123123412384組織機構代碼dataMap.put("地址",(String)scenMap.get("ILLEGALACT_ADDRESS")==null?" ":(String)scenMap.get("ILLEGALACT_ADDRESS"));//ILLEGALACT_ADDRESS 北京市朝陽區霄云路dataMap.put("電話",(String)scenMap.get("ILLEGALACT_PHONE")==null?" ":(String)scenMap.get("ILLEGALACT_PHONE"));//ILLEGALACT_PHONE 13366009185dataMap.put("法定代表人",(String)scenMap.get("LEGAL_REPRESENTATIVE")==null?" ":(String)scenMap.get("LEGAL_REPRESENTATIVE"));//LEGAL_REPRESENTATIVE 法定負責人dataMap.put("性別",(String)scenMap.get("GENDER")==null?" ":(String)scenMap.get("GENDER"));//GENDER 男dataMap.put("職務",(String)scenMap.get("DUTY")==null?" ":(String)scenMap.get("DUTY"));//DUTY 總經理 datamap示例?
?
?
? ? 由于插值{現場檢查}是一個富文本,需要圖文混排,我在這里是解析數據庫的html的標簽,根據需要向xcjc.ftl添加插值,并向dataMap中寫入對應的key、value:
? ?解析html中的圖片并調用修改ftl的方法:
? ? ? ? ? ? ? //用圖片分割后的富文本
???? ???????? String [] imgs=inspection.split("<img\\s+[^>]*/>|<img\\s+[^>]*>[^<]*</img>");
???? ???????? //如果有圖片,則重新生成ftl文件
???? ???????? XmlUtils xmlutils=new XmlUtils(getRequest());
???? ???? ???? Map newMap=xmlutils.xmlHandle("xcjc_copy.xml",imgs,pictList);
? ? 修改ftl的具體實現:
public Map xmlHandle(String xmlfilepath, String[] imgs,List<String> pictList) {Map<String, String> pictMap = new HashMap<String, String>();DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();try {DocumentBuilder db = dbf.newDocumentBuilder();File file = new File(ftlFilePath + fileS + xmlfilepath);document = db.parse(file);NodeList nodelist = document.getElementsByTagName("w:p");Node baseNode = null;// 基于此節點添加節點信息Node parentNode = null;// 在此節點下添加節點信息for (int i = 0; i < nodelist.getLength(); i++) {baseNode = nodelist.item(i);Short eNode = Node.ELEMENT_NODE;// 節點類型是節點,并且節點id:basewpif (eNode.equals(baseNode.getNodeType())&& "basewp".equalsIgnoreCase(((Element) baseNode).getAttribute("id"))) {parentNode = baseNode.getParentNode();break;}if (i == nodelist.getLength() - 1) {System.out.println("沒有找到指定類型的節點");return null;}}Map dataMap = new HashMap<String, String>();int pictNum = 0;// 拼裝要插入的xml節點:富文本是圖文并排,需要多次插入:解析這個富文本的工作要做,數據庫存儲的是html,需要的是純文本+圖片for (int i = 0; i < imgs.length; i++) {if (imgs[i] != null) {String xcjqText = imgs[i].replaceAll("<[^<>]*>|<|>", "");// 添加文本標簽// 給文本標簽模板賦值Node node = null;node = XmlUtils.getextNode("檢查情況文本"+i);parentNode.insertBefore(node, baseNode);pictMap.put("檢查情況文本"+i,xcjqText);}if (pictList.size() > pictNum) {// 解析圖片:圖片寬高String pictId = null;String pictWidth = null;String pictHeight = null;Pattern pt = Pattern.compile("http:[^\"']*");// 圖片鏈接// http:/i/eg_mouse.jpg?id=xxxxxMatcher m = pt.matcher(pictList.get(pictNum));while (m.find()) {pictId = m.group().split("=")[1];// 圖片UUID }Pattern ptw = Pattern.compile("width(:|=)\"?\\d*");Matcher mw = ptw.matcher(pictList.get(pictNum));while (mw.find()) {pictWidth = mw.group().split("=\"?|:")[1];// 圖片寬度數字部分 }Pattern pth = Pattern.compile("height(:|=)\"?\\d*");Matcher mh = pth.matcher(pictList.get(pictNum));while (mh.find()) {pictHeight = mh.group().split("=\"?|:")[1];// 圖片高度數字部分 }// 請求圖片數據轉String(數據庫或文件系統),請求失敗則不添加圖片標簽,go on// 要返回圖片的備用寬度,高度,如果從img標簽中取到,則不用這個寬高,否則使用String pictD[] = this.getBase64PictStr(pictId);if (pictWidth == null) {pictWidth = pictD[0];pictHeight = pictD[1];}// 給圖片模板賦值// pt=px乘以3/4。String pictW = Integer.parseInt(pictWidth) * 3 / 4 + "";String pictH = Integer.parseInt(pictHeight) * 3 / 4 + "";String puuid = "現場檢查"+pictNum;//UUID.randomUUID().toString() 不能使用uuid其中的字符會被ftl模板錯誤解析pictMap.put(puuid, pictD[2]);// 添加圖片標簽Node node = null;node = XmlUtils.getPicNode(puuid, pictW, pictH,(pictNum+1+""));parentNode.insertBefore(node, baseNode);pictNum++;if (i == imgs.length - 1 && pictNum < pictList.size() - 1) {// 繼續添加圖片 }}}// 利用transformer對象將修改后的文檔重新輸出TransformerFactory tFactory = TransformerFactory.newInstance();Transformer transformer = tFactory.newTransformer();DOMSource source = new DOMSource(document);// 將xml文檔保存為ftlStreamResult result = new StreamResult(new java.io.File(ftlFilePath+ File.separator + "xcjc_copy.ftl"));transformer.transform(source, result);} catch (ParserConfigurationException e) {// TODO 自動生成的 catch 塊// e.printStackTrace();System.out.println("xml配置有錯誤:ParserConfigurationException");} catch (SAXException e) {// TODO 自動生成的 catch 塊// e.printStackTrace();System.out.println("解析文件xml內容失敗");} catch (IOException e) {// TODO 自動生成的 catch 塊// e.printStackTrace();System.out.println(e + "讀取文件失敗");} catch (TransformerConfigurationException e) {// TODO 自動生成的 catch 塊// e.printStackTrace();System.out.println("轉換對象創建失敗");} catch (TransformerException e) {// TODO 自動生成的 catch 塊// e.printStackTrace();System.out.println("輸出文件失敗");}return pictMap;} xmlHandle?
?
? ? 在這個實現中,調用了2個私有方法,分別是添加文本節點:getextNode和添加圖片節點:getPicNode,其中圖片數據必須是base64碼的:getBase64PictStr
static Node getPicNode(String PictWordID, String picWidth, String picHeight,String picID) {// 一級節點// wp 節點及屬性Element wpe = document.createElement("w:p");wpe.setAttribute("wsp:rsidR", "00172C3B");wpe.setAttribute("wsp:rsidRDefault", "00B7682D");wpe.setAttribute("wsp:rsidP", "00172C3B");// 二級節點Element wppre = document.createElement("w:pPr");Element wre = document.createElement("w:r");wre.setAttribute("wsp:rsidRPr", "00974FA3");wpe.appendChild(wppre);wpe.appendChild(wre);// 三級節點Element wwindowcontrole = document.createElement("w:widowControl");Element wjce = document.createElement("w:jc");wjce.setAttribute("w:val", "left");Element wrpre = document.createElement("w:rPr");Element wrpre2 = document.createElement("w:rPr");Element wpicte = document.createElement("w:pict");wppre.appendChild(wwindowcontrole);wppre.appendChild(wjce);wppre.appendChild(wrpre);wre.appendChild(wrpre2);wre.appendChild(wpicte);// 四級節點:處理方式改為順序Element wrFontse = document.createElement("w:rFonts");wrFontse.setAttribute("w:ascii", "宋體");wrFontse.setAttribute("w:h-ansi", "宋體");wrFontse.setAttribute("w:cs", "宋體");wrpre.appendChild(wrFontse);Element wxfonte = document.createElement("wx:font");wxfonte.setAttribute("wx:val", "宋體");wrpre.appendChild(wxfonte);Element wkerne = document.createElement("w:kern");wkerne.setAttribute("w:val", "0");wrpre.appendChild(wkerne);Element wsze = document.createElement("w:sz");wsze.setAttribute("w:val", "24");wrpre.appendChild(wsze);Element wszcse = document.createElement("w:sz-cs");wszcse.setAttribute("w:val", "24");wrpre.appendChild(wszcse);Element wnoProof = document.createElement("w:noProof");wrpre2.appendChild(wnoProof);Element vshapetype = document.createElement("v:shapetype");vshapetype.setAttribute("id", "_x0000_t75");// //v:strokevshapetype.setAttribute("coordsize", "21600,21600");vshapetype.setAttribute("o:spt", "75");vshapetype.setAttribute("o:preferrelative", "t");vshapetype.setAttribute("path", "m@4@5l@4@11@9@11@9@5xe");vshapetype.setAttribute("filled", "f");vshapetype.setAttribute("stroked", "f");wpicte.appendChild(vshapetype);Element vstroke = document.createElement("v:stroke");vstroke.setAttribute("joinstyle", "miter");vshapetype.appendChild(vstroke);Element vformulas = document.createElement("v:formulas");vshapetype.appendChild(vformulas);Element vf = document.createElement("v:f");vf.setAttribute("eqn", "if lineDrawn pixelLineWidth 0");vformulas.appendChild(vf);Element vf2 = document.createElement("v:f");vf2.setAttribute("eqn", "sum @0 1 0");vformulas.appendChild(vf2);Element vf3 = document.createElement("v:f");vf3.setAttribute("eqn", "sum 0 0 @1");vformulas.appendChild(vf3);Element vf4 = document.createElement("v:f");vf4.setAttribute("eqn", "prod @2 1 2");vformulas.appendChild(vf4);Element vf5 = document.createElement("v:f");vf5.setAttribute("eqn", "prod @3 21600 pixelWidth");vformulas.appendChild(vf5);Element vf6 = document.createElement("v:f");vf6.setAttribute("eqn", "prod @3 21600 pixelHeight");vformulas.appendChild(vf6);Element vf7 = document.createElement("v:f");vf7.setAttribute("eqn", "sum @0 0 1");vformulas.appendChild(vf7);Element vf8 = document.createElement("v:f");vf8.setAttribute("eqn", "prod @6 1 2");vformulas.appendChild(vf8);Element vf9 = document.createElement("v:f");vf9.setAttribute("eqn", "prod @7 21600 pixelWidth");vformulas.appendChild(vf9);Element vf10 = document.createElement("v:f");vf10.setAttribute("eqn", "sum @8 21600 0");vformulas.appendChild(vf10);Element vf11 = document.createElement("v:f");vf11.setAttribute("eqn", "prod @7 21600 pixelHeight");vformulas.appendChild(vf11);Element vf12 = document.createElement("v:f");vf12.setAttribute("eqn", "sum @10 21600 0");vformulas.appendChild(vf12);Element vpath = document.createElement("v:path");vpath.setAttribute("o:extrusionok", "f");vpath.setAttribute("gradientshapeok", "t");vpath.setAttribute("o:connecttype", "rect");vshapetype.appendChild(vpath);Element olock = document.createElement("o:lock");olock.setAttribute("v:ext", "edit");olock.setAttribute("aspectratio", "t");vshapetype.appendChild(olock);Element wbinData = document.createElement("w:binData");wbinData.setAttribute("w:name", "wordml://0300000"+picID+".png");//修改圖片的src和w:name解決只加載第一張圖片的問題wbinData.setAttribute("xml:space", "preserve");wpicte.appendChild(wbinData);Text pictText = document.createTextNode("${" + PictWordID + "}");// 這兒可以添加圖片定位參數 wbinData.appendChild(pictText);Element vshape = document.createElement("v:shape");// 指定圖片id和寬高 vshape.setAttribute("id", PictWordID);//圖片id需要動態傳值,多個圖片現在只加載同一個vshape.setAttribute("o:spid", "_x0000_i1028");vshape.setAttribute("type", "#_x0000_t75");// picWidth// vshape.setAttribute("style","width:358.4pt;height:535.7pt;visibility:visible;mso-wrap-style:square");vshape.setAttribute("style", "width:" + picWidth + "pt;height:"+ picHeight + "pt;visibility:visible;mso-wrap-style:square");Element vimagedata = document.createElement("v:imagedata");vimagedata.setAttribute("src", "wordml://0300000"+picID+".png");vimagedata.setAttribute("o:title", "");vshape.appendChild(vimagedata);wpicte.appendChild(vshape);return wpe;} getPicNode?
static Node getextNode(String wordtext1) {// 一級節點// wp 節點及屬性Element wpe = document.createElement("w:p");wpe.setAttribute("wsp:rsidP", "008027B0");wpe.setAttribute("wsp:rsidR", "008027B0");wpe.setAttribute("wsp:rsidRDefault", "008027B0");wpe.setAttribute("wsp:rsidRPr", "006B689C");// 二級節點及屬性Element wpPr = document.createElement("w:pPr");Element wr = document.createElement("w:r");wr.setAttribute("wsp:rsidRPr", "006B689C");wpe.appendChild(wpPr);wpe.appendChild(wr);// 三級節點 順序添加//wppr節點及子節點Element wspacing = document.createElement("w:spacing");wspacing.setAttribute("w:line", "500");wspacing.setAttribute("w:line-rule", "exact");wpPr.appendChild(wspacing);Element wrPr = document.createElement("w:rPr");wpPr.appendChild(wrPr);Element wrFonts = document.createElement("w:rFonts");wrFonts.setAttribute("w:ascii", "仿宋_GB2312");wrFonts.setAttribute("w:cs", "仿宋_GB2312");wrPr.appendChild(wrFonts);Element wxfont = document.createElement("wx:font");wxfont.setAttribute("wx:val", "仿宋_GB2312");wrPr.appendChild(wxfont);Element wu = document.createElement("w:u");//和下面的代碼一起控制文字下面是否有下劃線wu.setAttribute("w:val", "single");//這里設置下劃線為單線 wrPr.appendChild(wu);//wr節點及子節點Element wrPr1 = document.createElement("w:rPr");wr.appendChild(wrPr1);Element wrFonts1 = document.createElement("w:rFonts");wrFonts1.setAttribute("w:ascii", "仿宋_GB2312");wrFonts1.setAttribute("w:cs", "仿宋_GB2312");wrPr1.appendChild(wrFonts1);Element wxfont1 = document.createElement("wx:font");wxfont1.setAttribute("wx:val", "仿宋_GB2312");wrPr1.appendChild(wxfont1);Element wu1 = document.createElement("w:u");//和下面的代碼一起控制文字下面是否有下劃線wu1.setAttribute("w:val", "single");//這里設置下劃線為單線 wrPr1.appendChild(wu1);Element wt = document.createElement("w:t");//創建要插入文本的節點Text wordtext=document.createTextNode("${" + wordtext1 + "}");//要插入文本的標記 wt.appendChild(wordtext);wr.appendChild(wt);return wpe;} getextNode public String[] getBase64PictStr(String pictID) {byte[] data = null;String[] wh = new String[3];Connection conn;Statement stmt = null;PreparedStatement ps = null;ResultSet rs = null;// 這個sql應該是動態獲取的String sql = "select image from picc where id='"+pictID+"'";//2e30826eba714a909758c2bfff8f4875DataSource dataSource = DataSourceFactory.defaultFactory.getDataSource("dataSource");try {conn = dataSource.getConnection();stmt = conn.createStatement();rs = stmt.executeQuery(sql);if (rs.next()) {Blob blob = rs.getBlob("image");// IMAGEdata = blob.getBytes(1, (int) blob.length());BufferedImage bis = ImageIO.read(new ByteArrayInputStream(data));int wid = bis.getWidth();wh[0] = wid + "";int hei = bis.getHeight();wh[1] = hei + "";BASE64Encoder encoder = new BASE64Encoder();String str = encoder.encode(data);wh[2] = str;// 編碼后的圖片字符串// System.out.println(str); }} catch (SQLException e1) {e1.printStackTrace();System.out.println("創建數據庫連接失敗");} catch (IOException e) {System.out.println("轉換圖片失敗");// e.printStackTrace(); }return wh;} getBase64PictStr? ? ?下一篇博客要寫下word轉pdf/png的方法,jodconver這個jar包用過2個版本,3.0的很不成熟,不推薦。這個方法生成word現在沒有在項目中使用,有問題互相探討。
轉載于:https://www.cnblogs.com/chonghua/p/4198325.html
總結
以上是生活随笔為你收集整理的执法文书打印的实现(二):基于freemaker技术生成可打印的word文档的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于VHDL的全自动洗衣机控制器设计
- 下一篇: LC并联谐振电路的原理