环境内容
操作系统: windows 10
运行环境: Tomcat 8.5 JDK1.8
Excel工具: EasyExcel 2.2.6
概述
这里简单概述一下我为什么选择使用 EasyExcel 来处理 Excel 表格,嫌啰嗦的可以忽略 !
由于 apache 的 poi和 jxl, excelpoi 都有一个严重的问题,就是非常消耗内存, 特别是处理数据量多时, 速度慢并且时有异常发生, 所以改用阿里研发的easyExcel更可靠一些, 大于1000行以上的数据, 会一行一行的解析, 避免了内存的溢出.
EasyExcel 主要功能
1. 支持Excel导入与导出, 同时支持xls 和 xlsx 的Excel文件格式.
2. 支持 pojo 注解, 映射成为 java 实体模型.
3. 支持多个 sheet, 同时一个 sheet 支持多张表
4. 支持自定义 Excel 样式: 字体, 加粗, 表头颜色, 数据内容颜色等.
5. 可以设置是否需要写表头.
上代码
代码写的有点重复, 可以忽略 1 和 2 ;
1.基本API
/**
* 基本读取数据
* 传统poi会有内存问题,他是一次性将文件加载到内存中,容易内存泄露
* 使用easyExecl的好处是: 他是一行一行读取,不会内存泄露,速度较慢,但是安全可靠
* @param args
*/
public static void main(String[] args) {
//读取文件
//1.创建ExcelReaderBuilder实例
ExcelReaderBuilder read = EasyExcel.read();
//2.获取文件对象
read.file("E:\\个人信息导入.xlsx");
//3.指定Sheet(可以通过下标/或者名字, 不指定加载所有)
read.sheet("Sheet");
//4.自动关闭输入流
read.autoCloseStream(true);
//5.设置Excel文件格式(.xlsx和xls可选)
read.excelType(ExcelTypeEnum.XLSX);
//6.设置监听器,因为easyExcel是一行一行读取,逐行读取,每读一行就会通知我们程序读取,
//注册监听器, 进行数据的解析 registerReadListener 是一个接口,这里我们用的实现类是 AnalysisEventListener抽象类
read.registerReadListener(new AnalysisEventListener() {
@Override
public void invoke(Object data, AnalysisContext context) {
//Object data : 可以通过加泛型的方式直接拿到Map类型<integer,String>
//因为他底层是LinkedHashMap Object是它的超类
//作用:一行数据读取完成之后的回调
System.out.println(data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
//作用: 通知文件读取完毕: 用来告诉我们数据已经读取完毕了
System.out.println("数据读取完毕");
}
});
//7.构建读取器
ExcelReader reader = read.build();
//8.读取数据
reader.readAll();//读取所有
//9.调用方法, 读取完毕
reader.finish();
//第一行不会读取 , 读取后会封装到对象中, 使用观察者模式
}
结果:
2. 泛型读取数据
/**
* 泛型读取数据
* @param args
*/
public static void main(String[] args) {
//读取文件
//1.创建ExcelReaderBuilder实例
ExcelReaderBuilder read = EasyExcel.read();
//2.获取文件对象
read.file("E:\\个人信息导入.xlsx");
//3.指定Sheet(可以通过下标/或者名字, 不指定加载所有)
read.sheet("Sheet");
//4.自动关闭输入流
read.autoCloseStream(true);
//5.设置Excel文件格式
read.excelType(ExcelTypeEnum.XLSX);
//6.设置监听器,因为easyExcel是一行一行读取,逐行读取,每读一行就会通知我们程序读取,
//注册监听器, 进行数据的解析 registerReadListener 是一个接口,这里我们用的实现类是 AnalysisEventListener抽象类
read.registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
//Object data : 可以通过加泛型的方式直接拿到Map类型<integer,String>
//因为: Object参数底层->LinkedHashMap, 返回的数据实际是Map类型
//可以通过泛型,指定数据类型,Map集合
@Override
public void invoke(Map<Integer, String> integerStringMap, AnalysisContext context) {
//作用:一行数据读取完成之后的回调
//解析Map
Set<Integer> keySet = integerStringMap.keySet();
Iterator<Integer> iterator = keySet.iterator();
while (iterator.hasNext()) {
Integer key = iterator.next();
System.out.println(key + ":" + integerStringMap.get(key) + ", ");
}
System.out.println("");
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
//作用: 通知文件读取完毕: 用来告诉我们数据已经读取完毕了
System.out.println("数据读取完毕");
}
});
//7.构建读取器
ExcelReader reader = read.build();
//8.读取数据
reader.readAll();//读取所有
//9.调用方法, 读取完毕
reader.finish();
//第一行不会读取 , 读取后会封装到对象中, 使用观察者模式
}
结果:
3. 读数据(自定义实体类接收Excel数据)
实体类
/**
* 对应Execl表格的实体类, 映射对象
* @ExcelProperty 注解完成实体类成员变量和Execl字段的映射
* 解析Excel时,直接指定实体类解析
*
* 注意:Execl文件第一行不会接收, 因为他是映射字段
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@ExcelProperty("序号")
private Integer id;
@ExcelProperty("姓名")
private String name;
@ExcelProperty("性别")
private String gender;
@ExcelProperty("出生日期")
private Date date;
@ExcelProperty("身份证号")
private String userId;
@ExcelProperty("手机号")
private String phone;
@ExcelProperty("邮箱")
private String email;
@ExcelProperty("QQ")
private Long qq;
}
Excel表格
接收方法
/**
* 读数据基本操作**
*
* 实体类 User 对象接收 Execl
* <p>
* *注意: 直接编译会报错,
* *因为: data底层->LinkedHashMap, 返回的数据实际是Map类型
* *LinkedHashMap 和 User没有任何关系, User是我们自定义的对象
* *不能完成类型转换
* *解决: 只需要调用的适合添加 head(User.class) 把需要解析的实体类类型添加进来
* 转换完成后取到的数据就是User的格式,工具会自动转成User格式,通过@ExcelProperty完成映射
*
* @param args
*/
public static void main(String[] args) {
//使用集合接收解耦合,方便操作
LinkedList<User> list = new LinkedList<>();
EasyExcel.read("E:\\个人信息导入.xlsx")
.head(User.class)
.sheet("Sheet")
.registerReadListener(new AnalysisEventListener<User>() {
@Override
public void invoke(User user, AnalysisContext context) {
list.add(user);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("读取数据完毕");
}
}).doRead();//doRead()读取
for (User user : list) {
System.out.println(user);
}
}
结果:
4.写数据(使用Excel把Java里的数据写到Execl表格里)
/**
* 写数据: 使用Execl把Java里的数据写到Execl表格里面
* 思路:
* 1.首先得有数据本身
* 2.通过java程序读出来,映射成一个List对象
* 3.接下来把List对象,通过easyExecl再给它写到另外一个Execl中
*/
public static void main(String[] args) {
//直接可以导入到本地文件
//但是会没有标题(第一行)
List<User> list = parseData();
//list写入Excel文件
EasyExcel.write("E:\\个人信息导入(副本1).xlsx")//写到哪里去(自定义路径和名称)
/**
* 调用head可以把它的标题传进来第一行
* T head(List<List<String>> head) 重载
* 可以定义list集合, 可以把文字装到List集合里
* 同时可以按照被注解(@ExcelProperty)标注的实体类格式,进行写入
* 名称,性别,出生日期这种形式作为它的head
*/
.head(User.class)
.excelType(ExcelTypeEnum.XLSX)//输出文件类型
.sheet("用户表")//设置我的标题名字
.doWrite(list);//读取
}
public static List<User> parseData() {
//使用集合接收解耦合,方便操作
LinkedList<User> list = new LinkedList<>();
EasyExcel.read("E:\\个人信息导入.xlsx")
.head(User.class)
.sheet("Sheet")
.registerReadListener(new AnalysisEventListener<User>() {
@Override
public void invoke(User user, AnalysisContext context) {
list.add(user);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("读取数据完毕");
}
}).doRead();//doRead()读取
return list;
}
结果: