在线观看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

    文章

    3055

    瀏覽量

    74331
  • 文件
    +關注

    關注

    1

    文章

    570

    瀏覽量

    24822
  • Excel
    +關注

    關注

    4

    文章

    224

    瀏覽量

    55627

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

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

收藏 人收藏

    評論

    相關推薦

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

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

    Python利用pandas讀寫Excel文件

    使用pandas模塊讀取Excel文件可以更為方便和快捷。pandas可以將Excel文件讀取為個DataFrame對象,方便進行數據
    的頭像 發表于 12-16 11:22 ?1453次閱讀
    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 ?2954次閱讀

    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 ?917次閱讀

    一款任務日程管理工具ToDoList

    ? 1.軟件介紹 2.軟件功能 3 試用感受 推薦給大家一款開源免費的任務日程管理工具ToDoList,是適合職場人尤其是程序員的經典任務管理軟件,使用好的話會讓大家在工作中事半功倍。 1.軟件介紹
    的頭像 發表于 07-05 10:00 ?1407次閱讀
    <b class='flag-5'>一款</b>任務日程管<b class='flag-5'>理工具</b>ToDoList

    如何解決內存溢出

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

    java內存溢出排查方法

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

    jvm內存溢出故障排查

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

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

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

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

    內存溢出內存泄漏:定義、區別與解決方案? 內存溢出內存泄漏是計算機科學中常見的問題,在開發和
    的頭像 發表于 12-19 14:10 ?2996次閱讀
    主站蜘蛛池模板: 美女拍拍拍免费视频观看 | 456亚洲人成影院在线观 | 天天看天天碰 | 美女黄色在线 | 亚洲一级毛片免费在线观看 | 日本a级精品一区二区三区 日本a级特黄三级三级三级 | 分分操免费视频在线观看 | 四虎影片国产精品8848 | 亚洲婷婷综合色高清在线 | 97精品久久天干天天蜜 | 五月激情六月婷婷 | 毛片观看网址 | 国产一卡2卡3卡四卡精品网站 | 爱逼综合 | 亚洲成a人片77777潘金莲 | 欧美日韩国产另类一区二区三区 | 黄乱色伦 | 欧美极品在线观看 | 国产在线a不卡免费视频 | 欧美大香a蕉免费 | 日本不卡高清视频 | 乱色伦短篇小说 | 国产精品夜夜春夜夜 | 国产网站在线免费观看 | 色综合久久98天天综合 | 亚洲国产精品久久婷婷 | 久久久精品免费观看 | 欧美一级别| 免费爱爱网 | 天天摸天天操天天干 | 天天插插| 久久精品夜夜夜夜夜久久 | 人人天天爱天天做天天摸 | 性xxxxhd高清 | 宅男lu66国产在线播放 | www.激情五月.com| 午夜免费福利视频 | 手机看片国产免费现在观看 | 精品国产影院 | 2022欧美高清中文字幕在线看 | 免费看美女的逼 |