博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用POI处理常见的文件类型
阅读量:3958 次
发布时间:2019-05-24

本文共 7486 字,大约阅读时间需要 24 分钟。

前言:拖更了很久,主要是公司项目太忙,抽不出大块时间去整理开发过程中遇到的问题或是心得。当然也有自己最近一段时间对于写博客有些懈怠的原因,以后尽可能的最少每天出一篇吧。

 

正题:相信很多小伙伴在企业级项目开发过程中,都遇到过对Office格式文档操作的问题,博主这段时间遇到这方面的需求比较多,用此文MARK一下。

简单用一下百度词条给出的 POI 释意,POI是Apache的开源函式库,提供API给JAVA程序对Office格式档案读写功能。

那我们大家立刻开始试试吧!

其一,使用POI操作Word

 

江湖规矩,先上POM文件

org.apache.poi
poi-scratchpad
4.1.0
org.apache.poi
poi-ooxml
4.1.0
org.apache.poi
poi-ooxml-schemas
4.1.0

以下代码仅为测试demo,提供思路而已,请根据具体场景做对应处理

场景,Word文档里内容是一个JSON串,读取后直接转为对象即可。

/**   * 测试demo   *   * @param    * @return    */   @PostMapping("/word")   public void mockPaper(@RequestParam("file") MultipartFile file) {       try {            String fileName = file.getOriginalFilename();            int lastIndexOf = fileName .lastIndexOf(".");            if(lastIndexOf==-1) {                throw new IllegalArgumentException("当前传入的文件格式不合法!");            }            String suffex=fileName.substring(lastIndexOf+1);                       if("docx".equals(suffex)){                InputStream inputStream = file.getInputStream();                XWPFDocument xwpfDocument = new XWPFDocument(inputStream);                XWPFWordExtractor extractor = new XWPFWordExtractor(xwpfDocument);                //从Word文档中提取文本                String text = extractor.getText();                           inputStream.close();                xwpfDocument.close();                extractor.close();                /*                分页获取                List
paragraphs = xwpfDocument.getParagraphs(); for(XWPFParagraph paragraph : paragraphs){ String words = paragraph.getText(); } Iterator
iterator = xwpfDocument.getParagraphsIterator(); while (iterator.hasNext()) { XWPFParagraph para = iterator.next(); }*/ }else if("doc".equals(suffex)){ InputStream inputStream = file.getInputStream(); //使用HWPF组件中WordExtractor类从Word文档中提取文本或段落 WordExtractor wordExtractor = new WordExtractor(inputStream); String s = wordExtractor.getText(); inputStream.close(); wordExtractor.close(); }else { throw new IllegalArgumentException("不能解析的文档类型,请输入正确的word文档类型的文件!"); } } catch (IOException e) { e.printStackTrace(); } }

其二,使用POI操作Excel

 

老规矩,先上POM

org.apache.poi
poi-ooxml-schemas
4.1.0
org.apache.poi
poi-ooxml
4.1.0

 

场景:根据Excel文档数据(约一万条,九十多列),根据文档单条某一列的值,去查询数据库判断是否存在对应,若存在则将数据保存在临时文件中,不存在则跳过。

思路:文档数据转DTO集合,批量查询数据库并判断单条是否存在对应,批量写入临时文件。

 

相关代码已作脱敏处理,导入接口

/**     * Excel导入     *     * @param file 入参     * @return RespDto 出参     */    @ResponseBody    @PostMapping("/importExcel")    @ApiOperation("Excel导入")    @ControllerLog(desc = "Excel导入")    public RespDto
> importExcel(MultipartFile file) { RespDto
> result = new RespDto<>(new SingleVo<>(Boolean.FALSE)); try { if(fundPoolService.importFund(file)){ result.setData(new SingleVo<>(Boolean.TRUE)); } } catch (Exception e) { log.error("importExcel 文件导入异常 error {}.param:{}",e,JSONObject.toJSONString(file)); result.setCode(ResultCodeEnum.UPDATE_ERR.getCode()).setMsg(e.getMessage()); } return result; }

 Excel导入,Service层代码接口

​/**     * Excel导入     *     * @param file 入参     * @return boolean 出参     */    @Transactional(rollbackFor = Exception.class)    public boolean importExcel(MultipartFile file) throws IOException{        AssertUtil.assertNotNull(file, "importExcel file is not allow null or empty");        List
xxList = new xxExcelUtil().readExcelFile(file.getInputStream(),file.getOriginalFilename()); if(ObjectUtils.isEmpty(xxList)){ throw new BusinessException("Excel导入异常,上传文件格式有误"); } //将成功数据写入临时文件 createResultFile(xxList); return true; }​

 构造通用的Excel处理工具

​public class xxExcelUtil {    public List
readExcelFile(InputStream inputStream, String fileName) throws IOException { Workbook workbook = null; try { //判断什么类型文件 if (fileName.endsWith(".xls")) { workbook = new HSSFWorkbook(inputStream); } else if (fileName.endsWith(".xlsx")) { workbook = new XSSFWorkbook(inputStream); }else { return null; } //获取所有的工作表的的数量,这里SheetNum数值应为1 int numOfSheet = workbook.getNumberOfSheets(); if(numOfSheet!=1){ return null; } //获取一个sheet也就是一个工作表 Sheet sheet = workbook.getSheetAt(numOfSheet-1); //获取一个sheet有多少Row int lastRowNum = sheet.getLastRowNum(); Row row; List
xxList = new ArrayList<>(); for (int j = 1; j <= lastRowNum; j++) { row = sheet.getRow(j); if (row == null) { continue; } //获取一个Row有多少Cell short lastCellNum = row.getLastCellNum(); xx xx= new xx(); for (int k = 0; k <= lastCellNum; k++) { //根据自己的业务处理 } xxList.add(xx); } //返回结果集 return xxList; } catch (Exception e) { return null; }finally { inputStream.close(); if(!ObjectUtils.isEmpty(workbook)){ workbook.close(); } } }}​

在这里可以看到,批量查询博主并没有采用常规的Mybatis in+拼接的方式,而采用了查取表中所有数据,通过一次遍历及唯一标识的方式,原因其一,九千条采用拼接的方式,会使查询SQL非常长,其二查询效率比如下这种方式低好几个档次。

特别提醒:但是这种基于内存的判断也有其本身的限制,因数据库表xx条数约两千多条,其日后不会有大变动,因此选择这种方式非常合适。但是如果表中数据条数非常多,或者不确定日后表中数据增长上升的速度,不建议采用这种方式。

/**     * 将成功数据写入临时文件     *     * @param      * @return      */    private void createResultFile(List
xxList){ //从数据库查取所有数据的唯一标识 List
codeList = xxMapper.selectAllCode(); if(ObjectUtils.isEmpty(codeList)){ throw new BusinessException("将成功数据写入临时文件异常,从数据库查取所有产品集为空"); } StringBuilder prodBuilder = new StringBuilder(); for (xx xx: xxList){ if(codeList.contains(xx.getCode())){ prodBuilder.append(prodInfo.getCode()).append(",") .append(prodInfo.getName()).append(",") .append(prodInfo.getScore()).append("\r\n"); } } //写入文件 FileUtil.writeString(prodBuilder.toString(),fixTempFile(),"UTF-8"); }

定位临时文件这个方法,有一个特别注意的地方,因为WIN和LINUX路径分隔符并不一致,而 File.separator 可根据项目部署的系统选择对应的分隔符,好用的爆炸。

/**     * 定位临时文件     *     * @param     * @return     */    private String fixTempFile(){        //定位临时文件        String resultFilePath = new File(this.getClass().getResource("").getPath()).toString();        String filePath = resultFilePath.substring(0, resultFilePath.lastIndexOf(File.separator) ) + File.separator +  "resultTxt" + File.separator ;        return filePath + FundConstant.FILE_NAME;    }

CSV文件导出先占个坑,下篇出

OK,使用POI处理常见的文件类型,圆满完结

✿✿✿ヽ(°▽°)ノ✿✿✿ヽ(°▽°)ノ✿✿✿ヽ(°▽°)ノ✿✿✿ヽ(°▽°)ノ✿✿✿

转载地址:http://pwozi.baihongyu.com/

你可能感兴趣的文章
wireshark检索命令
查看>>
五人分鱼问题(附答案)
查看>>
linux查看文件有多少行
查看>>
error:previous declartion of "XXX" is here的解决方法
查看>>
sha1的几个函数的使用
查看>>
为什么int型的数组用memset不能清零(memset的使用规范)
查看>>
<转>CRC校验、MD5、SHA1算法的概念和可靠性现状
查看>>
linux杀死进程详解
查看>>
字符串表示的IP地址与点分式表示的IP地址间的相互转化
查看>>
implicit declaration of function 这种警告问题的原因及解决方法
查看>>
utorrent如何处理占资源过大的问题
查看>>
<好文分享>妖怪和和尚过河问题
查看>>
uTP协议的前世今生(from wikipedia)
查看>>
uTP协议的前世今生(from wikipedia)
查看>>
utp的包头格式<2>
查看>>
开源搜索引擎的比较(收藏几个博客文章)最近要做搜索系统的研究方向
查看>>
asii码表
查看>>
<读书笔记>WebUsage Mining:Discovery and Applications of Usage Patterns from Web Data
查看>>
并查集(Disjoint Sets)
查看>>
在Linux下安装MATLAB
查看>>