业务需求:读取加密的excel文档,导入数据到数据库
操作步骤
一、引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.4</version>
</dependency>
注意版本号,不同版本号提供的方法不一样。有些方法只有高版本的才有
二、定义导出对象类
开始使用@ExcelProperty()
的value属性,读取的值都为null。后来改成使用index
方式,只能读取到部分值。
找了一堆的帖子,总算发现了问题
注意!!!这里的类有两个注意事项
1. 属性命名一定要遵守驼峰命名规则 2. lombok依赖和EasyExcel有冲突,有些属性不能用比如@Setter@Getter等
我是死在了第一点上,居然犯这么低级的错误,没用驼峰命名规则。
public class CBDExcelBo extends BaseRowModel{
@ExcelProperty(index = 1)
private String provinceCode; // 省份代码
@ExcelProperty(index = 3)
private String cityCode; // 地级市代码
@ExcelProperty(index = 5)
private String countyCode; // 区县代码
@ExcelProperty(index = 7)
private String townCode; // 乡镇代码
@ExcelProperty(index = 9)
private String cityLevel; // 城市及商圈等级
@ExcelProperty(index = 10, value = "商圈代码")
private String cbdCode; // 商圈代码
@ExcelProperty(index = 11, value = "商圈名称")
private String cbdName; // 商圈名称
@ExcelProperty(index = 12, value = "商圈等级")
private String cbdLevel; // 商圈等级
public CBDExcelBo() {
}
public CBDExcelBo(String provinceCode, String cityCode, String countyCode, String townCode, String cityLevel, String cbdCode, String cbdName, String cbdLevel) {
this.provinceCode = provinceCode;
this.cityCode = cityCode;
this.countyCode = countyCode;
this.townCode = townCode;
this.cityLevel = cityLevel;
this.cbdCode = cbdCode;
this.cbdName = cbdName;
this.cbdLevel = cbdLevel;
}
public String getProvinceCode() {
return provinceCode;
}
public void setProvinceCode(String provinceCode) {
this.provinceCode = provinceCode;
}
public String getCityCode() {
return cityCode;
}
public void setCityCode(String cityCode) {
this.cityCode = cityCode;
}
public String getCountyCode() {
return countyCode;
}
public void setCountyCode(String countyCode) {
this.countyCode = countyCode;
}
public String getTownCode() {
return townCode;
}
public void setTownCode(String townCode) {
this.townCode = townCode;
}
public String getCityLevel() {
return cityLevel;
}
public void setCityLevel(String cityLevel) {
this.cityLevel = cityLevel;
}
public String getCbdCode() {
return cbdCode;
}
public void setCbdCode(String cbdCode) {
this.cbdCode = cbdCode;
}
public String getCbdName() {
return cbdName;
}
public void setCbdName(String cbdName) {
this.cbdName = cbdName;
}
public String getCbdLevel() {
return cbdLevel;
}
public void setCbdLevel(String cbdLevel) {
this.cbdLevel = cbdLevel;
}
}
三、创建事件监听器
大致逻辑是
-
解析各条数据存储到List,存储到1000。
invoke(CBDExcelBo object, AnalysisContext context)
//该方法按条解析 -
List达到1000后,去重处理,存储到另一个集合。将原先解析的1000条数据清除
-
所有数据解析完成后,入库
doAfterAllAnalysed(AnalysisContext context)
// 数据读取完进行操作
public class ExcelListener extends AnalysisEventListener<CBDExcelBo> {
/**
* 每隔1000条存储数据库,方便内存回收
*/
private static final int BATCH_COUNT = 1000;
/**
* 自定义用于暂时存储data。
* 可以通过实例获取该值
*/
private List<CBDExcelBo> datas = new ArrayList<>();
private Set<CBDExcelDto> cbdExcelDtos = new HashSet<>();
CBDImportService cbdImportService;
private static int count = 1;
public ExcelListener(CBDImportService cbdImportService){
this.cbdImportService = cbdImportService;
}
/**
* 一行一行的读取数据,将数据放入集合,批量处理
*/
@Override
public void invoke(CBDExcelBo object, AnalysisContext context) {
System.out.println("解析到一条数据:{" + object.toString() + "}");
//数据存储到list,供批量处理,或后续自己业务逻辑处理。
count++;
if (datas.size() <= BATCH_COUNT) { //定量分批处理,防止内存溢出
datas.add(object);
} else { // 每到1000,data数据存储到Set,清除data数据
saveToSet();
datas = new ArrayList();
}
}
/**
* 数据读取完进行操作
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
if (datas.size() > 0) {
saveToSet();
}
saveData(cbdExcelDtos); //所有数据解析完成,入库
System.out.println("所有数据解析完成!");
System.out.println("count:" + count);
}
/**
* 将解析的数据存储到Set做去重
*/
private void saveToSet(){
//遍历解析过的excel中的数据
//1.根据城市及商圈等级(省级/地级/县级/乡镇)判断,寻找对应行的code
datas.stream().forEach(cbdExcelBo -> {
CBDExcelDto cbdExcelDto = new CBDExcelDto();
cbdExcelDto.setCbdCode(cbdExcelBo.getCbdCode()); //设置商圈代码
cbdExcelDto.setCbdName(cbdExcelBo.getCbdName()); //设置商圈名称
String areaCode = "";
String cityLevel = cbdExcelBo.getCityLevel(); //城市等级
String cbdLevel = cbdExcelBo.getCbdLevel(); //商圈等级
if (cityLevel.equals("省级")) {
areaCode = cbdExcelBo.getProvinceCode();
} else if (cityLevel.equals("地级")) {
areaCode = cbdExcelBo.getCityCode();
} else if (cityLevel.equals("县级")) {
areaCode = cbdExcelBo.getCountyCode();
} else if (cityLevel.equals("乡镇")) {
areaCode = cbdExcelBo.getTownCode();
}
cbdExcelDto.setAreaCode(areaCode); //设置地区编码
cbdExcelDto.setCbdCityLevel(cityLevel + cbdLevel); //设置商圈城市等级
if (!cbdExcelDto.getCbdName().equals("商圈")){
cbdExcelDtos.add(cbdExcelDto);
}
});
}
/**
* 根据业务自行实现该方法
*/
private void saveData( Set<CBDExcelDto> cbdExcelDtos) {
cbdImportService.insertCBD(cbdExcelDtos);
}
}
四、根据excel输入流,读取excel文件。
- 创建
ExcelReader
读取,从监听类中获取读取的数据 - 输入密码
File file = new File("文件地址.xls");
try {
FileInputStream inputStream = new FileInputStream(file);
/**
* CBDExcelBo.class:映射的实体对象
* new ExcelListener(cbdImportService):监听器,cbdImportService要操作数据库,所以传入service
*/
ExcelReader excelReader = EasyExcelFactory.read(inputStream, CBDExcelBo.class, new ExcelListener(cbdImportService))
.password("yourpassword")
.headRowNumber(0)
.build();
excelReader.readAll();
} catch (Exception e) {
log.error(e.getMessage());
e.printStackTrace();
}