在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一款解決大文件內存溢出的 Excel 處理工具

jf_ro2CN3Fa ? 來源:芋道源碼 ? 2023-07-03 16:11 ? 次閱讀

介紹

快速開始

引入依賴

簡單導出

定義實體類

復雜導出

簡單導入

參考資料

介紹

EasyExcel 是一個基于 Java 的、快速、簡潔、解決大文件內存溢出的 Excel 處理工具。它能讓你在不用考慮性能、內存的等因素的情況下,快速完成 Excel 的讀、寫等功能。

EasyExcel文檔地址:

https://easyexcel.opensource.alibaba.com/

基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

項目地址:https://github.com/YunaiV/ruoyi-vue-pro

視頻教程:https://doc.iocoder.cn/video/

快速開始

引入依賴


com.alibaba
easyexcel
3.1.3

簡單導出

以導出用戶信息為例,接下來手把手教大家如何使用EasyExcel實現導出功能!

定義實體類

在EasyExcel中,以面向對象思想來實現導入導出,無論是導入數據還是導出數據都可以想象成具體某個對象的集合,所以為了實現導出用戶信息功能,首先創建一個用戶對象UserDO實體類,用于封裝用戶信息:

/**
*用戶信息
*
*@authorwilliam@StarImmortal
*/
@Data
publicclassUserDO{
@ExcelProperty("用戶編號")
@ColumnWidth(20)
privateLongid;

@ExcelProperty("用戶名")
@ColumnWidth(20)
privateStringusername;

@ExcelIgnore
privateStringpassword;

@ExcelProperty("昵稱")
@ColumnWidth(20)
privateStringnickname;

@ExcelProperty("生日")
@ColumnWidth(20)
@DateTimeFormat("yyyy-MM-dd")
privateDatebirthday;

@ExcelProperty("手機號")
@ColumnWidth(20)
privateStringphone;

@ExcelProperty("身高(米)")
@NumberFormat("#.##")
@ColumnWidth(20)
privateDoubleheight;

@ExcelProperty(value="性別",converter=GenderConverter.class)
@ColumnWidth(10)
privateIntegergender;
}

上面代碼中類屬性上使用了EasyExcel核心注解:

@ExcelProperty: 核心注解,value屬性可用來設置表頭名稱,converter屬性可以用來設置類型轉換器

@ColumnWidth: 用于設置表格列的寬度;

@DateTimeFormat: 用于設置日期轉換格式;

@NumberFormat: 用于設置數字轉換格式。

自定義轉換器

在EasyExcel中,如果想實現枚舉類型到字符串類型轉換(例如gender屬性:1 -> 男,2 -> 女),需實現Converter接口來自定義轉換器,下面為自定義GenderConverter性別轉換器代碼實現:

/**
*Excel性別轉換器
*
*@authorwilliam@StarImmortal
*/
publicclassGenderConverterimplementsConverter{
@Override
publicClasssupportJavaTypeKey(){
returnInteger.class;
}

@Override
publicCellDataTypeEnumsupportExcelTypeKey(){
returnCellDataTypeEnum.STRING;
}

@Override
publicIntegerconvertToJavaData(ReadConverterContextcontext){
returnGenderEnum.convert(context.getReadCellData().getStringValue()).getValue();
}

@Override
publicWriteCellDataconvertToExcelData(WriteConverterContextcontext){
returnnewWriteCellData<>(GenderEnum.convert(context.getValue()).getDescription());
}
}
/**
*性別枚舉
*
*@authorwilliam@StarImmortal
*/
@Getter
@AllArgsConstructor
publicenumGenderEnum{

/**
*未知
*/
UNKNOWN(0,"未知"),

/**
*男性
*/
MALE(1,"男性"),

/**
*女性
*/
FEMALE(2,"女性");

privatefinalIntegervalue;

@JsonFormat
privatefinalStringdescription;

publicstaticGenderEnumconvert(Integervalue){
returnStream.of(values())
.filter(bean->bean.value.equals(value))
.findAny()
.orElse(UNKNOWN);
}

publicstaticGenderEnumconvert(Stringdescription){
returnStream.of(values())
.filter(bean->bean.description.equals(description))
.findAny()
.orElse(UNKNOWN);
}
}

定義接口

