EasyExcel官网文档:https://www.yuque.com/easyexcel/doc/easyexcel
前言:如果项目已引入了apache-poi,请保证apache-poi版本号与easyexcel中的poi版本号一致。
maven仓库地址:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.2</version>
</dependency>
导入
entity:
@Data
public class ReqCustomerDailyImport {
/**
* 客户名称
*/
@ExcelProperty(index = 0)
private String customerName;
/**
* MIS编码
*/
@ExcelProperty(index = 1)
private String misCode;
/**
* 月度滚动额
*/
@ExcelProperty(index = 3)
private BigDecimal monthlyQuota;
/**
* 最新应收账款余额
*/
@ExcelProperty(index = 4)
private BigDecimal accountReceivableQuota;
/**
* 本月利率(年化)
*/
@ExcelProperty(index = 5)
private BigDecimal dailyInterestRate;
}
controller:
@PostMapping("/import")
public void importCustomerDaily(@RequestParam MultipartFile file) throws IOException {
InputStream inputStream = file.getInputStream();
List<ReqCustomerDailyImport> reqCustomerDailyImports = EasyExcel.read(inputStream)
// 这个转换是成全局的, 所有java为string,excel为string的都会用这个转换器。
// 如果就想单个字段使用请使用@ExcelProperty 指定converter
.registerConverter(new StringConverter())
// 注册监听器,可以在这里校验字段
.registerReadListener(new CustomerDailyImportListener())
.head(ReqCustomerDailyImport.class)
.sheet()
.headRowNumber(2)
.doReadSync();
}
监听器:
public class CustomerDailyImportListener extends AnalysisEventListener {
List misCodes = Lists.newArrayList();
/**
* 每解析一行,回调该方法
* @param data
* @param context
*/
@Override
public void invoke(Object data, AnalysisContext context) {
String misCode = ((ReqCustomerDailyImport) data).getMisCode();
if (StringUtils.isEmpty(misCode)) {
throw new RuntimeException(String.format("第%s行MIS编码为空,请核实", context.readRowHolder().getRowIndex() + 1));
}
if (misCodes.contains(misCodes)) {
throw new RuntimeException(String.format("第%s行MIS编码已重复,请核实", context.readRowHolder().getRowIndex() + 1));
} else {
misCodes.add(misCode);
}
}
/**
* 出现异常回调
* @param exception
* @param context
* @throws Exception
*/
@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
// ExcelDataConvertException:当数据转换异常的时候,会抛出该异常,此处可以得知第几行,第几列的数据
if (exception instanceof ExcelDataConvertException) {
Integer columnIndex = ((ExcelDataConvertException) exception).getColumnIndex() + 1;
Integer rowIndex = ((ExcelDataConvertException) exception).getRowIndex() + 1;
String message = "第" + rowIndex + "行,第" + columnIndex + "列" + "数据格式有误,请核实";
throw new RuntimeException(message);
} else if (exception instanceof RuntimeException) {
throw exception;
} else {
super.onException(exception, context);
}
}
/**
* 解析完全部回调
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
misCodes.clear();
}
}
转换器:
public class StringConverter implements Converter<String> {
@Override
public Class supportJavaTypeKey() {
return String.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/**
* 将excel对象转成Java对象,这里读的时候会调用
*
* @param cellData NotNull
* @param contentProperty Nullable
* @param globalConfiguration NotNull
* @return
*/
@Override
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return "自定义:" + cellData.getStringValue();
}
/**
* 将Java对象转成String对象,写出的时候调用
*
* @param value
* @param contentProperty
* @param globalConfiguration
* @return
*/
@Override
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(value);
}
}
导入相关常用API
注解:
ExcelProperty 指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用名字去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。
ExcelIgnore 默认所有字段都会和excel去匹配,加了这个注解会忽略该字段。
DateTimeFormat 日期转换,用String去接收excel日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat。
NumberFormat 数字转换,用String去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat。
EasyExcel相关参数
readListener 监听器,在读取数据的过程中会不断的调用监听器。
converter 转换器,默认加载了很多转换器。也可以自定义,如果使用的是registerConverter,那么该转换器是全局的,如果要对单个字段生效,可以在ExcelProperty注解的converter指定转换器。
headRowNumber 需要读的表格有几行头数据。默认有一行头,也就是认为第二行开始起为数据。
head 与clazz二选一。读取文件头对应的列表,会根据列表匹配数据,建议使用class。
autoTrim 字符串、表头等数据自动trim。
sheetNo 需要读取Sheet的编码,建议使用这个来指定读取哪个Sheet。
sheetName 根据名字去匹配Sheet,excel 2003不支持根据名字去匹配。
导出
entity:
@Data
@Builder
public class RespCustomerDailyImport {
@ExcelProperty("客户编码")
private String customerName;
@ExcelProperty("MIS编码")
private String misCode;
@ExcelProperty("月度滚动额")
private BigDecimal monthlyQuota;
@ExcelProperty("最新应收账款余额")
private BigDecimal accountReceivableQuota;
@NumberFormat("#.##%")
@ExcelProperty("本月利率(年化)")
private BigDecimal dailyInterestRate;
}
Controller:
@GetMapping("/export")
public void export(HttpServletResponse response) throws IOException {
// 生成数据
List<RespCustomerDailyImport> respCustomerDailyImports = Lists.newArrayList();
for (int i = 0; i < 50; i++) {
RespCustomerDailyImport respCustomerDailyImport = RespCustomerDailyImport.builder()
.misCode(String.valueOf(i))
.customerName("customerName" + i)
.monthlyQuota(new BigDecimal(String.valueOf(i)))
.accountReceivableQuota(new BigDecimal(String.valueOf(i)))
.dailyInterestRate(new BigDecimal(String.valueOf(i))).build();
respCustomerDailyImports.add(respCustomerDailyImport);
}
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("导出", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), RespCustomerDailyImport.class)
.sheet("sheet0")
// 设置字段宽度为自动调整,不太精确
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.doWrite(respCustomerDailyImports);
}
导出相关常用API
注解:
ExcelProperty 指定写到第几列,默认根据成员变量排序。value指定写入的名称,默认成员变量的名字。
ExcelIgnore 默认所有字段都会写入excel,这个注解会忽略这个字段。
DateTimeFormat 日期转换,将Date写到excel会调用这个注解。里面的value参照java.text.SimpleDateFormat。
NumberFormat 数字转换,用Number写excel会调用这个注解。里面的value参照java.text.DecimalFormat。
EasyExcel相关参数
needHead 监听器是否导出头。
useDefaultStyle 写的时候是否是使用默认头。
head 与clazz二选一。写入文件的头列表,建议使用class。
autoTrim 字符串、表头等数据自动trim。
sheetNo 需要写入的编码。默认0。
sheetName 需要些的Sheet名称,默认同sheetNo。
本文暂时没有评论,来添加一个吧(●'◡'●)