easyexcel 设置标题_EasyExcel,让 excel 导入导出更加简单

本文介绍了EasyExcel框架,用于简化Excel的导入导出操作。通过示例展示了如何使用EasyExcel进行数据导入,包括设置标题、实体类注解、监听器和转换器,以及数据校验和类型转换。此外,还提供了导出数据的示例,演示了如何配置导出的实体类、设置导出头和自定义样式。EasyExcel通过简单的API大大减少了Excel处理的复杂性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

做积极的人,而不是积极废人!

来源:jianshu.com/p/8f3defdc76d4EasyExcelGitHub上的官方说明快速开始maven仓库地址导入导出总结

EasyExcel

在做excel导入导出的时候,发现项目中封装的工具类及其难用,于是去gitHub上找了一些相关的框架,最终选定了EasyExcel。之前早有听闻该框架,但是一直没有去了解,这次借此学习一波,提高以后的工作效率。

实际使用中,发现是真的很easy,大部分api通过名称就能知道大致意思,这点做的很nice。参考文档,大部分场景的需求基本都能够满足。

GitHub上的官方说明图片

快速开始

maven仓库地址

com.alibaba

easyexcel

2.1.2

导入

如下图excel表格:

建立导入对应实体类@Data

publicclassReqCustomerDailyImport{

/**

*客户名称

*/

@ExcelProperty(index=0)

privateStringcustomerName;

/**

*MIS编码

*/

@ExcelProperty(index=1)

privateStringmisCode;

/**

*月度滚动额

*/

@ExcelProperty(index=3)

privateBigDecimalmonthlyQuota;

/**

*最新应收账款余额

*/

@ExcelProperty(index=4)

privateBigDecimalaccountReceivableQuota;

/**

*本月利率(年化)

*/

@ExcelProperty(index=5)

privateBigDecimaldailyInterestRate;

}

Controller代码

@PostMapping('/import')

publicvoidimportCustomerDaily(@RequestParamMultipartFilefile)throwsIOException{

InputStreaminputStream=file.getInputStream();

ListreqCustomerDailyImports=EasyExcel.read(inputStream)

.head(ReqCustomerDailyImport.class)

//设置sheet,默认读取第一个

.sheet()

//设置标题所在行数

.headRowNumber(2)

.doReadSync();

}

运行结果图片

可以看出只需要在实体对象使用@ExcelProperty注解,读取时指定该class,即可读取,并且自动过滤了空行,对于excel的读取及其简单。不过此时发现一个问题,这样我如果要校验字段该怎么办?要将字段类型转换成另外一个类型呢?

不必担心,我们可以想到的问题,作者肯定也考虑到了,下面来一个Demo

代码如下ListreqCustomerDailyImports=EasyExcel.read(inputStream)

//这个转换是成全局的,所有java为string,excel为string的都会用这个转换器。

//如果就想单个字段使用请使用@ExcelProperty指定converter

.registerConverter(newStringConverter())

//注册监听器,可以在这里校验字段

.registerReadListener(newCustomerDailyImportListener())

.head(ReqCustomerDailyImport.class)

.sheet()

.headRowNumber(2)

.doReadSync();

}

监听器

publicclassCustomerDailyImportListenerextendsAnalysisEventListener{

ListmisCodes=Lists.newArrayList();

/**

*每解析一行,回调该方法

*@paramdata

*@paramcontext

*/

@Override

publicvoidinvoke(Objectdata,AnalysisContextcontext){

StringmisCode=((ReqCustomerDailyImport)data).getMisCode();

if(StringUtils.isEmpty(misCode)){

thrownewRuntimeException(String.format('第%s行MIS编码为空,请核实',context.readRowHolder().getRowIndex()+1));

}

if(misCodes.contains(misCodes)){

thrownewRuntimeException(String.format('第%s行MIS编码已重复,请核实',context.readRowHolder().getRowIndex()+1));

}else{

misCodes.add(misCode);

}

}

/**

*出现异常回调

*@paramexception

*@paramcontext

*@throwsException

*/

@Override

publicvoidonException(Exceptionexception,AnalysisContextcontext)throwsException{

//ExcelDataConvertException:当数据转换异常的时候,会抛出该异常,此处可以得知第几行,第几列的数据

if(exceptioninstanceofExcelDataConvertException){

IntegercolumnIndex=((ExcelDataConvertException)exception).getColumnIndex()+1;

IntegerrowIndex=((ExcelDataConvertException)exception).getRowIndex()+1;

Stringmessage='第'+rowIndex+'行,第'+columnIndex+'列'+'数据格式有误,请核实';

thrownewRuntimeException(message);

}elseif(exceptioninstanceofRuntimeException){

throwexception;

}else{

super.onException(exception,context);

}

}

/**

*解析完全部回调

*@paramcontext

*/

@Override

publicvoiddoAfterAllAnalysed(AnalysisContextcontext){

misCodes.clear();

}

}

