位置:首页 » 文章/教程分享 » POI不同版本替换Word模板时的问题

一、问题描述

通过POI,把Word中的占位符替换为实际的值,以生成复杂结构的业务报告。

在POI 3.9上,功能正常。由于某些原因升级到POI 3.10.1后,项目组反馈说Word模板出错,无法生成Word文件,总是报解析错误。

 

二、问题分析

Word模板功能相关的代码应该说是比较稳定了,相关代码很久没有变动过,而且已经有投产项目在正式使用。现在出了问题,应该是升级POI版本导致的。

Word模板内容示例:

本期产品为向${ds:ds001,col:INVESTER_TYPE_NAME}发行的混合类理财产品,本期产品投资期限为${ds:ds001,col:TERM}天,收益率为${ds:ds001,col:YTM_100}%/年,为${ds:ds001,col:INCOME_TYPE_NAME}类产品,到期还本付息。是一款具有投资安全性高、回报率高重点的理财产品。

分析、调试代码。发现两个版本的POI在处理Paragraph.getRuns()有区别:

3.9版本:一个段落就是一个XWPFRun;

3.10.1版本:一个段落不知道根据什么规则,胡乱分成了List<XWPFRun>。如上述示例模板,会被切换为长度为14的List;

这样就导致获取、替换段落文本时出错。

 

三、问题解决

问题被定位后,就尝试解决。主要的思路,就是强制把List中的内容合并成一个字符串,替换内容后,把段落中的XWPFRun全部remove掉,然后新建一个含有替换后内容的XPWFRun,并赋给当前段落。

解决问题的过程中,“对于removeRun方法无法达到本应达成的预期效果的问题”,耗费了不少时间。总结来说:不能从0到size()移除Run,这样的话Run不会被移除;而应该从size()到0进行移除。

需要继续关注表格替换时是否会有问题。

解决这类第三方软件引起的问题,几乎没有道理可言,如果不想被埋在相关源代码中,只能靠经验+运气。

 

四、附代码

在3.10.1下有问题的代码示意:

while (itPara.hasNext()) {

    XWPFParagraph paragraph = (XWPFParagraph) itPara.next();

   int length = paragraph.getRuns().size();

  if (length > 0) {

        String text = paragraph.getText();

        if (text.indexOf(tag) < 0) {

      continue;

        }

        while (length-- > 0) {

      paragraph.removeRun(0);

        }

        XWPFRun newrun = paragraph.insertNewRun(0);

        newrun.setText(text.replace(tag, val));

    }

}

修改后的代码示意:

while (itPara.hasNext()) {

     XWPFParagraph paragraph = (XWPFParagraph) itPara.next();

     int length = paragraph.getRuns().size();

    if (length > 0) {

        String text = StringUtils.join(paragraph.getRuns().toArray());

         if (text.indexOf(tag) < 0) {

    continue;

        }

        for (int i = (length - 1); i >= 0; i--) {

    paragraph.removeRun(i);

        }

        XWPFRun newRun = paragraph.insertNewRun(0);

        text = text.replaceAll(tag, val);

        newRun.setText(text, 0);

    }

}