刚开始接到生成文档的时候,我的内心是拒绝的,脑海里回想起了苦痛挪位置调像素的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出来的并不是最后能看到的整个单元格的内容 但是代码还没看出瑕疵 觉得都很有道理啊
有不是互不包含的字符串组 但竟然全都各归其位平安的完成了替换
...
同志整理完思路继续努力去啦 白白