前言:报告审批后,要求解析Word批注信息获取 作者、引用正文、批注内容 等信息入库,我这边额外加了回复对象(为后续考虑)

先上代码吧:


/*** @author : weiheng* @version V1.0* @date Date : 2019年08月28日 10:31*/
public class WordComment {/** 批注ID */private String id;/** 回复的目标批注ID(对哪条批注进行回复)*/private String replyFor;/** 批注引用的正文 */private String text;/** 批注内容 */private String comment;/** 批注人 */private String author;public String getId() {return id;}public WordComment setId(String id) {this.id = id;return this;}public String getReplyFor() {return replyFor;}public WordComment setReplyFor(String replyFor) {this.replyFor = replyFor;return this;}public String getText() {return text;}public WordComment setText(String text) {this.text = text;return this;}public String getComment() {return comment;}public WordComment setComment(String comment) {this.comment = comment;return this;}public String getAuthor() {return author;}public WordComment setAuthor(String author) {this.author = author;return this;}
}
import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFComment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.jeecgframework.core.util.FtpUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import java.io.File;
import java.io.IOException;
import java.util.*;/*** Word文件批注解析工具* @author : weiheng* @version V1.0* @date Date : 2019年08月27日 11:24*/
public class WordCommentsParseUtil {/** text ? Word正文内容 */private final String BODY_WT = "w:t";/** picture ? 图片 */private final String BODY_PIC = "wp:docPr";/** 批注开始标识 */private final String BODY_COMMENT_START = "w:commentRangeStart";/** 批注结束标识 */private final String BODY_COMMENT_END = "w:commentRangeEnd";/** 加载远程文件(FTP文件服务器)内容产生的临时文件目录 */private static String usrDir = System.getProperty("user.dir");/** 批注所引用正文装配Map完毕标识 */private boolean commentFilledComplete = false;/** Word document */private XWPFDocument docx = null;/** 批注最大下标 */private int maxCommentIndex;/** 当前批注索引 */private int commentIndex;/** FTP服务器加载到本地的临时文件输出地址 */private String localOutputFile;/** docx数据存储对象 */private OPCPackage opcPackage;/**** 初始化Word(XWPFDocument)文件对象* @param remotePath 远程文件访问路径(文件服务器)* @date 2019-08-27 11:54* @author weiheng*/private void initDocument(String remotePath){try {String filename = remotePath.substring(remotePath.lastIndexOf("/") + 1);localOutputFile = usrDir + "/" + filename;FtpUtils.downloadFileFromFtp(remotePath, localOutputFile);opcPackage = POIXMLDocument.openPackage(localOutputFile);docx = new XWPFDocument(opcPackage);maxCommentIndex = docx.getComments().length - 1;commentIndex = 0;} catch (IOException e) {e.printStackTrace();throw new RuntimeException("初始化文件异常:" + e.getMessage());}}/**** 获取服务器上文件的批注信息(ID、引用正文、批注内容、回复的批注对象)* @param fileRemotePath FTP远程访问路径* @date 2019-08-27 20:41* @author weiheng*/public List<WordComment> getWordCommentsInfo(String fileRemotePath){// 1、初始化 XWPFDocument 对象initDocument(fileRemotePath);// 2、解析正文,获取 批注ID, 批注正文, 批注回复对象IDList<WordComment> comments = new ArrayList<>(10);fillComments(docx.getDocument().getDomNode(), new LinkedList<>(), new HashMap<>(16), comments);// 3、获取批注内容及作者for (WordComment c : comments) {XWPFComment comment = docx.getCommentByID(c.getId());c.setComment(comment.getText()).setAuthor(comment.getAuthor());}// 4、释放连接releaseSource();// 5、删除本地临时文件deleteTempFile();return comments;}/**** 这里一定要释放Word文件的连接,否则临时文件无法删除* @date 2019-08-28 9:59* @author weiheng*/private void releaseSource() {try {if(opcPackage != null) {opcPackage.close();}} catch (IOException e) {e.printStackTrace();}}/**** 删除本地临时文件* @date 2019-08-27 20:41* @author weiheng*/private boolean deleteTempFile(){boolean flag = false;File file = new File(localOutputFile);if(file.isFile() && file.exists()){flag = file.delete();}return flag;}/**** 组装批注引用文本的Map,Map<批注ID, 批注引用的正文>* @param node Word的XML节点* @param ids 批注ID集合* @param values 批注引用的正文文本的集合* @param comments 要填充批注对象集合* @date 2019-08-27 13:54* @author weiheng*/private void fillComments(Node node, LinkedList<String> ids, Map<String, String> values, List<WordComment> comments){if(!insureNotNull(node, ids, values, comments)){throw new IllegalArgumentException(new StringBuilder().append(this.getClass().getName()).append("fillComments(").append(node).append(",").append(ids).append(",").append(values).append(",").append(comments).append(")").toString());}String nodeName = node.getNodeName();// 批注IDString id = ids.isEmpty() ? "" : ids.getFirst();if (BODY_WT.equals(nodeName) && id.length() > 0) {// text,批注引用的正文文本 - <id,text>values.put(id, node.getFirstChild().getNodeValue());} else if (BODY_PIC.equals(nodeName) && id.length() > 0) {// 图片上加的批注信息values.put(id, "[" + getAttribute(node, "name") + "]");} else if (BODY_COMMENT_START.equals(nodeName)) {// 添加批注ID - 批注引用开始ids.add(getAttribute(node, "w:id"));} else if (BODY_COMMENT_END.equals(nodeName) && id.length() > 0) {// 批注引用结束,添加信息到map中int size = ids.size();for (int i = 0; i < size ; i++) {String tempId = ids.get(i);if (!tempId.equals(getAttribute(node, "w:id"))) {continue;}WordComment wc = new WordComment().setId(tempId).setText(values.get(tempId));if(i != 0){String parentId = ids.get(i-1);wc.setReplyFor(parentId);} else {wc.setReplyFor("");}comments.add(wc);commentIndex++;}// 当前节点所有批注(含回复的批注)都添加了int added = 0;for(WordComment c : comments){if(ids.contains(c.getId())){added++;}}if(added == size){ids.clear();if (commentIndex == maxCommentIndex && ids.isEmpty()) {// 所有批注已经解析完毕commentFilledComplete = true;}}}// 是否有子节点,递归遍历if (node.hasChildNodes()) {NodeList temp = node.getChildNodes();for (int i = 0; i < temp.getLength(); i++) {if (commentFilledComplete) {break;}fillComments(temp.item(i), ids, values, comments);}}}private String getAttribute(Node node, String attName) {return (node.hasAttributes() && node.getAttributes().getNamedItem(attName) != null) ? node.getAttributes().getNamedItem(attName).getNodeValue() : null;}/**** 非空校验* @param objects 随便了* @return boolean 是否为null* @date 2019-08-27 13:45* @author weiheng*/private boolean insureNotNull(Object... objects) {for (Object object : objects) {if (object == null) {return false;}}return true;}// 测试public static void main(String[] args) {List<WordComment> comments = new WordCommentsParseUtil().getWordCommentsInfo("http://IP:PORT/文件路径");String separator = ",";for (WordComment c : comments) {System.out.println(c.getId() + separator + c.getText() + separator+ c.getComment() + separator + c.getReplyFor());}}
}

代码测试结果如下:

1是针对ID为0的批注的回复,所有这里没有引用的正文内容(2同理,是在1后追加的回复)

解题思路:

1、上官网瞅了瞅,发现Word并不像Excel一样有比较详尽的导航(这让我感到惆怅...)

https://poi.apache.org/components/document/quick-guide-xwpf.html

2、百度直接搜搜是否有人做过相关功能吧,还真有...

搜到如下一篇帖子,感觉挺有用的,感谢了

https://blog.csdn.net/liberalliushahe/article/details/86628870

大致思路是通过XML的形式解析Word文档,那这就OK了,对照着抄一抄改一改,基本问题已经解决了

POI解析Word批注信息相关推荐

