环境
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.5</version>
</dependency>
创建 需要映射 excel 字段的实体
@Data
public class PatientExcel {
@ExcelProperty("姓名")
private String name;
@ExcelProperty(index = 2, converter = CustomItemInfoConverter.class)
private ItemInfo genderType;
@ExcelProperty(index = 3)
@JsonFormat(pattern = "yyyy-MM-dd")
private Date birthday;
@ExcelIgnore
private String phone ;
}
@ExcelProperty(“姓名”) 根据 excel 列的名字 匹配 名字重复,会导致只有一个字段读取到数据
@ExcelProperty(index = 2) 根据 excel 列的的索引读取
@JsonFormat(pattern = “yyyy-MM-dd”) 序列化字段 时间格式化
@ExcelIgnore 忽略此字段 ,不参与 excel 列的匹配
@ExcelProperty(index = 2, converter= CustomItemInfoConverter.class) 自定义 序列化 excel 解析 机制
public class CustomItemInfoConverter implements Converter<ItemInfo> {
@Override
public Class supportJavaTypeKey() {
return null;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return null;
}
// 对象转换 写在这里面
@Override
public ItemInfo convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
String stringValue = cellData.getStringValue();
ItemInfo itemInfo = new ItemInfo();
if ("男".equals(stringValue)) {
itemInfo.setCode(1);
itemInfo.setInput("");
itemInfo.setName("男");
}
if ("女".equals(stringValue)) {
itemInfo.setCode(1);
itemInfo.setInput("");
itemInfo.setName("女");
}
if ("本地".equals(stringValue)) {
itemInfo.setCode(1);
itemInfo.setInput("");
itemInfo.setName("户籍");
}
if ("流动".equals(stringValue)) {
itemInfo.setCode(2);
itemInfo.setInput("");
itemInfo.setName("非户籍");
}
return itemInfo;
}
}
解析excel
/**
* 解析excel 内容转换成 entity
*
* @param file
* @param index
* @return
*/
protected List<PatientExcel> readAll(File file, int index) {
log.info("开始读取Excel文件: {}", file.getAbsolutePath());
List<PatientExcel> all = Lists.newArrayList();
ExcelReader excelReader = EasyExcel.read(file, PatientExcel.class, new PatientListener(all::addAll)).build();
ReadSheet readSheet = EasyExcel.readSheet(0).headRowNumber(index).build();
excelReader.read(readSheet);
excelReader.finish();
log.info("已读取Excel文件: {} ", file.getAbsolutePath());
return all;
}
/**
* 解析excel 的监听器
*/
private class PatientListener extends AnalysisEventListener<PatientExcel> {
private List<PatientExcel> list = new ArrayList<>();
private Consumer<List<PatientExcel>> consumer;
public PatientListener(Consumer<List<PatientExcel>> consumer) {
this.consumer = consumer;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
* BATCH_COUNT 界定符 ,例子 假如我只需要读到200条数据 BATCH_COUNT=200
*/
@Override
public void invoke(PatientExcel data, AnalysisContext context) {
if (list.size() >= BATCH_COUNT) return;
list.add(data);
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
this.consumer.accept(list);
log.info("所有数据解析完成!");
}
/**
* 报错 调用
*
* @param exception
* @param context
* @throws Exception
*/
@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
log.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
// 如果是某一个单元格的转换异常 能获取到具体行号
// 如果要获取头的信息 配合invokeHeadMap使用
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
log.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
excelDataConvertException.getColumnIndex());
}
}
}