Java解析、生成Excel比较有名的框架是Apache poi、jxl。但是它们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但是poi还是有一些缺陷,比如07版Excel解压缩以及解压缩后存储都是在内存中完成的,内存消耗依然很大。easyExcel重写了poi对07版的解析,一个3M的excel用poi sax解析依然需要100M左右内存,改用easyExcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便。
com.alibaba
easyexcel
3.0.5
org.projectlombok
lombok
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("user")
public class User implements Serializable {
//value表示表格列名,index表示第几列
@ExcelProperty(value = "编号",index = 0)
private Long id;
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年龄")
private Integer age;
@ExcelProperty("电子邮箱")
private String email;
@ExcelProperty("创建日期")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private LocalDateTime createTime;
@ExcelProperty("更新日期")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private LocalDateTime updateTime;
@ExcelProperty("逻辑删除")
// @ExcelIgnore: 导出Excel表格时可以忽略此注解标注的属性
private Integer deleted;
}
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import java.util.List;
/*
* @Author Xiaowu
* @Date 2022/3/28
* @Description: 表格导入导出
* */
public class Excelutils {
/* 导出Excel表格 参数说明
* urlPattren: 导出Excel表格的路径
* objectClass: 导出数据的Pojo的Class对象
* data: 导出的数据集合
* sheet: 工作表序号,不传参数默认为0
* */
public static void writeExcel(String urlPattren, Class> objectClass, List> data, String sheet){
ExcelWriterBuilder workBook = EasyExcel.write(urlPattren,objectClass);
workBook.sheet(sheet).doWrite(data);
}
}
@Resource
private EasyExcelService easyExcelServiceImp;
@GetMapping
public Object setExcel(){
//数据库读取的数据
List users = easyExcelServiceImp.setExcel();
Excelutils.writeExcel("E:/IDEA/projectTwo/easy-excel/user.xlsx",User.class,users,"sheet1");
return null;
}
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.wu.pojo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExcelListener extends AnalysisEventListener {
private Logger logger = LoggerFactory.getLogger(this.getClass());
//每读取一行数据都会执行一次invoke方法
@Override
public void invoke(User user, AnalysisContext analysisContext) {
logger.info(user.toString());
}
//读取完毕后执行doAfterAllAnalysed方法
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
logger.info("读取结束了");
}
}
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import java.util.List;
/*
* @Author Xiaowu
* @Date 2022/3/28
* @Description: 表格导入导出
* */
public class Excelutils {
/* 导入Excel表格数据 参数说明
* urlPattren: 导入Excel表格的路径
* objectClass: 每一行数据的Pojo的Class对象
* alet: 读取数据的监听器实例,每读一行则会执行一次invoke方法
* sheet: 工作表序号,不传参数默认为0
* */
public static List> readExcel(String urlPattren, Class> objectClass, AnalysisEventListener> alet,String sheet){
ExcelReaderBuilder workBook = EasyExcel.read(urlPattren, objectClass, alet);
ExcelReaderSheetBuilder sheet1 = workBook.sheet(sheet);
return sheet1.doReadSync();
}
}
@PostMapping
public Object getExcel(){
List users = (List)Excelutils.readExcel("E:/IDEA/projectTwo/easy-excel/user.xlsx", User.class, new ExcelListener(), "sheet1");
users.forEach(System.out::println);
return null;
}
高版本JDK可能会遇到这个问题,这是由于JDK8中有关反射相关的功能,从JDK9开始就已经被限制了。
为了兼容原来的版本,需要在`Edit Configurations`中`VM options`输入框中添加`--add-opens java.base/java.lang=ALL-UNNAMED`
选项来开启这种默认不被允许的行为