  1. Java POI解析Word提取数据存储在Excel

    JavaPOI解析word提取数据到excel 一.了解POI POI以前有了解,这次需求是解析word读取其中标题,还有内容赛选获取自己想要的内容 经过两天的学习,开始熟悉Java这么读取word和 ...

  2. poi解析word文档(解析表格,emf,wmf,svg转jpg图片)

    POI解析word文档 poi解析word的表格:   提前先准备需要的jar包:   <!-- poi --><dependency><groupId>org.a ...

  3. 如何使用poi解析word生成html目录结构

    POI解析word目录结构 简介说明 认识下Word 我们先看下doc版本的word 我们再看下docx版本的word(今天的主角) 目录解析的原理介绍 写word文档时,我们是怎么设置目录? 我们看 ...

  4. poi解析word中的表格

    解析word简历,使用poi解析word表格研究记录如下: package poi;import java.io.File; import java.io.FileInputStream; impor ...

  5. C# 获取word批注信息

    今天在Silverlight 应用程序中实现了 获取word文档批注信息 的功能. 在wcf服务继承接口类中编写的函数如下 [c-sharp] view plaincopy /// <summa ...

  6. java解析word批注

    最近有一个需求,通过java读取word文档,获取里面的批注内容,批注的作者以及被批注的内容,被批注内容所在的章节数和页码数.poi提供的API都是英文的,而且针对word的操作并不是很完善,所以就自 ...