/**
*EasyExcel導入導出
*
*@authorwilliam@StarImmortal
*/
@RestController
@RequestMapping("/excel")
publicclassExcelController{

@GetMapping("/export/user")
publicvoidexportUserExcel(HttpServletResponseresponse){
try{
this.setExcelResponseProp(response,"用戶列表");
ListuserList=this.getUserList();
EasyExcel.write(response.getOutputStream())
.head(UserDO.class)
.excelType(ExcelTypeEnum.XLSX)
.sheet("用戶列表")
.doWrite(userList);
}catch(IOExceptione){
thrownewRuntimeException(e);
}
}

/**
*設置響應結果
*
*@paramresponse響應結果對象
*@paramrawFileName文件名
*@throwsUnsupportedEncodingException不支持編碼異常
*/
privatevoidsetExcelResponseProp(HttpServletResponseresponse,StringrawFileName)throwsUnsupportedEncodingException{
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
StringfileName=URLEncoder.encode(rawFileName,"UTF-8").replaceAll("+","%20");
response.setHeader("Content-disposition","attachment;filename*=utf-8''"+fileName+".xlsx");
}

/**
*讀取用戶列表數據
*
*@return用戶列表數據
*@throwsIOExceptionIO異常
*/
privateListgetUserList()throwsIOException{
ObjectMapperobjectMapper=newObjectMapper();
ClassPathResourceclassPathResource=newClassPathResource("mock/users.json");
InputStreaminputStream=classPathResource.getInputStream();
returnobjectMapper.readValue(inputStream,newTypeReference>(){
});
}
}

測試接口

運行項目,通過 Postman 或者 Apifox 工具來進行接口測試

注意:在 Apifox 中訪問接口后無法直接下載,需要點擊返回結果中的下載圖標才行,點擊之后方可對Excel文件進行保存。

接口地址:http://localhost:8080/excel/export/user

d9d6b51c-17b7-11ee-962d-dac502259ad0.pngda05fffc-17b7-11ee-962d-dac502259ad0.png

復雜導出

由于 EasyPoi 支持嵌套對象導出,直接使用內置 @ExcelCollection 注解即可實現,遺憾的是 EasyExcel 不支持一對多導出,只能自行實現,通過此issues了解到,項目維護者建議通過自定義合并策略方式來實現一對多導出。

da25636a-17b7-11ee-962d-dac502259ad0.png

解決思路:只需把訂單主鍵相同的列中需要合并的列給合并了,就可以實現這種一對多嵌套信息的導出

自定義注解

創建一個自定義注解,用于標記哪些屬性需要合并單元格,哪個屬性是主鍵:

/**
*用于判斷是否需要合并以及合并的主鍵
*
*@authorwilliam@StarImmortal
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interfaceExcelMerge{
/**
*是否合并單元格
*
*@returntrue||false
*/
booleanmerge()defaulttrue;

/**
*是否為主鍵(即該字段相同的行合并)
*
*@returntrue||false
*/
booleanisPrimaryKey()defaultfalse;
}

定義實體類

在需要合并單元格的屬性上設置 @ExcelMerge 注解,二級表頭通過設置 @ExcelProperty 注解中 value 值為數組形式來實現該效果:

/**
*@authorwilliam@StarImmortal
*/
@Data
publicclassOrderBO{
@ExcelProperty(value="訂單主鍵")
@ColumnWidth(16)
@ExcelMerge(merge=true,isPrimaryKey=true)
privateStringid;

@ExcelProperty(value="訂單編號")
@ColumnWidth(20)
@ExcelMerge(merge=true)
privateStringorderId;

@ExcelProperty(value="收貨地址")
@ExcelMerge(merge=true)
@ColumnWidth(20)
privateStringaddress;

@ExcelProperty(value="創建時間")
@ColumnWidth(20)
@DateTimeFormat("yyyy-MM-ddHHss")
@ExcelMerge(merge=true)
privateDatecreateTime;

@ExcelProperty(value={"商品信息","商品編號"})
@ColumnWidth(20)
privateStringproductId;

@ExcelProperty(value={"商品信息","商品名稱"})
@ColumnWidth(20)
privateStringname;

@ExcelProperty(value={"商品信息","商品標題"})
@ColumnWidth(30)
privateStringsubtitle;

@ExcelProperty(value={"商品信息","品牌名稱"})
@ColumnWidth(20)
privateStringbrandName;

@ExcelProperty(value={"商品信息","商品價格"})
@ColumnWidth(20)
privateBigDecimalprice;

@ExcelProperty(value={"商品信息","商品數量"})
@ColumnWidth(20)
privateIntegercount;
}

