欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot 異常處理/自定義格式校驗的問題實例詳解

 更新時間:2025年07月23日 14:34:41   作者:Su-RE  
文章探討Spring Boot中自定義注解校驗問題,區(qū)分參數(shù)級與類級約束觸發(fā)的異常類型,建議通過@RestControllerAdvice統(tǒng)一處理,并說明如何獲取不同錯誤類型(FieldError/ObjectError)的信息差異,感興趣的朋友一起看看吧

1. 問題簡要描述

這個問題是在測試自定義注解實現(xiàn)數(shù)據(jù)格式校驗時遇到的,當前有兩個注解,ValidateParamsMatched和SafeParam。前者的功能是對類中的兩個列表的長度進行比較,后者則是對字符串進行校驗,判斷是否包含特殊字符
但是,當分別觸發(fā)這兩個校驗時,都會觸發(fā)異常并返回請求,但之后后者能返回請求信息。
這里問題本質上是沒弄懂對應的異常處理代碼,但也值得記錄一下。

2. 異常觸發(fā)

1) 參數(shù)級別約束

在 Controller 方法上直接使用參數(shù)級約束,并且,Controller 類上有 @Validated 注解時,驗證失敗會觸發(fā) ConstraintViolationException 異常

@Validated // 必需
@RestController
public class ProductController {
    @GetMapping("/products")
    public Product getProduct(@ValidCategory String category) {
        // ...
    }
}

在 DTO 的字段上使用參數(shù)級約束,且方法參數(shù)前有 @Valid 注解時,驗證失敗會觸發(fā) MethodArgumentNotValidException 異常

@PostMapping("/products")
public ResponseEntity<?> createProduct(
    @Valid @RequestBody ProductRequest request // 觸發(fā)驗證
) {
    // ...
}

2) 類級別約束

在實體類上標注了類級約束,且Controller 方法參數(shù)使用了 @Valid,觸發(fā)MethodArgumentNotValidException

@ValidInventory // 類級別約束
public class Product {
    private int stockQuantity;
    private int minStockLevel;
}
@PostMapping("/products")
public ResponseEntity<?> createProduct(
    @Valid @RequestBody Product product // 觸發(fā)驗證
) {
    // ...
}

注意:類級別約束應該加在需要驗證的目標類(實體類/DTO)的類聲明上,且在 Controller 方法參數(shù)添加 @Valid 和在 Service 方法參數(shù)添加 @Valid

3. 異常處理

建議通過 @RestControllerAdvice 設置全局異常處理來對此類異常進行處置。但獲取信息時,這兩類約束的方法不同。
在 MethodArgumentNotValidException 中,字段級約束產生 FieldError,類級約束產生 ObjectError(也稱為全局錯誤)

1) 字段級別約束

獲取方式為 ex.getBindingResult().getFieldErrors(),包含字段名、錯誤消息、拒絕值。
ex.getMessage() 會返回詳細錯誤信息

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException ex) {
    // 只獲取字段錯誤
    String errorMsg = ex.getBindingResult().getFieldErrors().stream()
            .map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
            .collect(Collectors.joining("; "));
    log.warn("請求值驗證異常 | request={}", ex.getMessage());
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorMsg);
}

2) 類級別約束

獲取方式為 ex.getBindingResult().getGlobalErrors(),包含對象名、錯誤消息。
ex.getMessage() 返回通用消息。

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException ex) {
    // 只獲取字段錯誤
    String errorMsg = ex.getBindingResult().getGlobalErrors().stream()
            .map(DefaultMessageSourceResolvable::getDefaultMessage)
            .collect(Collectors.joining("; "));
    log.warn("請求值驗證異常 | request={}", ex.getMessage());
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorMsg);
}

在類級別約束的異常處理時,ex.getBindingResult().getFieldErrors() 會返回空值;同樣的,ex.getBindingResult().getGlobalErrors()也會返回空值
因此,可以統(tǒng)一錯誤處理格式

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException ex) {
    // 創(chuàng)建錯誤消息列表
    List<String> errorMessages = new ArrayList<>();
    // 處理字段錯誤
    ex.getBindingResult().getFieldErrors().forEach(fieldError -> {
        String msg = String.format("%s: %s",
                fieldError.getField(),
                fieldError.getDefaultMessage());
        errorMessages.add(msg);
    });
    // 處理全局錯誤
    ex.getBindingResult().getGlobalErrors().forEach(globalError -> {
        String msg = String.format("全局錯誤: %s", globalError.getDefaultMessage());
        errorMessages.add(msg);
    });
    // 合并所有錯誤消息
    String errorMsg = String.join("; ", errorMessages);
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorMsg);
}

