SpringBoot實戰:Excel文件上傳、數據驗證與存儲全流程解析

一、需求場景與技術選型

在企業管理、數據中臺等系統中,Excel文件處理是常見需求。本文將基于SpringBoot實現以下核心功能:

  1. 支持.xls/.xlsx文件上傳
  2. 數據完整性驗證(非空、格式等)
  3. 業務數據驗證(關聯數據庫校驗)
  4. 異常數據記錄與反饋
  5. 數據批量入庫

技術棧

  • SpringBoot 2.7+
  • Apache POI + EasyExcel
  • MyBatis-Plus 3.5+
  • H2 Database(演示用)

二、環境準備

2.1 添加依賴

<!-- Web支持 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!-- Excel處理 -->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version>
</dependency><!-- 數據庫 -->
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope>
</dependency>
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version>
</dependency><!-- 工具類 -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>

2.2 配置文件

server:port: 8080servlet:context-path: /excel-demospring:datasource:driver-class-name: org.h2.Driverurl: jdbc:h2:mem:testdbusername: sapassword:servlet:multipart:max-file-size: 50MBmax-request-size: 100MBmybatis-plus:configuration:map-underscore-to-camel-case: true

三、核心實現

3.1 文件上傳接口

@RestController
@RequestMapping("/api/excel")
@Slf4j
public class ExcelImportController {@PostMapping("/upload")public ResponseEntity<Map<String, Object>> uploadExcel(@RequestParam("file") MultipartFile file) {try {String originalFilename = file.getOriginalFilename();if (!originalFilename.matches("^.+\\.(?i)(xls|xlsx)$")) {return ResponseEntity.badRequest().body(Collections.singletonMap("error", "Invalid file format"));}String savePath = "/tmp/uploads/";File dest = new File(savePath + originalFilename);if (!dest.getParentFile().exists()) {dest.getParentFile().mkdirs();}file.transferTo(dest);// 調用處理服務ImportResult result = excelService.processExcel(dest);return ResponseEntity.ok().body(result.toMap());} catch (Exception e) {log.error("File upload failed", e);return ResponseEntity.internalServerError().body(Collections.singletonMap("error", e.getMessage()));}}
}

3.2 數據模型與校驗規則

@Data
public class EmployeeDTO {@ExcelProperty("員工姓名")@NotBlank(message = "姓名不能為空")private String name;@ExcelProperty("員工工號")@Pattern(regexp = "\\d{8}", message = "工號格式不正確")private String employeeId;@ExcelProperty("所屬部門")private String department;@ExcelProperty("入職日期")@DateTimeFormat(pattern = "yyyy-MM-dd")private Date hireDate;
}

3.3 Excel解析與校驗

public class EmployeeDataListener extends AnalysisEventListener<EmployeeDTO> {private static final int BATCH_SIZE = 100;private final List<EmployeeDTO> validData = new ArrayList<>();private final List<Map<String, String>> errorList = new ArrayList<>();@Overridepublic void invoke(EmployeeDTO data, AnalysisContext context) {// 基礎校驗Set<ConstraintViolation<EmployeeDTO>> violations = Validation.buildDefaultValidatorFactory().getValidator().validate(data);// 業務校驗if (!departmentService.existByName(data.getDepartment())) {violations.add(new ConstraintViolationImpl<>("部門不存在", null, null, null, null, null));}if (!violations.isEmpty()) {handleErrors(context.readRowHolder().getRowIndex(), violations);return;}validData.add(data);if (validData.size() >= BATCH_SIZE) {saveBatch();validData.clear();}}private void handleErrors(Integer rowNum, Set<ConstraintViolation<?>> violations) {Map<String, String> error = new HashMap<>();error.put("row", String.valueOf(rowNum + 1));error.put("errors", violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";")));errorList.add(error);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {if (!validData.isEmpty()) {saveBatch();}}private void saveBatch() {employeeService.saveBatch(validData.stream().map(this::convertToEntity).collect(Collectors.toList()));}
}

3.4 服務層實現

@Service
@RequiredArgsConstructor
public class ExcelImportService {private final EmployeeService employeeService;private final DepartmentService departmentService;public ImportResult processExcel(File excelFile) {try (ExcelReader excelReader = EasyExcel.read(excelFile, EmployeeDTO.class, new EmployeeDataListener(employeeService, departmentService)).build()) {ReadSheet readSheet = EasyExcel.readSheet(0).headRowNumber(1).build();excelReader.read(readSheet);return ImportResult.success().errorRecords(listener.getErrorList()).totalCount(listener.getTotalCount()).build();}}
}

四、關鍵問題處理

4.1 大文件處理優化