转换器publicclassStringConverterimplementsConverter{

@Override

publicClasssupportJavaTypeKey(){

returnString.class;

}

@Override

publicCellDataTypeEnumsupportExcelTypeKey(){

returnCellDataTypeEnum.STRING;

}

/**

*将excel对象转成Java对象,这里读的时候会调用

*

*@paramcellDataNotNull

*@paramcontentPropertyNullable

*@paramglobalConfigurationNotNull

*@return

*/

@Override

publicStringconvertToJavaData(CellDatacellData,ExcelContentPropertycontentProperty,

GlobalConfigurationglobalConfiguration){

return'自定义:'+cellData.getStringValue();

}

/**

*将Java对象转成String对象,写出的时候调用

*

*@paramvalue

*@paramcontentProperty

*@paramglobalConfiguration

*@return

*/

@Override

publicCellDataconvertToExcelData(Stringvalue,ExcelContentPropertycontentProperty,

GlobalConfigurationglobalConfiguration){

returnnewCellData(value);

}

}

可以看出注册了一个监听器:CustomerDailyImportListener,还注册了一个转换器:StringConverter。流程为:框架读取一行数据,先执行转换器,当一行数据转换完成,执行监听器的回调方法,如果转换的过程中,出现转换异常,也会回调监听器中的onException方法。因此,可以在监听器中校验数据,在转换器中转换数据类型或者格式。

运行结果图片

修改一下表格,测试校验是否生效图片

再次导入,查看运行结果图片

导入相关常用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不支持根据名字去匹配。

导出

建立导出对应实体类

@Data

@Builder

publicclassRespCustomerDailyImport{

@ExcelProperty('客户编码')

privateStringcustomerName;

@ExcelProperty('MIS编码')

privateStringmisCode;

@ExcelProperty('月度滚动额')

privateBigDecimalmonthlyQuota;

@ExcelProperty('最新应收账款余额')

privateBigDecimalaccountReceivableQuota;

@NumberFormat('#.##%')

@ExcelProperty('本月利率(年化)')

privateBigDecimaldailyInterestRate;

}

Controller代码@GetMapping('/export')

publicvoidexport(HttpServletResponseresponse)throwsIOException{

//生成数据

ListrespCustomerDailyImports=Lists.newArrayList();

for(inti=0;i<50;i++){

RespCustomerDailyImportrespCustomerDailyImport=RespCustomerDailyImport.builder()

.misCode(String.valueOf(i))

.customerName('customerName'+i)

.monthlyQuota(newBigDecimal(String.valueOf(i)))

.accountReceivableQuota(newBigDecimal(String.valueOf(i)))

.dailyInterestRate(newBigDecimal(String.valueOf(i))).build();

respCustomerDailyImports.add(respCustomerDailyImport);

}

response.setContentType('application/vnd.ms-excel');

response.setCharacterEncoding('utf-8');

//这里URLEncoder.encode可以防止中文乱码当然和easyexcel没有关系

StringfileName=URLEncoder.encode('导出','UTF-8');

response.setHeader('Content-disposition','attachment;filename='+fileName+'.xlsx');

EasyExcel.write(response.getOutputStream(),RespCustomerDailyImport.class)

.sheet('sheet0')

//设置字段宽度为自动调整,不太精确

.registerWriteHandler(newLongestMatchColumnWidthStyleStrategy())

.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。

总结

可以看出不管是excel的读取还是写入,都是一个注解加上一行代码完成,可以让我们少些很多解析的代码,极大减少了重复的工作量。当然这两个例子使用了最简单的方式,EasyExcel还支持更多场景,例如读,可以读多个sheet,也可以解析一行数据或者多行数据做一次入库操作;写的话,支持复杂头,指定列写入,重复多次写入,多个sheet写入,根据模板写入等等。更多的例子可以去参考EasyExcel官方文档https://www.yuque.com/easyexcel/doc/easyexcel

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值