POI批量替换world文档XWPFParagraph.getRuns 出现分段混乱

简介: POI批量替换world文档XWPFParagraph.getRuns 出现分段混乱

问题:在操作POI替换world时发现getRuns将我们预设的${product}自动切换成了

  ${product, }]
${product  }
成了两个部分

解决方法一。(未尝试)

强制把List中的内容合并成一个字符串,替换内容后,把段落中的XWPFRun全部remove掉,然后新建一个含有替换后内容的XPWFRun,并赋给当前段落。

解决方法二.

请用复制粘贴把你的${product}添加进world文档里面即可解决,不要手打 目前发现复制粘贴是没有问题的,感觉像是poi的一个bug不知道立贴为证。

注意:${这里尽量不要存中文,否在还出现上面情况}

下面上代码:

public class WorldUtil {
    public static String doc2String2() {
      try {
        WorldUtil wd = new WorldUtil();
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("reportDate", "2014-02-28");
/*        params.put("appleAmt", "100.00");
        params.put("bananaAmt", "200.00");
        params.put("totalAmt", "300.00");*/
        String filePath = "d:\\1.docx";
        InputStream is = new FileInputStream(filePath);
        XWPFDocument doc = new XWPFDocument(is);
        //替换段落里面的变量  
        wd.replaceInPara(doc, params);
        //替换表格里面的变量  
        wd.replaceInTable(doc, params);
        OutputStream os = new FileOutputStream("d:\\sample.docx");
        doc.write(os);
        wd.close(os);
        wd.close(is);
      } catch (Exception e) {
        // TODO: handle exception
      }
      return null;
    }
      /**
       * 读取doc文件内容
       * @param file 想要读取的文件对象
       * @return 返回文件内容
       */
      public static String doc2String(){
        try {
          FileInputStream stream = new FileInputStream("d://1.docx");
          XWPFDocument doc = new XWPFDocument(stream);// 创建Word文件
          for(XWPFParagraph p : doc.getParagraphs())//遍历段落
          {
            System.out.println(p.getParagraphText());
          }
          for(XWPFTable table : doc.getTables())//遍历表格
          {
             for(XWPFTableRow row : table.getRows())
             {
               for(XWPFTableCell cell : row.getTableCells())
               {
                 System.out.println(cell.getText());
               }
             }
          }
          FileOutputStream out = new FileOutputStream("d://sample.docx");
          doc.write(out);
          out.close();
          stream.close();
      } catch (Exception e) {
        // TODO: handle exception
      }
      return null;
      }
      /** 
       * 替换段落里面的变量 
       * @param doc 要替换的文档 
       * @param params 参数 
       */  
      private void replaceInPara(XWPFDocument doc, Map<String, Object> params) {  
         Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();  
         XWPFParagraph para;  
         while (iterator.hasNext()) {  
            para = iterator.next();  
            this.replaceInPara(para, params);  
         }  
      }  
      /** 
       * 替换段落里面的变量 
       * @param para 要替换的段落 
       * @param params 参数 
       */  
      private void replaceInPara(XWPFParagraph para, Map<String, Object> params) {  
         List<XWPFRun> runs;  
         Matcher matcher;  
         if (matcher(para.getParagraphText()).find()) {  
            runs = para.getRuns();  
            for (int i=0; i<runs.size(); i++) {
               XWPFRun run = runs.get(i);  
               String runText = run.toString();  
               matcher = matcher(runText);  
               System.out.println(runText);
               if (matcher.find()) { 
                 System.out.println("进1");
                   while ((matcher = this.matcher(runText)).find()) {  
                      runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));  
                   }  
                   //直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面,  
                   //所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。  
                   para.removeRun(i);  
                   para.insertNewRun(i).setText(runText);  
               }  
            }  
         }  
      }  
      /** 
       * 替换表格里面的变量 
       * @param doc 要替换的文档 
       * @param params 参数 
       */  
      private void replaceInTable(XWPFDocument doc, Map<String, Object> params) {  
         Iterator<XWPFTable> iterator = doc.getTablesIterator();  
         XWPFTable table;  
         List<XWPFTableRow> rows;  
         List<XWPFTableCell> cells;  
         List<XWPFParagraph> paras;  
         while (iterator.hasNext()) {  
            table = iterator.next();  
            rows = table.getRows();  
            for (XWPFTableRow row : rows) {  
               cells = row.getTableCells();  
               for (XWPFTableCell cell : cells) {  
                   paras = cell.getParagraphs();  
                   for (XWPFParagraph para : paras) {  
                      this.replaceInPara(para, params);  
                   }  
               }  
            }  
         }  
      }  
      /** 
       * 正则匹配字符串 
       * @param str 
       * @return 
       */  
      private Matcher matcher(String str) {  
         Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);  
         Matcher matcher = pattern.matcher(str); 
         return matcher;  
      }  
      /** 
       * 关闭输入流 
       * @param is 
       */  
      private void close(InputStream is) {  
         if (is != null) {  
            try {  
               is.close();  
            } catch (IOException e) {  
               e.printStackTrace();  
            }  
         }  
      }  
      /** 
       * 关闭输出流 
       * @param os 
       */  
      private void close(OutputStream os) {  
         if (os != null) {  
            try {  
               os.close();  
            } catch (IOException e) {  
               e.printStackTrace();  
            }  
         }  
      }    
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    //doc2String();
    doc2String2();
  }
}
目录
相关文章
|
XML Java API
使用 XDocReport 将 .docx 文件转换为 .pdf 文件
本文介绍如何使用 XDocReport 库在 Java 中将 Word 文件转换为 PDF 文件
6559 0
|
JSON Java 数据格式
有关Java调用第三方接口【Content-type为form-data】的示例代码
有关Java调用第三方接口【Content-type为form-data】的示例代码
1302 0
Apifox测试导出excel接口
Apifox测试导出excel接口
2222 0
|
Java
Java实现图片转化为pdf
Java实现图片转化为pdf
1082 0
|
安全 Java Spring
Spring Boot 过滤器(Filter)详解
本文详解Spring Boot中过滤器的原理与实践,涵盖Filter接口、执行流程、@Component与FilterRegistrationBean两种实现方式、执行顺序控制及典型应用场景如日志记录、权限验证。对比拦截器,突出其在Servlet容器层的通用性与灵活性,助力构建高效稳定的Web应用。
6137 1
|
算法 Java Linux
java制作海报一:java使用Graphics2D 在图片上写字,文字换行算法详解
这篇文章介绍了如何在Java中使用Graphics2D在图片上绘制文字,并实现自动换行的功能。
1064 0
|
消息中间件 NoSQL 架构师
招行面试:亿级秒杀,超卖问题+少卖问题,如何解决?(图解+秒懂+史上最全)
45岁资深架构师尼恩在读者交流群中分享了如何系统化解决高并发下的库存抢购超卖少买问题,特别是针对一线互联网企业的面试题。文章详细解析了秒杀系统的四个阶段(扣库预扣、库存扣减、支付回调、库存补偿),并通过Redis分布式锁和Java代码示例展示了如何防止超卖。此外,还介绍了使用RocketMQ延迟消息和xxl-job定时任务解决少卖问题的方法。尼恩强调,掌握这些技术不仅能提升面试表现,还能增强实际项目中的高并发处理能力。相关答案已收入《尼恩Java面试宝典PDF》V175版本,供后续参考。