EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。 github地址:GitHub - alibaba/easyexcel: 快速、简洁、解决大文件内存溢出的java处理Excel工具
通过java代码完成对Excel的读写操作,所谓的读写理解为上传和下载
官网:关于Easyexcel | Easy Excel (alibaba.com)
所谓的写操作就是把java中的类对象写入到excel表格中。
实现步骤:
1.引入相关依赖
com.alibaba easyexcel 3.0.5 2.封装响应的对象
package com.wzh.excel; import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import java.util.Date; @Data @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode public class DemoData { @ExcelProperty("字符串标题") private String string; @ExcelProperty("日期标题") private Date date; @ExcelProperty("数字标题") private Double doubleData; /** * 忽略这个字段 */ @ExcelIgnore private String ignore; }
3.通过easyexcel完成写操作
package com.wzh.excel; import com.alibaba.excel.EasyExcel; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @ProjectName: computer * @Package: com.wzh.excel * @ClassName: TestWriterDemo * @Author: 王振华 * @Description: * @Date: 2022/10/24 20:37 * @Version: 1.0 */ public class TestWriterDemo { public static void main(String[] args) { //fileName:表示excel文件所在路径以及名称 String fileName = "D:\\java_idea_2020\\dev\\自己代码\\computer\\easyexcel.xlsx"; // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可 //模拟要写入excel的数据 List
list = new ArrayList<>(); list.add(new DemoData("aaa",new Date(),3.1,"aaaaaa")); list.add(new DemoData("bbb",new Date(),3.1,"bbbbbb")); EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(list); } }
写Excel | Easy Excel (alibaba.com)
package com.wzh.controller;
import com.alibaba.excel.EasyExcel;
import com.wzh.excel.DemoData;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class ExcelController {
/**
* 文件下载(失败了会返回一个有部分数据的Excel)
*
* 1. 创建excel对应的实体对象 参照{@link DownloadData}
*
* 2. 设置返回的 参数
*
* 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
//模拟要写入excel的数据
List list = new ArrayList<>();
list.add(new DemoData("aaa",new Date(),3.1,"aaaaaa"));
list.add(new DemoData("bbb",new Date(),3.1,"bbbbbb"));
EasyExcel.write(response.getOutputStream(), DemoData.class).sheet("模板").doWrite(list);
}
}
这个是我之前的一个工具类:
package com.wzh.utils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @ProjectName: computer
* @packageName: com.wzh.utils
* @author: xmhz45
* @create: 2022/7/6 19:31
*/
public class ExcelUtil {
public void print(String filename, List objects, HttpServletResponse response) {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//防止中文乱码
//String fileName = URLEncoder.encode("测试","utf-8");
response.setHeader("Content-Disposition","attachment;filename=UTF-8''"+fileName+".xlsx");
ServletOutputStream outputStream = response.getOutputStream();
//工作簿对象
ExcelWriterBuilder writerWork = EasyExcel.write(outputStream,objects.get(0).getClass());
//工作表对象
ExcelWriterSheetBuilder sheet = writerWork.sheet(filename);
sheet.doWrite(objects);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map map = new HashMap();
map.put("status", "failure");
map.put("message", "下载文件失败" + e.getMessage());
e.printStackTrace();
}
}
}
读Excel | Easy Excel (alibaba.com)
1.需要一个监听器
package com.wzh.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener {
/**
* 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 100;
/**
* 缓存的数据
*/
private List cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private DemoDAO demoDAO;
public DemoDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
demoDAO = new DemoDAO();
}
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param demoDAO
*/
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
/**
* 这个每一条数据解析都会来调用 excel数据 07版没有限制
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(DemoData data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
cachedDataList.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
//如果excel数据够100条执行if语句 不够的话执行doAfterAllAnalysed方法
if (cachedDataList.size() >= BATCH_COUNT) {
System.out.println("100条保存");
saveData();
// 存储完成清理 list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context 最后需要执行的代码
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
System.out.println("不足100条最后调用");
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
demoDAO.save(cachedDataList);
log.info("存储数据库成功!");
}
}
2.dao层 之后只需要操作这个 存入数据库即可
package com.wzh.excel;
import java.util.List;
/**
* 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。
**/
@Component
public class DemoDAO {
public void save(List list) {
// 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
}
}
3.测试
package com.wzh.excel;
import com.alibaba.excel.EasyExcel;
import java.io.File;
public class TestReadDemo {
public static void main(String[] args) {
//要读的文件路劲及文件名
String fileName = "D:\\java_idea_2020\\dev\\自己代码\\computer\\easyexcel.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet
//DemoData.class:实体类
//new DemoDataListener() 监听器
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
}
ssm框架:
1.依赖--文件上传的依赖
commons-fileupload
commons-fileupload
1.4
2.文件上传解析器
/**
* 文件上传
*
* 1. 创建excel对应的实体对象 参照{@link UploadData}
*
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
*
* 3. 直接读即可
*/
@PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
return "success";
}
package com.wzh.controller;
import com.alibaba.excel.EasyExcel;
import com.wzh.excel.DemoDAO;
import com.wzh.excel.DemoData;
import com.wzh.excel.DemoDataListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class ExcelController {
/**
* 文件下载(失败了会返回一个有部分数据的Excel)
*
* 1. 创建excel对应的实体对象 参照{@link DownloadData}
*
* 2. 设置返回的 参数
*
* 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
//模拟要写入excel的数据
List list = new ArrayList<>();
list.add(new DemoData("aaa",new Date(),3.1,"aaaaaa"));
list.add(new DemoData("bbb",new Date(),3.1,"bbbbbb"));
EasyExcel.write(response.getOutputStream(), DemoData.class).sheet("模板").doWrite(list);
}
@Autowired
private DemoDAO demoDAO;
/**
* 文件上传
*
* 1. 创建excel对应的实体对象 参照{@link UploadData}
*
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
*
* 3. 直接读即可
*/
@PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), DemoData.class, new DemoDataListener(demoDAO)).sheet().doRead();
return "success";
}
}
测试用postman传参文件:
测试的时候会出现一个问题DemoDao没有注入成功,那是因为没有被包扫描到。
springboot:
一个普通类如何被spring所管理,spring boot整合EasyExcel_calf小小牛的博客-CSDN博客
前端需要注意的是 要设置类型 blob
//导出
printC(){
if(this.multipleSelection.length!=0){
var that = this;
axios.post("/outlibrarytransfer/printC?filename=平调入库", this.multipleSelection
,{responseType: 'blob'}).then(function (res){
var blob = new Blob([res.data])
var downloadElement = document.createElement('a');
var href = window.URL.createObjectURL(blob); //创建下载的链接
downloadElement.href = href;
downloadElement.download = '平调入库.xlsx'; //下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); //点击下载
document.body.removeChild(downloadElement); //下载完成移除元素
window.URL.revokeObjectURL(href); //释放掉blob对象
console.log(res);
that.initTable();
});
}else{
this.$message.error("请选择要到导出的数据!");
}
},
(8条消息) postman 导出excel_天狼1222的博客-CSDN博客_postman 导出excel
(8条消息) poi excel操作汇总_天狼1222的博客-CSDN博客