  • 使用SXSSF模式(POI的流式API)
  • 分批次提交數據庫事務
  • 異步處理(@Async + 線程池)
@Async("excelTaskExecutor")
public Future<ImportResult> asyncProcess(File file) {// 處理邏輯
}

4.2 數據驗證策略

驗證類型實現方式示例
格式驗證JSR-303注解校驗@Pattern(regexp=…)
業務邏輯驗證數據庫查詢校驗部門是否存在
唯一性驗證數據庫唯一索引+緩存去重工號唯一性
關聯數據驗證預加載緩存數據批量校驗預加載部門列表

4.3 異常處理機制

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MultipartException.class)public ResponseEntity<?> handleSizeExceeded() {return ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).body(Collections.singletonMap("error", "文件大小超過限制"));}@ExceptionHandler(ExcelAnalysisException.class)public ResponseEntity<?> handleExcelError() {return ResponseEntity.badRequest().body(Collections.singletonMap("error", "Excel解析失敗"));}
}

五、測試驗證

  1. 準備測試文件(包含正確和錯誤數據)
  2. 使用Postman發送POST請求
curl -X POST -F "file=@test.xlsx" http://localhost:8080/api/excel/upload
  1. 查看響應結果:
{"success": true,"total": 150,"successCount": 132,"errorCount": 18,"errors": [{"row": 5, "errors": "部門不存在"},{"row": 17, "errors": "工號格式不正確"}]
}
  1. 檢查數據庫記錄
SELECT * FROM employee WHERE hire_date > '2023-01-01';

六、生產級優化建議

  1. 安全增強

    • 文件病毒掃描
    • 文件頭校驗防止偽裝擴展名
    • 上傳頻率限制
  2. 性能優化

    • 使用Redis緩存部門數據
    • 多線程分片處理
    • 數據庫批量插入優化
  3. 可觀測性

    • 添加處理進度查詢接口
    • 集成Prometheus監控指標
    • 詳細操作日志記錄
  4. 用戶體驗

    • 生成錯誤報告Excel
    • 支持斷點續傳
    • 郵件通知處理結果

完整代碼示例已托管至GitHub:springboot-excel-demo

通過本文的實現,我們構建了一個健壯的Excel處理流程,能夠應對企業級應用中的復雜數據處理需求。實際項目中可根據具體業務場景擴展驗證規則和優化處理邏輯。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/74221.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/74221.shtml
英文地址,請注明出處:http://en.pswp.cn/web/74221.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用Java爬蟲按關鍵字搜索淘寶商品?

在電商領域&#xff0c;通過關鍵字搜索商品是獲取商品信息的常見需求。Java爬蟲技術可以幫助我們自動化地獲取這些信息&#xff0c;提高工作效率。本文將詳細介紹如何使用Java爬蟲按關鍵字搜索淘寶商品&#xff0c;并提供完整的代碼示例。 一、準備工作 1. 注冊淘寶開放平臺賬…

【Git】5 個分區的切換方式及示例

