一、起因
這幾天在做電子簽章問題,要通過替換docx文件中的占位符生成包含業務數據的合同數據,再轉換成html文件,轉換成pdf文件。遇到的問題是:通過apache poi轉換docx到html時,原生的表格文件可以正常顯示,但是我通過代碼生成的表格只有數據,而不展示邊框。
二、問題分析
google了一下發現有人碰到過類似問題,但是沒有找到解決方法。現成的沒有只能自己研究。
貼上簡單的填充表格內容的java代碼
1 private void replaceTable(XWPFDocument xdoc, List<List<String>> lines, int pos) { 2 if (CollectionUtils.isEmpty(lines)) { 3 List<String> th = new ArrayList<String>(); 4 th.add("姓名"); 5 th.add("身份證"); 6 th.add("金額"); 7 lines.add(th); 8 } 9 XWPFTable replace = xdoc.createTable(lines.size(), lines.get(0).size()); 10 CTTbl cttbl = replace.getCTTbl(); 11 cttbl.addNewTblPr().addNewTblW().setW(BigInteger.valueOf(8800)); 12 CTTblGrid cg = cttbl.addNewTblGrid(); 13 cg.addNewGridCol().setW(BigInteger.valueOf(2500)); 14 cg.addNewGridCol().setW(BigInteger.valueOf(3800)); 15 cg.addNewGridCol().setW(BigInteger.valueOf(2500)); 16 if (CollectionUtils.isNotEmpty(lines)) { 17 for (int i = 0; i < lines.size(); i++) { 18 List<String> line = lines.get(i); 19 for (int j = 0; j < line.size(); j++) { 20 XWPFTableCell cell = replace.getRow(i).getCell(j); 21 cell.setText(line.get(j)); 22 cell.getCTTc().addNewTcPr().addNewTcBorders().addNewTop(); 23 } 24 } 25 } 26 xdoc.setTable(pos, replace); 27 xdoc.removeBodyElement(xdoc.getPosOfTable(replace)); 28 }
邏輯很簡單,通過生成一個新的表格來替換原來的表格。
然后看一下可正常顯示的表格的doc xml代碼
1 <xml-fragment xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"> 2 <w:tblPr> 3 <w:tblW w:w="0" w:type="auto"/> 4 <w:tblBorders> 5 <w:top w:val="single" w:sz="4" w:space="0" w:color="auto"/> 6 <w:left w:val="single" w:sz="4" w:space="0" w:color="auto"/> 7 <w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto"/> 8 <w:right w:val="single" w:sz="4" w:space="0" w:color="auto"/> 9 <w:insideH w:val="single" w:sz="4" w:space="0" w:color="auto"/> 10 <w:insideV w:val="single" w:sz="4" w:space="0" w:color="auto"/> 11 </w:tblBorders> 12 <w:tblLook w:val="04A0" w:firstRow="1" w:lastRow="0" w:firstColumn="1" w:lastColumn="0" w:noHBand="0" w:noVBand="1"/> 13 </w:tblPr> 14 <w:tblGrid> 15 <w:gridCol w:w="1984"/> 16 <w:gridCol w:w="2694"/> 17 <w:gridCol w:w="2885"/> 18 </w:tblGrid> 19 <w:tr w:rsidR="00D347DE" w:rsidRPr="00A709A0" w14:paraId="47BBA15B" w14:textId="77777777" w:rsidTr="00146A0B"> 20 <w:tc> 21 <w:tcPr> 22 <w:tcW w:w="1984" w:type="dxa"/> 23 </w:tcPr> 24 <w:p> 25 <w:pPr> 26 <w:jc w:val="center"/> 27 </w:pPr> 28 <w:r> 29 <w:t>${表格匹配信息}</w:t> 30 </w:r> 31 </w:p> 32 </w:tc> 33 <w:tc> 34 <w:tcPr> 35 <w:tcW w:w="2694" w:type="dxa"/> 36 </w:tcPr> 37 <w:p> 38 <w:pPr> 39 <w:jc w:val="center"/> 40 </w:pPr> 41 <w:r> 42 <w:t xml:space="preserve"></w:t> 43 </w:r> 44 </w:p> 45 </w:tc> 46 <w:tc> 47 <w:tcPr> 48 <w:tcW w:w="2885" w:type="dxa"/> 49 </w:tcPr> 50 <w:p> 51 <w:pPr> 52 <w:jc w:val="center"/> 53 </w:pPr> 54 <w:r> 55 <w:t xml:space="preserve"></w:t> 56 </w:r> 57 </w:p> 58 </w:tc> 59 </w:tr> 60 </xml-fragment>
然后看一下我們自己生成的替換表格
1 <xml-fragment xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"> 2 <w:tblGrid> 3 <w:gridCol w:w="2500"/> 4 <w:gridCol w:w="3800"/> 5 <w:gridCol w:w="2500"/> 6 </w:tblGrid> 7 <w:tr> 8 <w:tc> 9 <w:p> 10 <w:r> 11 <w:t>姓名</w:t> 12 </w:r> 13 </w:p> 14 </w:tc> 15 <w:tc> 16 <w:p> 17 <w:r> 18 <w:t>身份證</w:t> 19 </w:r> 20 </w:p> 21 </w:tc> 22 <w:tc> 23 <w:p> 24 <w:r> 25 <w:t>金額</w:t> 26 </w:r> 27 </w:p> 28 </w:tc> 29 </w:tr> 30 <w:tr> 31 <w:tc> 32 <w:p> 33 <w:r> 34 <w:t>小七</w:t> 35 </w:r> 36 </w:p> 37 </w:tc> 38 <w:tc> 39 <w:p> 40 <w:r> 41 <w:t>12345</w:t> 42 </w:r> 43 </w:p> 44 </w:tc> 45 <w:tc> 46 <w:p> 47 <w:r> 48 <w:t>888888.00</w:t> 49 </w:r> 50 </w:p> 51 </w:tc> 52 </w:tr> 53 <w:tr> 54 <w:tc> 55 <w:p> 56 <w:r> 57 <w:t>合計筆數:1</w:t> 58 </w:r> 59 </w:p> 60 </w:tc> 61 <w:tc> 62 <w:p> 63 <w:r> 64 <w:t/> 65 </w:r> 66 </w:p> 67 </w:tc> 68 <w:tc> 69 <w:p> 70 <w:r> 71 <w:t>合計:888888.00</w:t> 72 </w:r> 73 </w:p> 74 </w:tc> 75 </w:tr> 76 </xml-fragment>
可以很明顯的看出,我們自己生成的表格在屬性和元素數量上都比正常表格少了很多。
三、解決方法
好在apache的代碼設計結構清晰,十分優美,彌補了資料較少的不足。剛開始我是想參考正常表格手動補全缺少的內容,后來發現這樣的工作量大不說,補出來的東西多多少少還是和正常結構有差,還是沒法正常顯示,后來發現了XMLObject這個類有一個set方法,可以通過這個方法直接復制正常表格的內容。
最終的代碼就是這樣
1 private void replaceTable(XWPFDocument xdoc, List<List<String>> lines, int pos, XWPFTable table) throws XmlException { 2 if (CollectionUtils.isEmpty(lines)) { 3 List<String> th = new ArrayList<String>(); 4 th.add("姓名"); 5 th.add("身份證"); 6 th.add("金額"); 7 if (lines == null) { 8 lines = new ArrayList<List<String>>(); 9 } 10 lines.add(th); 11 } 12 XWPFTable replace = xdoc.createTable(lines.size(), lines.get(0).size()); 13 CTTbl cttbl = replace.getCTTbl(); 14 15 cttbl.getTblPr().set(table.getCTTbl().getTblPr()); 16 17 CTTblGrid cg = cttbl.addNewTblGrid(); 18 cg.addNewGridCol().setW(BigInteger.valueOf(2500)); 19 cg.addNewGridCol().setW(BigInteger.valueOf(3800)); 20 cg.addNewGridCol().setW(BigInteger.valueOf(2500)); 21 22 CTRow originalRow = table.getCTTbl().getTrArray(0); 23 if (CollectionUtils.isNotEmpty(lines)) { 24 for (int i = 0; i < lines.size(); i++) { 25 List<String> line = lines.get(i); 26 CTRow ctRow = cttbl.getTrArray(i); 27 ctRow.set(originalRow); 28 for (int j = 0; j < line.size(); j++) { 29 CTTc ctTc = ctRow.getTcArray(j); 30 ctTc.removeP(0); 31 CTText text = ctTc.addNewP().addNewR().addNewT(); 32 text.setStringValue(line.get(j)); 33 34 } 35 } 36 } 37 xdoc.setTable(pos, replace); 38 xdoc.removeBodyElement(xdoc.getPosOfTable(replace)); 39 }
