传统的excel处理工具(apache poi、jxl等)严重消耗内存(3兆的文件一般需要100兆的内存),在并发量大或者数据量很大时,容易发生内存溢出(OOM)、jvm频繁full gc;
easyexcel重写了poi对07版Excel的解析,减少了内存消耗;同时对模型转换进行封装,简化了用户使用
传统excel解析工具将所有数据一次性加载到内存进行解析,解析完成后返回数据;
easyexcel没有将数据一次性加载到内存,而是在磁盘上一行一行读取,逐个解析;
将解析结果通过观察者模式返回,交给程序进行后续处理;
解析时丢弃一些不重要的数据(宽度、样式、字体等),节省了内存消耗
3.0.5 com.alibaba easyexcel ${easyexcel.version}
@Data @AllArgsConstructor @NoArgsConstructor @Builder public class Tcinfos { //主键自增 @TableId(type = IdType.AUTO) //忽略下面的id @ExcelIgnore private Integer tcid; @ExcelProperty("吊塔类型") private String type; @JsonFormat(pattern = "yyyy-MM-dd")//取日期时使用 @DateTimeFormat(pattern = "yyyy-MM-dd")//存日期时使用 @ExcelProperty("建造日期") private Date makedate; @ExcelProperty("最大高度") private Integer maxhigh; @ExcelProperty("最大幅度") private Integer maxrange; @ExcelProperty("最大载重") private Integer maxweight; @ExcelProperty("安全员工号") private Integer secman; @ExcelProperty("负责人工号") private Integer resman; }
package com.kgc.towercrane.tcmanager.common; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.kgc.towercrane.tcmanager.domian.module.Tcinfos; import com.kgc.towercrane.tcmanager.mapper.TCinfosMapper; import java.util.ArrayList; import java.util.List; public class ExcelReadListener extends AnalysisEventListener{ //定义批量 每次读取500行数据 最合适可以3000 private static final int BATCH_SIZE=500; //创建一个全局集合 每次读取数据存入其中 private List tcs=new ArrayList<>(); //定义一个mapper接口属性 private TCinfosMapper tCinfosMapperss; //创建一个有参构造 方便在controller层传入mapper接口 public ExcelReadListener(TCinfosMapper tcinfos){ this.tCinfosMapperss=tcinfos; } /** * 每读一行 自动触发invoke方法 * @param tcinfos * @param analysisContext * */ @Override public void invoke(Tcinfos tcinfos, AnalysisContext analysisContext) { System.out.println(tcinfos); //读取数据到集合 tcs.add(tcinfos); //判断集合有木有到500 if(tcs.size()>=BATCH_SIZE){ //读取到的数据大于等于500 插入500条数据到mysql数据库 tCinfosMapperss.batchSaveTcInfo(tcs); //清空集合 tcs.clear(); } } /** * 文件读完后触发doAfterAllAndLysed一次 * 假设数据量是3490条 invoke方法每500跳插入一次 * 最后一条还剩490就不会插入 我们在这个方法手动在保存一次 * 插入最后的490跳 * @param analysisContext */ @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("文件读完后再触发一次!!"); tCinfosMapperss.batchSaveTcInfo(tcs); tcs.clear(); } }
@RestController @RequestMapping("/tcinfo") public class TcinfosCtrl {/** * 2 批量插入 * @param file * @return */ @PostMapping(value ="/batchTowerCrane") public String batchTc(MultipartFile file){ tcinfoStoreService.batch_save(file); return BackinfoConf.BATCHADDTC_SUCCESS; } }
#接口
/** * 上传文件 读取文件内容 * 并批量保存数据 * @param file */ void batch_save(MultipartFile file);
#实现类
@Transactional @Override public void batch_save(MultipartFile file) {@Resource private TCinfosMapper tCinfosMapper;try { //new ExcelReadListener调用他的有参构造 注入mapper对象 EasyExcel.read(file.getInputStream(),Tcinfos.class,new ExcelReadListener(tCinfosMapper)).sheet().doRead(); } catch (IOException e) { e.printStackTrace(); } }
#接口 @Mapper //使用mybatis-plus实现crud public interface TCinfosMapper extends BaseMapper{ //对于传进来的数组批量插入数据库 void batchSaveTcInfo(List tc); }
#配置mapper.xml 批量插入 使用动态sqlinsert into tcinfos (type,makedate,maxhigh,maxrange,maxweight,secman,resman) values (#{tc.type},#{tc.makedate},#{tc.maxhigh},#{tc.maxrange},#{tc.maxweight},#{tc.secman},#{tc.resman})
@RestController @RequestMapping("/tcinfo") public class TcinfosCtrl {@Resource private TcinfoStoreService tcinfoStoreService;// 5 数据库获取数据 在转为excel文件 然后再给用户文件下载 // @Parame 回写文件信息对象 @GetMapping(value ="/downloadTowerCrane") public void downloadTcinfo(HttpServletResponse response) throws IOException { //用于下载的流 ServletOutputStream sos = response.getOutputStream(); //用户生成网页的流 前端可以直接从后端获得一个生成好的网页 // PrintWriter out = response.getWriter(); //获取所有的塔吊信息 Listtcs = tcinfoStoreService.findAllTc(); //下载文件名 String downloadExcelFile="塔吊信息.xlsx"; //准备回传response头部信息 response.setContentType("application/vnd.ms-excel;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(downloadExcelFile, "UTF-8").replaceAll("\\+", "%20")); //向客户端发送 EasyExcel.write(sos,Tcinfos.class) .sheet("塔吊基础信息") .doWrite(tcs); //写完后关闭流 sos.close(); } }
#接口
public interface TcinfoStoreService {/** * 下载所有塔机资料 * @return */ ListfindAllTc(); }
#实现类
@Service public class TcinfoStoreServiceImpl implements TcinfoStoreService { @Resource private TCinfosMapper tCinfosMapper;/** * 查询所有塔吊信息 */ public ListfindAllTc(){ return tCinfosMapper.selectList(null); } }
@Mapper //使用mybatis-plus实现基础的CRUD public interface TCinfosMapper extends BaseMapper{ //对于传进来的数组批量插入数据库 void batchSaveTcInfo(List tc); }