目錄 1. **工作區&#xff08;Working Directory&#xff09;**2. **緩存區&#xff08;Stage/Index&#xff09;**3. **本地倉庫&#xff08;Local Repository&#xff09;**4. **遠程倉庫&#xff08;Remote Repository&#xff09;**5. **貯藏區&#xff08;Stash&#xff0…

【計算機視覺】YOLO語義分割

一、語義分割簡介 1. 定義 語義分割&#xff08;Semantic Segmentation&#xff09;是計算機視覺中的一項任務&#xff0c;其目標是對圖像中的每一個像素賦予一個類別標簽。與目標檢測只給出目標的邊界框不同&#xff0c;語義分割能夠在像素級別上區分不同類別&#xff0c;從…

MATLAB之數據分析圖系列:從二維到三維(直接套用)

MATLAB以其強大的矩陣運算和可視化功能&#xff0c;成為科研、工程領域的標配工具。本文提供從基礎二維圖形到復雜三維模型的即用代碼塊&#xff0c;涵蓋數據標注、多圖排版、動態演示等核心技巧 所有代碼均經過MATLAB 2023a實測&#xff0c;替換數據即可生成專業級圖表。” …

HTTP響應數據包全面解析:結構、原理與最佳實踐

目錄 HTTP響應概述 HTTP響應數據包結構 2.1 狀態行 2.2 響應頭 2.3 空行 2.4 響應體 HTTP狀態碼詳解 3.1 1xx信息響應 3.2 2xx成功響應 3.3 3xx重定向 3.4 4xx客戶端錯誤 3.5 5xx服務器錯誤 常見HTTP響應頭字段 響應體內容類型 緩存控制機制 實際HTTP響應示例分…

H.264編碼解析與C++實現詳解

一、H.264編碼核心概念 1.1 分層編碼結構 H.264采用分層設計&#xff0c;包含視頻編碼層&#xff08;VCL&#xff09;和網絡抽象層&#xff08;NAL&#xff09;。VCL處理核心編碼任務&#xff0c;NAL負責封裝網絡傳輸數據。 1.2 NALU單元結構 // NAL單元頭部結構示例 struc…

快速入手-基于Django-rest-framework的自身組件權限認證(九)

1、在對應的視圖函數里增加認證&#xff08;局部起作用&#xff0c;不全局生效&#xff09; 導入類&#xff1a; from rest_framework.authentication import ( BasicAuthentication, SessionAuthentication, ) from rest_framework.permissions import IsAuthentica…

受控組件和非受控組件的區別

在 React 中&#xff0c;?受控組件&#xff08;Controlled Components&#xff09;? 和 ?非受控組件&#xff08;Uncontrolled Components&#xff09;? 是處理表單元素的兩種不同方式&#xff0c;它們的核心區別在于 ?數據管理的方式 和 ?與 React 的交互模式。 受控組件…

邁向云原生:理想汽車 OLAP 引擎變革之路

在如今數據驅動的時代&#xff0c;高效的分析引擎對企業至關重要。理想汽車作為智能電動汽車的領軍企業&#xff0c;面臨著海量數據分析的挑戰。本文將展開介紹理想汽車 OLAP 引擎從存算一體向云原生架構演進的變革歷程&#xff0c;以及在此過程中面臨的挑戰&#xff0c;以及是…

ZLMediaKit 源碼分析——[3] ZLToolKit 中EventPoller之網絡事件處理

系列文章目錄 第一篇 基于SRS 的 WebRTC 環境搭建 第二篇 基于SRS 實現RTSP接入與WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 環境搭建 第四篇 WebRTC學習一&#xff1a;獲取音頻和視頻設備 第五篇 WebRTC學習二&#xff1a;WebRTC音視頻數據采集 第六篇 WebRTC學習三…

【分布式】分布式限流方案解析

文章目錄 固定窗口限流方案?實現方式?優點?缺點? 滑動窗口限流方案?實現方式?優點?缺點? 令牌桶限流方案?實現方式?優點?缺點? 漏斗限流方案?實現方式?優點?缺點? 在分布式系統蓬勃發展的當下&#xff0c;系統面臨的流量挑戰日益復雜。為確保系統在高并發場景下…

