模板生成word文件 By POI+Word書籤功能
剛開始接到生成文件的時候,我的內心是拒絕的,腦海裡回想起了苦痛挪位置調畫素的jasper,和不停add各種style的POI。但是這個模組都歸我~~~老子說了算趕緊上網搜搜有沒什麼easy way。看到挺多人說起FreeMarker,大略一看So easy啊,只要做好一個word文件,然後~~ 準備馬上學起來。
但是預先設定的方向是用POI,我提出FreeMarker之後,被指出用來後續需要的動態生成會變得複雜。
同時,他們給出了一個demo(也是網上找到的,不是我找的所以無法附上鍊接,抱歉啦),可以結合word的書籤功能實現我想要的效果。
不過實驗之後有一個需求[一個單元格內有多段資料]滿足不了。於是新增了一個方法,在此分享一把。應該可以滿足大部分生成文件的需求了~再也不用畫報表了有沒有很開心~
原Demo是這樣的
這個需求第一反應是用public void replaceBookMark(Map<String,String> indicator)方法來做,但是結果把文件替換的一團亂...
我剛開始想到的思路有三種(嘗試優先順序如下)
1. 研究一下replaceBookMark裡究竟發生了什麼事
根本搞不懂其中的insertTextAtBookMark怎麼回事,也沒什麼思路,很快就放棄啦╮(╯▽╰)╭
歡迎有研究精神的小夥伴們告知:)
2.改replaceText 通過查詢子字串 替換之
3.遍歷找出w:t 比較替換
其實最終的解決方法是2和3 的結合體
在replaceText(String bookMarkName, Map<String,String> bookmarkMap)方法中改動替換文字的方法
//獲到改行的所有單元格 List<XWPFTableCell> cells = row.getTableCells(); for(XWPFTableCell c : cells){ List<XWPFParagraph> paragraphs = c.getParagraphs(); for(XWPFParagraph paragraph : paragraphs){ for(Entry<String,String> e : bookmarkMap.entrySet()){ // if(c.getText().equals(e.getKey())){ // // //刪掉單元格內容 // c.removeParagraph(0); // // //給單元格賦值 // c.setText(e.getValue()); // } // else if(paragraph.getText().contains(e.getKey())){ c.replaceParagraphText(paragraphs.indexOf(paragraph), e); } } } }
另外在XWPFTableCell中增加一個方法 以獲得<w:t>直接對String操作
public void replaceParagraphText(final int paragraphPos, final Entry<String,String> text) throws IndexOutOfBoundsException {
if(this.ctTc.sizeOfPArray() < paragraphPos){
throw new IndexOutOfBoundsException();
}
final CTP ctP = this.ctTc.getPArray(paragraphPos);
final XWPFParagraph par = new XWPFParagraph(ctP, this);
List<XWPFRun> runs = par.getRuns();
for(XWPFRun run : runs){
for(int i = 0; i < run.getCTR().sizeOfTArray(); i++){
if(run.getText(i).equals(text.getKey())){
String replaceBy = run.getText(i).replaceAll(text.getKey(), text.getValue());
run.setText(replaceBy, i);
}
}
}
}
不過還有一些覺得不可思議的奇怪現象沒搞懂
比如XWPFTableCell的getText... get出來的並不是最後能看到的整個單元格的內容 但是程式碼還沒看出瑕疵 覺得都很有道理啊
有不是互不包含的字串組 但竟然全都各歸其位平安的完成了替換
...
同志整理完思路繼續努力去啦 白白