用java语言通过APACHE-POI实现导入带目录的word文档 ,按标题级别提取 ,插入数据库

发布时间 2023-05-23 10:51:13作者: 奋斗de小青年

        最近有一个项目需要将一个word文档中的数据提取到数据库中。就去网上查了好多资料,网上很多都是提取简历那种带表格的,但是我这个项目需要提取带目录的。找了好久,最终实现了(我的这篇博客主要是借鉴用POI实现word读写操作并自动将标题编号_poi word 序号_qq_16601953的博客-CSDN博客)。

目录截图

编辑

 

下面贴上主要代码我是按照上面博客借鉴的稍微根据我的需求改了改

/**
 * word文档导入
 */
@RestController
@RequestMapping("/api/import/word")
public class ImportWordController {
    private final Logger logger = LoggerFactory.getLogger(ImportWordController.class);
   

    /**
     * 上传word文档,保存内容
     *
     * @param mFile  word文件
     * @return
     */
    @PostMapping("/importWord")
    public JsonResultView importWordLibrary(@RequestParam("file") MultipartFile mFile) {
        logger.info("进入导入");
        if (mFile.isEmpty()) {
            return new JsonResultView<>(MetaCodeEnum.PARAM_ERROR.getCode(), MetaCodeEnum.PARAM_ERROR.getErrDesc());
        }
        InputStream is = null;
        XWPFDocument doc = null;
        File file = null;
        List<String> failTitleList=new ArrayList<>();
        try {
            //MultipartFile 转file文件
            file = new File(mFile.getOriginalFilename());
            FileUtils.copyInputStreamToFile(mFile.getInputStream(), file);

            is = new FileInputStream(file);
            doc = new XWPFDocument(is);
            //获取段落
            List<XWPFParagraph> paras = doc.getParagraphs();
            int f = 0;//判断只从标题开始
            int inE = 0;//判断词条库什么时候添加
            int inT = 0;//判断词条库什么时候添加
            int level = 1;//判断级别什么时候添加
            //这个是我项目需要的,需要改自己逻辑
            EntryLibrary ntryLibrary = new EntryLibrary();//内容
            LibraryType libraryType = null;//类型
            Integer libraryTypeId = 0;//类型id
            for (XWPFParagraph para : paras) {
                String failTitle="";//返回错误标题
                try {
                    String titleLvl = getTitleLvl(doc, para);//获取段落级别
                    if ("a5".equals(titleLvl) || "a7".equals(titleLvl) || "HTML".equals(titleLvl) || "".equals(titleLvl) || null == titleLvl) {
                        titleLvl = "8";
                    }
                    if (!"8".equals(titleLvl)) {
                    }
                    libraryType = new LibraryType();
                    Date date = new Date();//时间
                    if (null != titleLvl && !"".equals(titleLvl) && !"8".equals(titleLvl)) {
                        if (f != 1 && "0".equals(titleLvl)) {//这里是去除目录,只从内容标题开始
                            f = 1;
                        }
                        System.out.println("级别===" + titleLvl + "内容===" + para.getParagraphText());
                        if ("0".equals(titleLvl)) {
                            ++inT;
                            level = 2;
                            if (inT != 1) {//第一次不添加,第二次到的时候说明前边的段落内容已经循环完成然后添加
                                failTitle=ntryLibrary.getTitle();
                                ntryLibrary.setContent(StringUtils.isNotEmpty(ntryLibrary.getContent())?(ntryLibrary.getContent() + para.getParagraphText()):para.getParagraphText());
                                //添加到数据库
                                ntryLibrary.setCreateTime(date);
                                ntryLibrary.setTypeId(libraryTypeId);
                                ntryLibraryService.insertBean(ntryLibrary);
                                ntryLibrary = new EntryLibrary();
                            }
                            libraryType.setName(para.getParagraphText());
                            libraryType.setCreateTime(date);
                             //添加类型,这个是我项目需要的,需要改自己逻辑
                            libraryTypeId = libraryTypeService.insertBean(libraryType);
                        } else if ("1".equals(titleLvl)) {
                            ++inE;
                            if (inE != 1 && level == 1) {//第一次不添加,第二次到的时候说明前边的段落内容已经循环完成然后添加
                                System.out.println("拼接===" + ntryLibrary .getContent());
                                failTitle=gaugeEntryLibrary.getTitle();
                                ntryLibrary.setCreateTime(date);
                                ntryLibrary.setTypeId(libraryTypeId);
                                ntryLibraryService.insertBean(ntryLibrary);
                                ntryLibrary = new EntryLibrary();
                            }
                            level = 1;
                            ntryLibrary.setTitle(para.getParagraphText());
                        } else if ("2".equals(titleLvl)) {
                            ntryLibrary.setContent(para.getParagraphText());
                        }
                    } else {
                        if (f == 1) {//这里是去除目录,只从内容标题开始
                            if (StringUtils.isNotEmpty(para.getParagraphText())) {
                                System.out.println("段落内容===" + para.getParagraphText());//段落内容
                                ntryLibrary.setContent(StringUtils.isNotEmpty(ntryLibrary.getContent())?(ntryLibrary.getContent() + para.getParagraphText()):para.getParagraphText());
                            }
                        }
                    }
                }catch (Exception e){
                    failTitleList.add(failTitle);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != is) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 会在本地产生临时文件,用完后需要删除
            if (file.exists()) {
                file.delete();
            }
        }
        return new JsonResultView<>(failTitleList);
    }

    /**
     * Word中的大纲级别,可以通过getPPr().getOutlineLvl()直接提取,但需要注意,Word中段落级别,通过如下三种方式定义:
     * 1、直接对段落进行定义;
     * 2、对段落的样式进行定义;
     * 3、对段落样式的基础样式进行定义。
     * 因此,在通过“getPPr().getOutlineLvl()”提取时,需要依次在如上三处读取。
     *
     * @param doc
     * @param para
     * @return
     */
    private String getTitleLvl(XWPFDocument doc, XWPFParagraph para) {
        String titleLvl = "";
        try {
            //判断该段落是否设置了大纲级别
            if (para.getCTP().getPPr().getOutlineLvl() != null) {
                return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal());
            }
        } catch (Exception e) {

        }
        try {
            //判断该段落的样式是否设置了大纲级别
            if (doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) {
                return String.valueOf(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
            }
        } catch (Exception e) {

        }

        try {
            //判断该段落的样式的基础样式是否设置了大纲级别
            if (doc.getStyles().getStyle(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal())
                    .getCTStyle().getPPr().getOutlineLvl() != null) {
                String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal();
                return String.valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
            }
        } catch (Exception e) {

        }
        try {
            if (para.getStyleID() != null) {
                return para.getStyleID();
            }
        } catch (Exception e) {

        }
        return titleLvl;
    }
}

还是有很多需要改进的,希望大神评论指点。