WPS JS宏編程教程(從基礎到進階)-- 第三部分:JS宏編程語言開發基礎

第三部分:JS宏編程語言開發基礎 @[TOC](第三部分:JS宏編程語言開發基礎)**第三部分:JS宏編程語言開發基礎**1. 變量與數據類型**變量聲明:三種方式****示例代碼****數據類型判斷****實戰:動態處理單元格類型**2. 運算符全解析**算術運算符****易錯點:字符串拼接 vs 數值相…

Python - 爬蟲-網頁抓取數據-庫urllib

urllib庫是Python內置的HTTP請求庫。無需額外安裝&#xff0c;可以直接使用。urllib庫包含以下四個模塊。 urllib.request - 打開和讀取 URL。urllib.error - 包含 urllib.request 拋出的異常。urllib.parse - 解析 URL。urllib.robotparser - 解析 robots.txt 文件。 1、reque…

C++進階知識復習 1~15

C 進階總復習 &#xff08;1~15&#xff09; 目的1. 介紹下程序從編寫到可執行的整個過程2. C中的auto和decltype的區別3. 介紹下多態的實現原理4. C中的new[] 和delete[] 為什么一定要配對使用&#xff1f;5. C中malloc申請的內存 可以使用delete釋放嘛6. 什么情況下會出現內存…

輸電線路航空標志球:低空飛行的安全路標 / 恒峰智慧科技

在現代社會&#xff0c;隨著航空業的快速發展&#xff0c;低空飛行活動日益頻繁。為了確保飛行安全&#xff0c;避免飛機與高壓電線等障礙物發生碰撞&#xff0c;輸電線路航空標志球應運而生。這種裝置被廣泛應用于高壓輸電線路上&#xff0c;尤其是超高壓和跨江輸電線&#xf…

Debian/Ubuntu的networking的`/etc/network/interfaces`配置文件詳解

Debian/Ubuntu的networking的/etc/network/interfaces配置文件詳解 Debian/Ubuntu 的 /etc/network/interfaces 配置文件詳解 在 Debian/Ubuntu 系統中&#xff0c;/etc/network/interfaces 是傳統網絡接口配置文件&#xff0c;用于定義網絡接口的靜態/動態配置。以下是逐項解…

OpenCV 圖形API(或稱G-API)(1)

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 引言 OpenCV 圖形API&#xff08;或稱G-API&#xff09;是一個新的OpenCV模塊&#xff0c;旨在使常規圖像處理更快且更便攜。通過引入一種新的基于圖的執行…

Leetcode 3505. Minimum Operations to Make Elements Within K Subarrays Equal

Leetcode 3505. Minimum Operations to Make Elements Within K Subarrays Equal 1. 解題思路2. 代碼實現 題目鏈接&#xff1a;3505. Minimum Operations to Make Elements Within K Subarrays Equal 1. 解題思路 這一題大的思路上不難想到就是一個動態規劃的思路。我們分別…

win10之mysql server 8.0.41安裝

一 mysql server 下載 官網下載地址頁面 https://dev.mysql.com/downloads/mysql/二 免裝版使用步驟 1 解壓 下載完成后,解壓文件夾,如下所示: 2 執行安裝命令 D:\soft\mysql\mysql-8.0.41-winx64\mysql-8.0.41-winx64\bin>mysqld --install Service successfully in…

第十二屆藍橋杯省賽軟件類(cc++組)

第一題&#xff08;空間&#xff09; 解題思路 答案 #include <stdio.h>int main() {// 計算256MB對應的字節數&#xff0c;1MB 1024KB&#xff0c;1KB 1024Blong long total_bytes 256 * 1024 * 1024; // 每個32位二進制整數占4個字節&#xff08;32 / 8 4&#xf…