數據映射與平鋪

導出之前,需要對數據進行處理,將訂單數據進行平鋪,orderList為平鋪前格式,exportData為平鋪后格式:

da5a96a2-17b7-11ee-962d-dac502259ad0.png

自定義單元格合并策略

當 Excel 中兩列主鍵相同時,合并被標記需要合并的列:

/**
*自定義單元格合并策略
*
*@authorwilliam@StarImmortal
*/
publicclassExcelMergeStrategyimplementsRowWriteHandler{

/**
*主鍵下標
*/
privateIntegerprimaryKeyIndex;

/**
*需要合并的列的下標集合
*/
privatefinalListmergeColumnIndexList=newArrayList<>();

/**
*數據類型
*/
privatefinalClasselementType;

publicExcelMergeStrategy(ClasselementType){
this.elementType=elementType;
}

@Override
publicvoidafterRowDispose(WriteSheetHolderwriteSheetHolder,WriteTableHolderwriteTableHolder,Rowrow,IntegerrelativeRowIndex,BooleanisHead){
//判斷是否為標題
if(isHead){
return;
}
//獲取當前工作表
Sheetsheet=writeSheetHolder.getSheet();
//初始化主鍵下標和需要合并字段的下標
if(primaryKeyIndex==null){
this.initPrimaryIndexAndMergeIndex(writeSheetHolder);
}
//判斷是否需要和上一行進行合并
//不能和標題合并,只能數據行之間合并
if(row.getRowNum()<=?1)?{
????????????return;
????????}
????????//?獲取上一行數據
????????Row?lastRow?=?sheet.getRow(row.getRowNum()?-?1);
????????//?將本行和上一行是同一類型的數據(通過主鍵字段進行判斷),則需要合并
????????if?(lastRow.getCell(primaryKeyIndex).getStringCellValue().equalsIgnoreCase(row.getCell(primaryKeyIndex).getStringCellValue()))?{
????????????for?(Integer?mergeIndex?:?mergeColumnIndexList)?{
????????????????CellRangeAddress?cellRangeAddress?=?new?CellRangeAddress(row.getRowNum()?-?1,?row.getRowNum(),?mergeIndex,?mergeIndex);
????????????????sheet.addMergedRegionUnsafe(cellRangeAddress);
????????????}
????????}
????}

????/**
?????*?初始化主鍵下標和需要合并字段的下標
?????*
?????*?@param?writeSheetHolder?WriteSheetHolder
?????*/
????private?void?initPrimaryIndexAndMergeIndex(WriteSheetHolder?writeSheetHolder)?{
????????//?獲取當前工作表
????????Sheet?sheet?=?writeSheetHolder.getSheet();
????????//?獲取標題行
????????Row?titleRow?=?sheet.getRow(0);
????????//?獲取所有屬性字段
????????Field[]?fields?=?this.elementType.getDeclaredFields();
????????//?遍歷所有字段
????????for?(Field?field?:?fields)?{
????????????//?獲取@ExcelProperty注解,用于獲取該字段對應列的下標
????????????ExcelProperty?excelProperty?=?field.getAnnotation(ExcelProperty.class);
????????????//?判斷是否為空
????????????if?(null?==?excelProperty)?{
????????????????continue;
????????????}
????????????//?獲取自定義注解,用于合并單元格
????????????ExcelMerge?excelMerge?=?field.getAnnotation(ExcelMerge.class);
????????????//?判斷是否需要合并
????????????if?(null?==?excelMerge)?{
????????????????continue;
????????????}
????????????for?(int?i?=?0;?i?

定義接口

將自定義合并策略 ExcelMergeStrategy 通過 registerWriteHandler 注冊上去:

/**
*EasyExcel導入導出
*
*@authorwilliam@StarImmortal
*/
@RestController
@RequestMapping("/excel")
publicclassExcelController{

@GetMapping("/export/order")
publicvoidexportOrderExcel(HttpServletResponseresponse){
try{
this.setExcelResponseProp(response,"訂單列表");
ListorderList=this.getOrderList();
ListexportData=this.convert(orderList);
EasyExcel.write(response.getOutputStream())
.head(OrderBO.class)
.registerWriteHandler(newExcelMergeStrategy(OrderBO.class))
.excelType(ExcelTypeEnum.XLSX)
.sheet("訂單列表")
.doWrite(exportData);
}catch(IOExceptione){
thrownewRuntimeException(e);
}
}

/**
*設置響應結果
*
*@paramresponse響應結果對象
*@paramrawFileName文件名
*@throwsUnsupportedEncodingException不支持編碼異常
*/
privatevoidsetExcelResponseProp(HttpServletResponseresponse,StringrawFileName)throwsUnsupportedEncodingException{
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
StringfileName=URLEncoder.encode(rawFileName,"UTF-8").replaceAll("+","%20");
response.setHeader("Content-disposition","attachment;filename*=utf-8''"+fileName+".xlsx");
}
}

測試接口

運行項目,通過 Postman 或者 Apifox 工具來進行接口測試

注意:在 Apifox 中訪問接口后無法直接下載,需要點擊返回結果中的下載圖標才行,點擊之后方可對Excel文件進行保存。

接口地址:http://localhost:8080/excel/export/order

da8b135e-17b7-11ee-962d-dac502259ad0.pngdac00fe6-17b7-11ee-962d-dac502259ad0.png

簡單導入

以導入用戶信息為例,接下來手把手教大家如何使用EasyExcel實現導入功能!

/**
*EasyExcel導入導出
*
*@authorwilliam@StarImmortal
*/
@RestController
@RequestMapping("/excel")
@Api(tags="EasyExcel")
publicclassExcelController{

@PostMapping("/import/user")
publicResponseVOimportUserExcel(@RequestPart(value="file")MultipartFilefile){
try{
ListuserList=EasyExcel.read(file.getInputStream())
.head(UserDO.class)
.sheet()
.doReadSync();
returnResponseVO.success(userList);
}catch(IOExceptione){
returnResponseVO.error();
}
}
}
dafb5a4c-17b7-11ee-962d-dac502259ad0.png

責任編輯:彭菁

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3096

    瀏覽量

    74828
  • 文件
    +關注

    關注

    1

    文章

    575

    瀏覽量

    25075
  • Excel
    +關注

    關注

    4

    文章

    225

    瀏覽量

    56201

原文標題:SpringBoot 集成 EasyExcel 3.x 優雅實現 Excel 導入導出

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux平臺大文件生成和處理方法

    在日常工作中,為了驗證某些場景下的功能,經常需要人為構造大文件進行測試,有時需要用大文件來測試下載速度,有時需要用大文件來覆蓋磁盤空間;偶爾會看到
    發表于 07-14 16:38 ?4176次閱讀

    Python利用pandas讀寫Excel文件

    使用pandas模塊讀取Excel文件可以更為方便和快捷。pandas可以將Excel文件讀取為個DataFrame對象,方便進行數據
    的頭像 發表于 12-16 11:22 ?1680次閱讀
    Python利用pandas讀寫<b class='flag-5'>Excel</b><b class='flag-5'>文件</b>

    ReqMan需求提取和協同處理工具怎么樣看了就知道

    ReqMan是由德國engineering method AG公司開發的一款高效的、可自由定制的需求提取和協同處理工具。ReqMan 能夠將PDF、Word、Excel等格式的文檔提取出來并將需求條目化,同時提供了多種文檔格式之
    發表于 03-08 07:52

    介紹一款蘋果操作系統的電源管理工具

    Power Manager for Mac是蘋果操作系統上的一款筆記本電源管理工具,該工具支持蘋果系列的筆記本,可以有效地優化蘋果系統,結束不必要的系統任務,同時還可以提高筆記本電池的使用量
    發表于 01-03 07:42

    基于PHP大文件上傳的研究和設計

    基于PHP大文件上傳的研究和設計,感興趣的可以看看。
    發表于 02-22 18:15 ?6次下載

    TXT大文件切割軟體應用程序免費下載

    本文檔的主要內容詳細是TXT大文件切割軟體應用程序免費下載,可以切割任意大小的txt文件,可以根據大小,數量,標題等類別進行切割,絕對是大文件切割的必備工具,該軟體綠色免安裝,誰用誰知
    發表于 11-07 08:00 ?5次下載
    TXT<b class='flag-5'>大文件</b>切割軟體應用程序免費下載

    內存溢出內存泄露的區別_內存溢出的原因以及解決方法

    內存溢出內存泄露的區別是什么?內存溢出怎么解決?內存溢出
    發表于 06-01 10:27 ?3021次閱讀

    EXCEL大文件Vlookup工具”使用步驟資料下載

    電子發燒友網為你提供EXCEL大文件Vlookup工具”使用步驟資料下載的電子資料下載,更有其他相關的電路圖、源代碼、課件教程、中文資料、英文資料、參考設計、用戶指南、解決方案等資料,希望可以幫助到廣大的電子工程師們。
    發表于 04-28 08:55 ?16次下載
    <b class='flag-5'>EXCEL</b>“<b class='flag-5'>大文件</b>Vlookup<b class='flag-5'>工具</b>”使用步驟資料下載

    如何通過python輕松處理大文件

    眾所周知,python除了以簡潔著稱,其成熟的第三方庫功能也是很強大的,今天浩道帶大家看看如何通過python輕松處理大文件,真讓人直呼yyds 。
    的頭像 發表于 04-27 10:54 ?987次閱讀

    如何解決內存溢出

    ,有時候會自動關閉軟件,重啟電腦或者軟件后釋放掉一部分內存又可以正常運行該軟件,而由系統配置、數據流、用戶代碼等原因而導致的內存溢出錯誤,即使用戶重新執行任務依然無法避免 其實很簡單,在 Java 中,那就是 Out Of Me
    的頭像 發表于 09-25 10:54 ?1598次閱讀
    如何解決<b class='flag-5'>內存</b><b class='flag-5'>溢出</b>

    java內存溢出排查方法

    過程中常見的問題之,可能導致應用程序崩潰、性能下降甚至系統崩潰。在本文中,將詳細介紹如何排查和解決Java內存溢出問題。 、什么是Java內存
    的頭像 發表于 11-23 14:46 ?3615次閱讀

    jvm內存溢出故障排查

    JVM內存溢出是常見且令人頭疼的問題,特別是在運行大型Java應用程序或長時間運行的應用程序時。當JVM分配給應用程序的內存不足以處理應用程序所需的數據時,就會發生
    的頭像 發表于 12-05 11:04 ?1000次閱讀

    jvm內存溢出該如何定位解決

    超出限制和堆空間不足。 定位JVM內存溢出問題是個比較復雜的任務,需要結合工具和技術來進行分析和解決。本文將介紹些常用的調試和解決
    的頭像 發表于 12-05 11:05 ?1485次閱讀

    內存溢出內存泄漏:定義、區別與解決方案

    內存溢出內存泄漏:定義、區別與解決方案? 內存溢出內存泄漏是計算機科學中常見的問題,在開發和
    的頭像 發表于 12-19 14:10 ?3344次閱讀

    Spire.Cloud.Excel云端Excel文檔處理SDK

    Spire.Cloud.Excel一款專業的云端 Excel 文檔處理 SDK,開發人員可調用 SDK 在云端創建、讀取、編輯、轉換、及保存 E
    的頭像 發表于 02-13 11:03 ?277次閱讀
    Spire.Cloud.<b class='flag-5'>Excel</b>云端<b class='flag-5'>Excel</b>文檔<b class='flag-5'>處理</b>SDK
    主站蜘蛛池模板: 98pao强力打造高清免费 | 456成人网 | 欧美色图首页 | 狠狠色成色综合网 | 四虎影城库 | 亚洲jizzjizz | 美女网站黄页 | 国产欧美久久久精品影院 | 天堂网www在线观看 天堂网www在线资源中文 | 日本色片视频 | 久久天天躁狠狠躁夜夜躁综合 | 黄色的视频网站 | 国产aa | 色播欧美 | 久久久久免费 | 欧美黄色片 一级片 | 国产综合色在线视频区色吧图片 | 国产三级在线 | 久久午夜免费视频 | 日本人xxxxxxxxx69 | 99热这里只有精品一区二区三区 | 色狠狠色综合吹潮 | 日本免费人成黄页网观看视频 | 丁香五婷婷 | 在线精品一区二区三区 | 亚洲欧美日韩另类精品一区二区三区 | 色噜噜噜噜噜 | 亚洲成色www久久网站 | 日本视频色 | 日本中文字幕在线播放 | 亚洲成年人影院 | 美女露出扒开尿口让男人桶 | 99久久精品免费观看国产 | 天天看天天爽天天摸天天添 | 午夜免费福利视频 | 亚洲一区二区三区麻豆 | 夜夜狠| 69日本xxxxxxxxx98 69日本xxxxxxxxx内谢 | 四虎影院国产精品 | 激情6月丁香婷婷色综合 | 亚洲综合免费 |