一、介绍
EasyExcel 是一个基于 Apache POI,用于读写 Excel 的 Java 简易工具库。它能在尽可能节约内存的情况下,读写 Excel。与其他基于 Apache POI 的 Excel 工具库相比,EasyExcel 在处理大量数据时,能显著减少内存消耗,避免发生内存溢出错误OOM(OutOfMemoryError)。
二、使用
需求:
我这次使用easyExcel是想实现将一个Excel文件中的数据读取出来,经过处理后再写入到另一个excel中。
需要读取的数据样式(‘客户’那个sheet页只是我生成数据时使用的,本次使用easyexcel操作excel的时候并没有使用):
想生成的数据样式(两个Sheet页):
生成数据与原数据相比是增加了三列和一个sheet页,第二个Sheet中的数据就是将账单表Sheet页中的数据按照客户分别计算重量、数量、货款
1.导入pom依赖
首先导入easyexcel的依赖,这里我也导入了lombok的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
</dependency>
2.创建实体类
easyexcel可以将表格中的每一行看作一个对象,因此我们先创建对应的实体类
想要读取的excel的实体类
@Data
public class Bill {
/**
* 日期格式需要是String类型 @DateTimeFormat注解才能生效
* @ExcelProperty(value = "日期",index = 0) value表示这个属性在表格中的列名,index表示列的位置
*/
@ExcelProperty(value = "日期",index = 0)
@DateTimeFormat("yyyy-MM-dd")
private String dateTime;
@ExcelProperty(value = "客户",index = 1)
private String customer;
@ExcelProperty(value = "农户",index = 2)
private String farmer;
@ExcelProperty(value = "数量",index = 3)
private Integer num;
@ExcelProperty(value = "单重",index = 4)
private Double singleWeight;
@ExcelProperty(value = "额外重量",index = 5)
private Double additionalWeight;
@ExcelProperty(value = "单价",index = 6)
private Double singlePrice;
}
想要写入的excel的对象的实体类sheet1
因为sheet1中的数据与读取的那个表格中的数据相比只是增加了三列,因此直接继承Bill类
@Data
public class BillOut extends Bill{
/**
* 总重量
*/
@ExcelProperty(value = "总重量",index = 7)
private Double sumWeight;
/**
* 货款
*/
@ExcelProperty(value = "货款",index = 8)
private Double customerAmount;
/**
* 农户货款
*/
@ExcelProperty(value = "农户货款",index = 9)
private Double farmerAmount;
}
想要写入的excel的对象的实体类sheet2
@Data
public class BillSum {
/**
* 客户名称
*/
@ExcelProperty("客户")
private String customer;
/**
* 客户当天的数量
*/
@ExcelProperty("客户收货数量")
private Integer customerNum;
/**
* 客户当天的货款
*/
@ExcelProperty("客户总货款")
private Double customerAmount;
/**
* 客户当天的总重量
*/
@ExcelProperty("总重量")
private Double customerSumWeight;
}
3.读取excel
/**
* 读取Excel的数据
* @param fileName
* @return
*/
public static List<Bill> getData(String fileName){
// 存放读取出来的数据
final List<Bill> list = new ArrayList<Bill>();
// fileName是需要读取的文件路径
EasyExcel.read(fileName)
// .head() 用来设置表头对应的类 也就是每一行数据对应的那个对象的类
.head(Bill.class)
// .sheet() 设置想要读取的数据在文件中的哪个sheet页面 0-表示第一个sheet页
.sheet(0)
// 创建一个读监听器(使用匿名内部类的方式)
.registerReadListener(new AnalysisEventListener<Bill>() {
// 重新invoke方法,easyexcel是一行一行读取数据的,相当于对每个数据都执行一遍这个操作
public void invoke(Bill bill, AnalysisContext analysisContext) {
list.add(bill);
}
// 重写doAfterAllAnalysed 这个是读完所有数据后最后执行的方法
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("数据读取完毕");
}
})
// 最后执行doRead方法执行
.doRead();
return list;
}
4.写入excel
/**
* 处理数据 写入Excel
* Sheet1 :所有货的数据
* Sheet2 : 每个客户的和
* @param preData
*/
public static void writeSheet(List<Bill> preData,String outFileName){
// 存放Sheet1需要的数据
List<BillOut> sheet1Data = new ArrayList<BillOut>();
// 存放Sheet2需要的数据 -- 因为是按客户维度计算一些数据,所以以客户名为key,将数据放入到map中 最后返回的时候只需要返回value集合就可以
Map<String,BillSum> customerMap = new HashMap<String, BillSum>();
for (Bill bill:preData){
BillOut billOut = new BillOut();
// 将读取到的数据copy到需要写入的数据中
BeanUtil.copyProperties(bill,billOut);
// 1.处理Sheet1中的数据
// 计算总重量
Double sumWeight = billOut.getNum()*billOut.getSingleWeight()+billOut.getAdditionalWeight();
billOut.setSumWeight(sumWeight);
// 计算货款
Double customerAmount = sumWeight*billOut.getSinglePrice();
billOut.setCustomerAmount(customerAmount);
// 计算农户货款
Double farmerAmount = sumWeight*(billOut.getSinglePrice()-BillConstant.DEDUCT_MONEY);
billOut.setFarmerAmount(farmerAmount);
// 2.处理Sheet2中的数据
BillSum billSum;
if (customerMap.containsKey(billOut.getCustomer())){
billSum = customerMap.get(billOut.getCustomer());
}else{
billSum = new BillSum();
billSum.setCustomer(billOut.getCustomer());
billSum.setCustomerAmount(0.0);
billSum.setCustomerNum(0);
billSum.setCustomerSumWeight(0.0);
customerMap.put(billSum.getCustomer(),billSum);
}
// 客户数量 = 该客户下的所有数量和
billSum.setCustomerNum(billSum.getCustomerNum()+billOut.getNum());
billSum.setCustomerSumWeight(billSum.getCustomerSumWeight()+billOut.getSumWeight());
billSum.setCustomerAmount(billSum.getCustomerAmount()+billOut.getCustomerAmount());
// 将Sheet1中的数据放入sheet1的list中
sheet1Data.add(billOut);
}
// 写入Excel
ExcelWriter writeWorkbook = EasyExcel.write(outFileName).build();
// sheet1的builder
ExcelWriterSheetBuilder sheetBuilder1 = EasyExcel.writerSheet(0,"账单表").head(BillOut.class);
// sheet2的builder
ExcelWriterSheetBuilder sheetBuilder2 = EasyExcel.writerSheet(1,"客户账单表").head(BillSum.class);
WriteSheet writeSheet1 = sheetBuilder1.build();
WriteSheet writeSheet2 = sheetBuilder2.build();
// 指定将数据写入到哪个sheet中
writeWorkbook.write(sheet1Data,writeSheet1);
writeWorkbook.write(customerMap.values(),writeSheet2);
// 结束
writeWorkbook.finish();
}
5.运行
public static void main(String[] args) {
String fileName = "E:\笔记\学习笔记\excel学习笔记\测试\数据校验test2.xlsx";
String outFileName = "E:\笔记\学习笔记\excel学习笔记\测试\导出数据test3.xlsx";
List<Bill> bills = getData(fileName);
writeSheet(bills,outFileName);
}