当前位置: 首页 > article >正文

使用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();
    }

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

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


http://www.kler.cn/a/317433.html

相关文章:

  • leetcode-位运算题型
  • 前端面试笔试(二)
  • vue面试题7|[2024-11-14]
  • 使用API有效率地管理Dynadot域名,编辑账户中whois联系人信息
  • 贪心算法day03(最长递增序列问题)
  • 实现 MVC 模式
  • 单线服务器是什么?单线服务器有什么优点?
  • 掌握 Flutter 中的 `Overlay` 和 `OverlayEntry`:弹窗管理的艺术
  • 如何将Vue项目部署至 nginx
  • 力扣最热一百题——最小覆盖子串
  • 【优选算法之前缀和】No.6--- 经典前缀和算法
  • Unity webgl跨域问题 unity使用nginx设置跨域 ,修改请求头
  • 基于微信小程序的宠物寄养平台的设计与实现+ssm(lw+演示+源码+运行)
  • Adams与Matlab通过FMI联合仿真
  • 我的AI工具箱Tauri版-FunAsr音频转文本
  • git 删除 git push 失败的记录
  • 阿里开源多模态大模型Ovis1.6,重塑出海电商AI格局
  • python自学笔记
  • 价格便宜又好用的云电脑挑选:ToDesk云电脑 vs 青椒云
  • oracle rac多个实例就相当于多个数据库系统程序
  • Python 管理 AWS ElastiCache 告警
  • 前端——盒子模型
  • 巨潮股票爬虫逆向
  • Qt_多元素控件
  • 机器学习(1)——线性回归、线性分类与梯度下降
  • CSS中的多种关系选择器