使用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
一般以下几个原因:
- 没有引入POI相关jar或引入版本太低
- 引入了多个版本的POI,导致包冲突了
- 没有引入关联依赖,这个具体要看下堆栈中的
Cause By
Excel上传和下载
Excel上传
前端
<el-form-item>
<el-upload :shaw-file-list="false" :on-change="onChange" :auto-upload="false">
<el-button type="primary"> 导入</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"> 导出 </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();
}
通过线程池来完成百万级别数据插入
通过线程池来完成百万级别数据插入