自学内容网 自学内容网

使用Hutool-poi封装Apache POI进行Excel的上传与下载

介绍

Hutool-poi是针对Apache POI的封装,因此需要用户自行引入POI库,Hutool默认不引入。到目前为止,Hutool-poi支持:

  • Excel文件(xls, xlsx)的读取(ExcelReader)
  • Excel文件(xls,xlsx)的写出(ExcelWriter)

#使用

#引入POI依赖

推荐引入poi-ooxml,这个包会自动关联引入poi包,且可以很好的支持Office2007+的文档格式

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>${poi.version}</version>
</dependency>

如果需要使用Sax方式读取Excel,需要引入以下依赖(POI-4.x以上这个非必须):

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>${xerces.version}</version>
</dependency>

说明
hutool-4.x的poi-ooxml 版本需高于 3.17(别问我3.8版本为啥不行,因为3.17 > 3.8 )
hutool-5.x的poi-ooxml 版本需高于 4.1.2
hutool-5.6.x支持poi-ooxml 版本高于 5.0.0
xercesImpl版本高于2.12.0(非必须)

引入后即可使用Hutool的方法操作Office文件了,Hutool提供的类有:

  • ExcelUtil Excel工具类,读取的快捷方法都被封装于此
  • ExcelReader Excel读取器,Excel读取的封装,可以直接构造后使用。
  • ExcelWriter Excel生成并写出器,Excel写出的封装(写出到流或者文件),可以直接构造后使用。

#常见问题

部分用户使用POI模块时会提示:

You need to add dependency of 'poi-ooxml' to your project, and version >= 4.1.2

一般以下几个原因:

  1. 没有引入POI相关jar或引入版本太低
  2. 引入了多个版本的POI,导致包冲突了
  3. 没有引入关联依赖,这个具体要看下堆栈中的Cause By

Excel上传和下载

Excel上传

前端

<el-form-item> 
        <el-upload :shaw-file-list="false" :on-change="onChange" :auto-upload="false"> 
           <el-button type="primary">&nbsp导入</el-button>
        </el-upload>
   </el-form-item>

const onChange = (uploadFile: any, _uploadFiles: any) => {

    let name = uploadFile.name
    let reader = new FileReader()
    reader.readAsDataURL(uploadFile.raw) // 异步的读
    reader.onload = (file) => {
        callUploadApi(name, file.target?.result)
    }

}

const callUploadApi = (name: string, base64: any) => {

    productApi.upload.call({ name, base64 }).then((res: any) => {
         ElMessage.success("上传成功")
    })
}

后端

@PostMapping("upload")
    public String upload(@RequestBody UploadDto uploadDto) throws IOException {

        String base64 = uploadDto.getBase64();
        String[] base64s = StrUtil.splitToArray(base64, "base64,");
        byte[] decode = Base64.decode(base64s[1]);

        //用于创建一个基于字节数组的输入流。它允许你从一个字节数组中读取数据。
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);

        //创建Excel读取器,用于后续的Excel数据读取操作
        ExcelReader reader = ExcelUtil.getReader(byteArrayInputStream);

        //通过反射机制读取所有产品数据。
        List<Product> readAll = reader.readAll(Product.class);

        productService.insert(readAll);

        byteArrayInputStream.close();
        return "success";

    }

Excel下载

前端

<el-form-item>
            <el-button type="primary" @click="exportExcel">&nbsp导出                    </el-button>
      </el-form-item>


const exportExcel = () => {
    let name = formData.name == '' ? undefined : formData.name
    window.open('/api/pro/download?name='+name, '_blank', '')
}

后端

 @GetMapping("download")
    public void download(HttpServletResponse response, ProductQuery productQuery) throws IOException {

        List<Product> productList = productService.select(productQuery);

        // 初始化Excel写入器 加true指定Excel文件是xlsx格式
        ExcelWriter writer = ExcelUtil.getWriter(true);

        writer.addHeaderAlias("id", "Id");
        writer.addHeaderAlias("name", "姓名");
        writer.addHeaderAlias("subName", "介绍");
        writer.addHeaderAlias("status", "状态");
        writer.addHeaderAlias("price", "价格");

        // 写入当前批次的数据
        writer.write(productList,true);

        //response为HttpServletResponse对象   设置响应的内容类型为Excel文件
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
        //设置响应头,告诉浏览器以附件形式下载文件,文件名为test.xlsx。这样设置可以让浏览器弹出文件下载对话框。
        String time = System.currentTimeMillis() +"";
        response.setHeader("Content-Disposition", "attachment;filename=product"+time+".xlsx");
        //获取响应输出流,它是用于将响应的数据发送给客户端的流。
        ServletOutputStream out = response.getOutputStream();
        //将Excel数据写入输出流。第二个参数为true表示追加写入,即将数据追加到已有的Excel文件中。
        writer.flush(out, true);

        //关闭输出流
        out.close();
    }

通过线程池来完成百万级别数据插入

通过线程池来完成百万级别数据插入


原文地址:https://blog.csdn.net/zhzjn/article/details/142464655

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!