Spring?Boot?+?EasyExcel?+?SqlServer?進行批量處理數(shù)據(jù)的高效方法
前言
在日常開發(fā)和工作中,我們可能要根據(jù)用戶上傳的文件做一系列的處理,本篇文章就以Excel表格文件為例,模擬用戶上傳Excel文件,講述后端如何高效的進行數(shù)據(jù)的處理。
一.引入 EasyExcel 依賴
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.3.2</version> </dependency>
二.在接口中編寫代碼
(一).使用什么參數(shù)接收?
由于用戶上傳的是一個Excel文件,也就是說前端發(fā)來的是一個Excel表格的文件,那么我們后端就需要使用 MultipartFile file 來進行接收
@PostMapping("/importExcelUpdateFlag") public Map<String,Object> importExcelUpdateFlag(@RequestBody MultipartFile file) { //具體代碼...... }
(二).如何存儲到本地目錄中(最后說為什么存儲到本地)
既然前端發(fā)來了一個Excel文件,后端需要對其進行重命名還有大量的數(shù)據(jù)處理,那么如何存儲到本地是一個問題。我們在三層架構的基礎上,這個存儲到本地的工作一般放在 Service 層進行處理。
Controller層的代碼
下面的 uploadPath(也就是你要存儲到本地的目錄) 是自己在 yml文件中定義好的,然后進行使用,截圖如下:
@PostMapping("/importExcelUpdateFlag") public Map<String,Object> importExcelUpdateFlag(@RequestBody MultipartFile file) { //把前端發(fā)來的文件數(shù)據(jù),傳到本機指定的 uploadPath 目錄之下 String pathAndFileName = jdCloudService.uploadFile(file,uploadPath); //其他代碼.... }
注意這里 pathAndFileName 接收的是一個本地路徑,后續(xù)需要根據(jù)這個路徑找到指定文件
Service 層的代碼
@Override public String uploadFile(MultipartFile file, String uploadPath) { if(file.isEmpty()){ return "上傳文件為空"; } try { String originalFilename = StringUtils.cleanPath(file.getOriginalFilename()); String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".")); String newFilename = generateFilename() + fileExtension; File targetFile = new File(uploadPath + File.separator + newFilename); file.transferTo(targetFile); return uploadPath + "\\" + newFilename; } catch (Exception e) { return "文件上傳失敗: " + e.getMessage(); } } private String generateFilename() { // 根據(jù)你的需求生成新的文件名,例如使用時間戳或隨機字符串等,這里使用時間戳 return String.valueOf("更新文件名.." + System.currentTimeMillis()); }
代碼解讀:我們假設前端傳來了一個 hello.xlsx 文件
String originalFilename = StringUtils.cleanPath(file.getOriginalFilename());
這行代碼會將 "hello.xlsx " 賦值給 originalFilename
變量。
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
這行代碼會從 "hello.txt" 中提取出文件擴展名 ".txt",并將其賦值給 fileExtension
變量。
String newFilename = generateFilename() + fileExtension;
這行代碼會調用generateFilename()
方法生成一個新的唯一文件名,例如 "abc123"。將生成的文件名 "abc123.xlsx" 與文件擴展名 ".txt" 拼接,賦值給newFilename
變量。
File targetFile = new File(uploadPath + File.separator + newFilename);
假設uploadPath
是 "/path/to/uploads/"。這行代碼會創(chuàng)建一個File
對象,代表文件的保存路徑和文件名 "/path/to/uploads/abc123.xlsx"。那么這個就會創(chuàng)建出文件了(但是沒有內容)
file.transferTo(targetFile);
這行代碼會將用戶上傳的 "hello.xlsx" 文件的內容,寫入到 "/path/to/uploads/abc123.xlsx" 文件中。
通過這樣的處理,原本名為 "hello.xlsx" 的文件會被保存為 "abc123.xlsx",并且保存在 "/path/to/uploads/" 目錄下。這樣可以避免文件名與現(xiàn)有文件發(fā)生沖突,確保文件上傳的安全性。
注意這里返回給 Controller 層的是一個本地目錄,是根據(jù)目錄來找到指定的文件!
三.假設需求
現(xiàn)在假設我們本地指定的目錄下面已經有用戶上傳的文件了,那么我們要對這個文件進行一系列的處理。 現(xiàn)在假設我們的需求是根據(jù)Excel文件中用戶的 工號,更新用戶的 Flag 標簽(0變?yōu)?)
那么應該如何做呢?
繼續(xù)編寫代碼
Controller層
@PostMapping("/importExcelUpdateFlag") public Map<String,Object> importExcelUpdateFlag(@RequestBody MultipartFile file) { Map<String,Object> response = new HashMap<>(); response.put("code",0); response.put("data",":"); //把前端發(fā)來的文件數(shù)據(jù),傳到本機指定的 uploadPath 目錄之下 String pathAndFileName = jdCloudService.uploadFile(file,uploadPath); if(pathAndFileName.equals("上傳文件為空") || pathAndFileName.equals("文件上傳失敗")) { response.put("msg",pathAndFileName); return response; } String feedBackMsg = jdCloudService.enableFlagUpdate(pathAndFileName); response.put("msg",feedBackMsg); return response; }
這里主要是 feedBackMsg,這個調用的 Service 層的代碼是處理表格數(shù)據(jù)的主要內容,我們來看
Service層
@Override public String enableFlagUpdate(String filename) { //獲取 PersonSynData 類的 Class 對象。 Class<PersonSynData> head = PersonSynData.class; List<PersonSynData> updateList = new ArrayList<>(); ExcelReader excelReader = EasyExcel.read(filename, head, new AnalysisEventListener<PersonSynData>() { @Override public void invoke(PersonSynData personSynData, AnalysisContext analysisContext) { updateList.add(personSynData); } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("Excel解析完成......"); } }).build(); //創(chuàng)建 sheet 對象,并且讀取Excel的第一個sheet(下表從0開始),也可以根據(jù) sheet 名稱獲取 ReadSheet readSheet = EasyExcel.readSheet(0).build(); //讀取 sheet 表格數(shù)據(jù),參數(shù)是可變參數(shù),也可以讀取多個sheet //這個操作會讀取 excel 表格的數(shù)據(jù) excelReader.read(readSheet); //需要自己關閉流操作,在讀取文件的時候會創(chuàng)建臨時文件,如果不關閉的話,會損耗磁盤 excelReader.finish(); }
代碼解讀:
1.首先獲取到實體類的 class 對象,后續(xù)需要進行使用
2.updateList 是要存儲 Excel 表格中的每一行,每一行都是一個 實體類對象
3. ExcelReader excelReader = EasyExcel.read(filename, head, new AnalysisEventListener<PersonSynData>() {...});是Alibaba提供的一個工廠方法,用于創(chuàng)建一個 ExcelReader 對象。
filename 是要解析的 Excel 文件的路徑。
head 是前面獲取的 PersonSynData 類的 Class 對象,用于告訴 EasyExcel 應該如何解析 Excel 數(shù)據(jù)。
new AnalysisEventListener<PersonSynData>() {...} 是一個匿名內部類,實現(xiàn)了 AnalysisEventListener 接口。這個監(jiān)聽器用于處理 Excel 數(shù)據(jù)的解析過程。
4. invoke 是必須重寫的方法
- 每解析到一行 Excel 數(shù)據(jù),就會調用這個方法,并將解析后的
PersonSynData
實例作為參數(shù)傳遞進來。 - 在這個方法中,我們將解析出的
PersonSynData
實例添加到updateList
中。
5. doAfterAllAnalysed也是必須重寫的方法
- 這個方法是
AnalysisEventListener
接口的doAfterAllAnalysed
方法的實現(xiàn)。 - 當 Excel 文件的所有數(shù)據(jù)都解析完成后,就會調用這個方法。
- 在這個方法中,我們打印了一條消息,表示 Excel 解析完成。
6.當代碼執(zhí)行到 excelReader.read(readSheet); 此時 updateList 中就有我們需要的數(shù)據(jù)了
注意!更新操作在下一篇: http://chabaoo.cn/program/322571vt7.htm
四.為什么要緩存到本地?
緩存到本地和在內存中進行處理是兩種不同的解決方案
在處理前端傳來的Excel文件時,后端是否需要將其存儲到本地再進行解析,確實存在幾種不同的處理方式。
存儲到本地后再解析:這種方式的優(yōu)點是可以避免在內存中一次性加載整個Excel文件,從而減輕內存壓力。同時,如果需要對文件進行多次處理,存儲到本地后可以直接讀取而無需重新上傳,提高效率。缺點是需要占用服務器硬盤空間,并且需要額外的IO操作。
直接在內存中解析:這種方式可以省略存儲到本地的步驟,直接從前端傳來的數(shù)據(jù)流中進行解析。優(yōu)點是減少了IO操作,提高了處理速度。缺點是需要一次性加載整個Excel文件到內存中,如果文件很大可能會造成內存溢出的風險。
綜合來看,兩種方式各有優(yōu)缺點。具體采用哪種方式,需要根據(jù)實際業(yè)務需求、文件大小、服務器資源等因素進行權衡。如果Excel文件較小,且只需要處理一次,直接在內存中解析可能是更好的選擇。而對于較大的Excel文件,或需要多次處理的場景,將其存儲到本地可能會更合適??傊?在設計后端處理邏輯時,需要充分考慮各種因素,選擇最佳的解決方案。
到此這篇關于Spring Boot + EasyExcel + SqlServer 進行批量處理數(shù)據(jù)的文章就介紹到這了,更多相關Spring Boot EasyExcel 批量處理數(shù)據(jù)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java報錯:java.util.concurrent.ExecutionException的解決辦法
在Java并發(fā)編程中,我們經常使用java.util.concurrent包提供的工具來管理和協(xié)調多個線程的執(zhí)行,va并發(fā)編程中,然而,在使用這些工具時,可能會遇到各種各樣的異常,其中之一就是java.util.concurrent.ExecutionException,本文將詳細分析這種異常的背景、可能的原因2024-09-09SpringBoot內存數(shù)據(jù)導出成Excel的實現(xiàn)方法
這篇文章主要給大家介紹了關于SpringBoot內存數(shù)據(jù)導出成Excel的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12springboot整合logback實現(xiàn)日志管理操作
本章節(jié)是記錄logback在springboot項目中的簡單使用,本文將會演示如何通過logback將日志記錄到日志文件或輸出到控制臺等管理操作,感興趣的朋友跟隨小編一起看看吧2024-02-02