easyexcel 设置标题_EasyExcel,让 excel 导入导出更加简单
做積極的人,而不是積極廢人!
來(lái)源:jianshu.com/p/8f3defdc76d4EasyExcelGitHub上的官方說(shuō)明快速開(kāi)始maven倉(cāng)庫(kù)地址導(dǎo)入導(dǎo)出總結(jié)
EasyExcel
在做excel導(dǎo)入導(dǎo)出的時(shí)候,發(fā)現(xiàn)項(xiàng)目中封裝的工具類及其難用,于是去gitHub上找了一些相關(guān)的框架,最終選定了EasyExcel。之前早有聽(tīng)聞該框架,但是一直沒(méi)有去了解,這次借此學(xué)習(xí)一波,提高以后的工作效率。
實(shí)際使用中,發(fā)現(xiàn)是真的很easy,大部分api通過(guò)名稱就能知道大致意思,這點(diǎn)做的很nice。參考文檔,大部分場(chǎng)景的需求基本都能夠滿足。
GitHub上的官方說(shuō)明圖片
快速開(kāi)始
maven倉(cāng)庫(kù)地址
com.alibaba
easyexcel
2.1.2
導(dǎo)入
如下圖excel表格:
建立導(dǎo)入對(duì)應(yīng)實(shí)體類@Data
publicclassReqCustomerDailyImport{
/**
*客戶名稱
*/
@ExcelProperty(index=0)
privateStringcustomerName;
/**
*MIS編碼
*/
@ExcelProperty(index=1)
privateStringmisCode;
/**
*月度滾動(dòng)額
*/
@ExcelProperty(index=3)
privateBigDecimalmonthlyQuota;
/**
*最新應(yīng)收賬款余額
*/
@ExcelProperty(index=4)
privateBigDecimalaccountReceivableQuota;
/**
*本月利率(年化)
*/
@ExcelProperty(index=5)
privateBigDecimaldailyInterestRate;
}
Controller代碼
@PostMapping('/import')
publicvoidimportCustomerDaily(@RequestParamMultipartFilefile)throwsIOException{
InputStreaminputStream=file.getInputStream();
ListreqCustomerDailyImports=EasyExcel.read(inputStream)
.head(ReqCustomerDailyImport.class)
//設(shè)置sheet,默認(rèn)讀取第一個(gè)
.sheet()
//設(shè)置標(biāo)題所在行數(shù)
.headRowNumber(2)
.doReadSync();
}
運(yùn)行結(jié)果圖片
可以看出只需要在實(shí)體對(duì)象使用@ExcelProperty注解,讀取時(shí)指定該class,即可讀取,并且自動(dòng)過(guò)濾了空行,對(duì)于excel的讀取及其簡(jiǎn)單。不過(guò)此時(shí)發(fā)現(xiàn)一個(gè)問(wèn)題,這樣我如果要校驗(yàn)字段該怎么辦?要將字段類型轉(zhuǎn)換成另外一個(gè)類型呢?
不必?fù)?dān)心,我們可以想到的問(wèn)題,作者肯定也考慮到了,下面來(lái)一個(gè)Demo
代碼如下ListreqCustomerDailyImports=EasyExcel.read(inputStream)
//這個(gè)轉(zhuǎn)換是成全局的,所有java為string,excel為string的都會(huì)用這個(gè)轉(zhuǎn)換器。
//如果就想單個(gè)字段使用請(qǐng)使用@ExcelProperty指定converter
.registerConverter(newStringConverter())
//注冊(cè)監(jiān)聽(tīng)器,可以在這里校驗(yàn)字段
.registerReadListener(newCustomerDailyImportListener())
.head(ReqCustomerDailyImport.class)
.sheet()
.headRowNumber(2)
.doReadSync();
}
監(jiān)聽(tīng)器
publicclassCustomerDailyImportListenerextendsAnalysisEventListener{
ListmisCodes=Lists.newArrayList();
/**
*每解析一行,回調(diào)該方法
*@paramdata
*@paramcontext
*/
@Override
publicvoidinvoke(Objectdata,AnalysisContextcontext){
StringmisCode=((ReqCustomerDailyImport)data).getMisCode();
if(StringUtils.isEmpty(misCode)){
thrownewRuntimeException(String.format('第%s行MIS編碼為空,請(qǐng)核實(shí)',context.readRowHolder().getRowIndex()+1));
}
if(misCodes.contains(misCodes)){
thrownewRuntimeException(String.format('第%s行MIS編碼已重復(fù),請(qǐng)核實(shí)',context.readRowHolder().getRowIndex()+1));
}else{
misCodes.add(misCode);
}
}
/**
*出現(xiàn)異常回調(diào)
*@paramexception
*@paramcontext
*@throwsException
*/
@Override
publicvoidonException(Exceptionexception,AnalysisContextcontext)throwsException{
//ExcelDataConvertException:當(dāng)數(shù)據(jù)轉(zhuǎn)換異常的時(shí)候,會(huì)拋出該異常,此處可以得知第幾行,第幾列的數(shù)據(jù)
if(exceptioninstanceofExcelDataConvertException){
IntegercolumnIndex=((ExcelDataConvertException)exception).getColumnIndex()+1;
IntegerrowIndex=((ExcelDataConvertException)exception).getRowIndex()+1;
Stringmessage='第'+rowIndex+'行,第'+columnIndex+'列'+'數(shù)據(jù)格式有誤,請(qǐng)核實(shí)';
thrownewRuntimeException(message);
}elseif(exceptioninstanceofRuntimeException){
throwexception;
}else{
super.onException(exception,context);
}
}
/**
*解析完全部回調(diào)
*@paramcontext
*/
@Override
publicvoiddoAfterAllAnalysed(AnalysisContextcontext){
misCodes.clear();
}
}
轉(zhuǎn)換器publicclassStringConverterimplementsConverter{
@Override
publicClasssupportJavaTypeKey(){
returnString.class;
}
@Override
publicCellDataTypeEnumsupportExcelTypeKey(){
returnCellDataTypeEnum.STRING;
}
/**
*將excel對(duì)象轉(zhuǎn)成Java對(duì)象,這里讀的時(shí)候會(huì)調(diào)用
*
*@paramcellDataNotNull
*@paramcontentPropertyNullable
*@paramglobalConfigurationNotNull
*@return
*/
@Override
publicStringconvertToJavaData(CellDatacellData,ExcelContentPropertycontentProperty,
GlobalConfigurationglobalConfiguration){
return'自定義:'+cellData.getStringValue();
}
/**
*將Java對(duì)象轉(zhuǎn)成String對(duì)象,寫出的時(shí)候調(diào)用
*
*@paramvalue
*@paramcontentProperty
*@paramglobalConfiguration
*@return
*/
@Override
publicCellDataconvertToExcelData(Stringvalue,ExcelContentPropertycontentProperty,
GlobalConfigurationglobalConfiguration){
returnnewCellData(value);
}
}
可以看出注冊(cè)了一個(gè)監(jiān)聽(tīng)器:CustomerDailyImportListener,還注冊(cè)了一個(gè)轉(zhuǎn)換器:StringConverter。流程為:框架讀取一行數(shù)據(jù),先執(zhí)行轉(zhuǎn)換器,當(dāng)一行數(shù)據(jù)轉(zhuǎn)換完成,執(zhí)行監(jiān)聽(tīng)器的回調(diào)方法,如果轉(zhuǎn)換的過(guò)程中,出現(xiàn)轉(zhuǎn)換異常,也會(huì)回調(diào)監(jiān)聽(tīng)器中的onException方法。因此,可以在監(jiān)聽(tīng)器中校驗(yàn)數(shù)據(jù),在轉(zhuǎn)換器中轉(zhuǎn)換數(shù)據(jù)類型或者格式。
運(yùn)行結(jié)果圖片
修改一下表格,測(cè)試校驗(yàn)是否生效圖片
再次導(dǎo)入,查看運(yùn)行結(jié)果圖片
導(dǎo)入相關(guān)常用API
注解ExcelProperty 指定當(dāng)前字段對(duì)應(yīng)excel中的那一列。可以根據(jù)名字或者Index去匹配。當(dāng)然也可以不寫,默認(rèn)第一個(gè)字段就是index=0,以此類推。千萬(wàn)注意,要么全部不寫,要么全部用index,要么全部用名字去匹配。千萬(wàn)別三個(gè)混著用,除非你非常了解源代碼中三個(gè)混著用怎么去排序的。ExcelIgnore 默認(rèn)所有字段都會(huì)和excel去匹配,加了這個(gè)注解會(huì)忽略該字段。DateTimeFormat 日期轉(zhuǎn)換,用String去接收excel日期格式的數(shù)據(jù)會(huì)調(diào)用這個(gè)注解。里面的value參照java.text.SimpleDateFormat。NumberFormat 數(shù)字轉(zhuǎn)換,用String去接收excel數(shù)字格式的數(shù)據(jù)會(huì)調(diào)用這個(gè)注解。里面的value參照java.text.DecimalFormat。
EasyExcel相關(guān)參數(shù)readListener 監(jiān)聽(tīng)器,在讀取數(shù)據(jù)的過(guò)程中會(huì)不斷的調(diào)用監(jiān)聽(tīng)器。converter 轉(zhuǎn)換器,默認(rèn)加載了很多轉(zhuǎn)換器。也可以自定義,如果使用的是registerConverter,那么該轉(zhuǎn)換器是全局的,如果要對(duì)單個(gè)字段生效,可以在ExcelProperty注解的converter指定轉(zhuǎn)換器。headRowNumber 需要讀的表格有幾行頭數(shù)據(jù)。默認(rèn)有一行頭,也就是認(rèn)為第二行開(kāi)始起為數(shù)據(jù)。head 與clazz二選一。讀取文件頭對(duì)應(yīng)的列表,會(huì)根據(jù)列表匹配數(shù)據(jù),建議使用class。autoTrim 字符串、表頭等數(shù)據(jù)自動(dòng)trim。sheetNo 需要讀取Sheet的編碼,建議使用這個(gè)來(lái)指定讀取哪個(gè)Sheet。sheetName 根據(jù)名字去匹配Sheet,excel 2003不支持根據(jù)名字去匹配。
導(dǎo)出
建立導(dǎo)出對(duì)應(yīng)實(shí)體類
@Data
@Builder
publicclassRespCustomerDailyImport{
@ExcelProperty('客戶編碼')
privateStringcustomerName;
@ExcelProperty('MIS編碼')
privateStringmisCode;
@ExcelProperty('月度滾動(dòng)額')
privateBigDecimalmonthlyQuota;
@ExcelProperty('最新應(yīng)收賬款余額')
privateBigDecimalaccountReceivableQuota;
@NumberFormat('#.##%')
@ExcelProperty('本月利率(年化)')
privateBigDecimaldailyInterestRate;
}
Controller代碼@GetMapping('/export')
publicvoidexport(HttpServletResponseresponse)throwsIOException{
//生成數(shù)據(jù)
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可以防止中文亂碼當(dāng)然和easyexcel沒(méi)有關(guān)系
StringfileName=URLEncoder.encode('導(dǎo)出','UTF-8');
response.setHeader('Content-disposition','attachment;filename='+fileName+'.xlsx');
EasyExcel.write(response.getOutputStream(),RespCustomerDailyImport.class)
.sheet('sheet0')
//設(shè)置字段寬度為自動(dòng)調(diào)整,不太精確
.registerWriteHandler(newLongestMatchColumnWidthStyleStrategy())
.doWrite(respCustomerDailyImports);
}
導(dǎo)出效果圖片
導(dǎo)出相關(guān)常用API
注解ExcelProperty 指定寫到第幾列,默認(rèn)根據(jù)成員變量排序。value指定寫入的名稱,默認(rèn)成員變量的名字。ExcelIgnore 默認(rèn)所有字段都會(huì)寫入excel,這個(gè)注解會(huì)忽略這個(gè)字段。DateTimeFormat 日期轉(zhuǎn)換,將Date寫到excel會(huì)調(diào)用這個(gè)注解。里面的value參照java.text.SimpleDateFormat。NumberFormat 數(shù)字轉(zhuǎn)換,用Number寫excel會(huì)調(diào)用這個(gè)注解。里面的value參照java.text.DecimalFormat。
EasyExcel相關(guān)參數(shù)needHead 監(jiān)聽(tīng)器是否導(dǎo)出頭。useDefaultStyle 寫的時(shí)候是否是使用默認(rèn)頭。head 與clazz二選一。寫入文件的頭列表,建議使用class。autoTrim 字符串、表頭等數(shù)據(jù)自動(dòng)trim。sheetNo 需要寫入的編碼。默認(rèn)0。sheetName 需要些的Sheet名稱,默認(rèn)同sheetNo。
總結(jié)
可以看出不管是excel的讀取還是寫入,都是一個(gè)注解加上一行代碼完成,可以讓我們少些很多解析的代碼,極大減少了重復(fù)的工作量。當(dāng)然這兩個(gè)例子使用了最簡(jiǎn)單的方式,EasyExcel還支持更多場(chǎng)景,例如讀,可以讀多個(gè)sheet,也可以解析一行數(shù)據(jù)或者多行數(shù)據(jù)做一次入庫(kù)操作;寫的話,支持復(fù)雜頭,指定列寫入,重復(fù)多次寫入,多個(gè)sheet寫入,根據(jù)模板寫入等等。更多的例子可以去參考EasyExcel官方文檔https://www.yuque.com/easyexcel/doc/easyexcel
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的easyexcel 设置标题_EasyExcel,让 excel 导入导出更加简单的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java comp env 区别_加和不
- 下一篇: java float x=26f_东软j