  7. 关于poi解析word 2007版docx问题

    最近因工作需要使用java解析word 2007 .docx文档,电脑上用的office版本是未激活的office,保存打开编辑都没有问题,但是使用poi来读取数据时,却提示 而使用WPS和正版的Of ...

  8. java如何解析word大纲_Java POI 解析word文档

    实现步骤: 1.poi实现word转html 2.模型化解析html 3.html转Map数组 Map数组(数组的操作处理不做说明) 1.导jar包. 2.代码实现 package com.web.o ...

  9. POI解析Word中文API

    https://yq135314.iteye.com/blog/1538182 POI操作word文档的两个主要模块就是HWPF和XWPF. HWPF是操作Microsoft Word 97(-200 ...

最新文章

  1. linux修改vim配色,更改vim配色的具体操作 更改vim配色的图文教程
  2. 抽象工厂模式(JAVA反射)
  3. python自动化报表定时跑_POINTer分享:Python如何做报表自动化
  4. oracle 导出数据 utl,使用utl_file做选择性数据导出
  5. Ubuntu16使用theano出错
  6. 自动化测试,从入门到跑路1
  7. FL计算机软件,FL Studio水果编曲软件
  8. 物流行业GPS定位应用解决方案
  9. 【转】机器学习入门——浅谈神经网络
  10. 计算机联锁控制系统的软件应具备信号操作功能,N6_计算机联锁控制系统原理-软件原理.ppt...
  11. HDU 5336 XYZ and Drops (模拟+搜索,详解)
  12. 展辰涂料如何利用K2BPM加强流程管控?
  13. 初中数学503个必考知识点_高考数学必考知识点高中数学重点知识归纳
  14. Arcesium面试体验|S6(在校园实习)
  15. 电梯卫士等对计算机的应用,小班安全活动教案:电梯小卫士教案
  16. 莫队算法 (普通莫队、带修莫队、树上莫队)
  17. ST M24C01-WDW6TP EEPROM存储器芯片
  18. axios每次发送请求会有两次,多一次Request Method: OPTIONS是怎么回事?
  19. 爬虫|wallhere壁纸批量下载
  20. AutoCAD 2010中文版从入门与精通视频教程

热门文章

  1. 《全基因组测序WGS数据分析——1.DNA测序技术》学习笔记
  2. HTML+CSS一个简单的电影网页制作作业,学生个人html静态网页制作成品代码, html电影速递网
  3. 1967年图灵奖--莫里斯·威尔克斯生平
  4. 【新手入门.考试高频】Java中“一个类声明的两个对象如果有相同的引用,二者就有相同的变量”的理解
  5. MFC中listctrl图片拖拽效果
  6. 多路测量实时同步工作原理_数字示波器原理
  7. 将开发板的usb配置为ncm网口(qnx系统)
  8. 【Spring AOP】静态代理设计模式、Spring 动态代理开发详解、切入点详解(切入点表达式、切入点函数)
  9. 北漂生活第十八弹-日子还照旧
  10. 关于word2016中mathtype无法使用以及“由于宏安全设置,无法找到宏或宏已被禁用”的解决方案