4. 進一步學習

值得注意的是, ex.getMessage() 給出的結果也是不一樣的,這個與代碼實現(xiàn)有關

public String getMessage() {
    StringBuilder sb = new StringBuilder("Validation failed for argument at index ")
            .append(getParameter().getParameterIndex()).append(" in method: ")
            .append(getParameter().getExecutable().toGenericString());
    BindingResult result = getBindingResult();
    if (result.getErrorCount() > 0) {
        sb.append(", with ").append(result.getErrorCount()).append(" error(s): ");
        for (ObjectError error : result.getAllErrors()) {
            sb.append('[').append(error).append("] ");
        }
    }
    return sb.toString();
}

當只有類級約束失敗時,result.getErrorCount() == 1(只有 ObjectError),因此,ex.getMessage() 輸出的內容不同

  1. 另外,在調試的過程中還遇到了一個問題,在類級別約束中,考慮到已經存在非空校驗了,因此,在類約束中再重復做校驗。但在測試過程中發(fā)現(xiàn),輸入屬性為空時,會在類約束中報錯。后來經過查驗,確定問題原因。
    1. 雖然對于 Bean 的校驗按照 字段->類 的順序進行,但校驗過程會收集所有違反約束的情況,而不是在遇到第一個約束失敗時就停止。也就是說類級別的約束(即放在類上的注解)的校驗器,在字段級別約束失敗時,仍然會被執(zhí)行

到此這篇關于SpringBoot 異常處理/自定義格式校驗的文章就介紹到這了,更多相關springboot異常處理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java高級排序之希爾排序

    java高級排序之希爾排序

    這篇文章主要介紹了java高級排序之希爾排序 ,需要的朋友可以參考下
    2015-04-04
  • Java類加載機制實現(xiàn)流程及原理詳解

    Java類加載機制實現(xiàn)流程及原理詳解

    這篇文章主要介紹了Java類加載機制實現(xiàn)流程及原理詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • java使用POI實現(xiàn)html和word相互轉換

    java使用POI實現(xiàn)html和word相互轉換

    這篇文章主要為大家詳細介紹了java使用POI實現(xiàn)html和word的相互轉換,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Java字符串比較方法equals的空指針異常的解決

    Java字符串比較方法equals的空指針異常的解決

    這篇文章主要介紹了Java字符串比較方法equals的空指針異常的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-09-09
  • Java?nacos動態(tài)配置實現(xiàn)流程詳解

    Java?nacos動態(tài)配置實現(xiàn)流程詳解

    使用動態(tài)配置的原因是properties和yaml是寫到項目中的,好多時候有些配置需要修改,每次修改就要重新啟動項目,不僅增加了系統(tǒng)的不穩(wěn)定性,也大大提高了維護成本,非常麻煩,且耗費時間
    2022-09-09
  • javascript最新2020經典面試題

    javascript最新2020經典面試題

    這篇文章主要介紹了javascript最新2020經典面試題的相關內容,有需要的朋友們可以學習下。
    2020-02-02
  • java多線程開發(fā)ScheduledExecutorService簡化方式

    java多線程開發(fā)ScheduledExecutorService簡化方式

    這篇文章主要為大家介紹了java多線程開發(fā)ScheduledExecutorService的簡化方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • Java常見的數(shù)據(jù)結構之棧和隊列詳解

    Java常見的數(shù)據(jù)結構之棧和隊列詳解

    這篇文章主要介紹了Java常見的數(shù)據(jù)結構之棧和隊列詳解,棧(Stack) 是一種基本的數(shù)據(jù)結構,具有后進先出(LIFO)的特性,類似于現(xiàn)實生活中的一疊盤子,棧用于存儲一組元素,但只允許在棧頂進行插入(入棧)和刪除(出棧)操作,需要的朋友可以參考下
    2023-10-10
  • 基于Intellij Idea亂碼的解決方法

    基于Intellij Idea亂碼的解決方法

    下面小編就為大家分享一篇基于Intellij Idea亂碼的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • springboot后端使用LocalDate接收日期的問題解決

    springboot后端使用LocalDate接收日期的問題解決

    在做Java開發(fā)時,肯定會碰到傳遞時間參數(shù)的情況,本文主要介紹了springboot后端使用LocalDate接收日期的問題解決,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09

最新評論