在Spring Boot項目中,我們經常需要對請求參數進行格式或業務規則的校驗。雖然Spring Boot提供了如@NotNull、@Size等基礎校驗注解,但在實際開發中往往無法滿足復雜的業務需求。但是在Controller層寫大量的 if 語句的判斷邏輯又實在不優雅,好在 Spring Validator 為我們提供了一種自定義校驗注解的方法實現優雅的參數校驗。
簡而言之,自定義校驗注解的優點大概有以下幾點:
- 統一性:避免在Controller層寫大量if判斷邏輯
- 可復用性:可以在多個字段或多個實體類中重復使用
- 可維護性:校驗邏輯和業務邏輯分離,便于后期修改和擴展
自定義校驗注解的實現步驟:
一、 創建自定義注解類
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidN1Validator.class)
public @interface ValidN1 {String message() default "必須1位數字";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
解析:
1.?@Target({ElementType.FIELD, ElementType.PARAMETER}):表示該注解可以用于字段或方法參數上。例如,你可以標注在實體類字段上,也可以用在Controller方法的參數上。
2.?@Retention(RetentionPolicy.RUNTIME):表示該注解在運行時依然可用,這樣Spring才能在運行時讀取并執行校驗邏輯。
3.?@Constraint(validatedBy = ValidN1Validator.class):指定該注解由哪個校驗器來處理,這里是 ValidN1Validator 類。
4.?message():校驗失敗時返回的默認錯誤提示信息。
5.?groups():分組校驗使用,允許你根據不同的業務場景選擇性地啟用某些校驗規則。
6.?payload():可選屬性,通常用于攜帶額外元數據,如嚴重級別等。
二、實現對應的校驗器類
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class ValidN1Validator implements ConstraintValidator<ValidN1, Integer> {@Overridepublic boolean isValid(Integer value, ConstraintValidatorContext context) {if(value == null){return true;}if(value >= 0 && value <= 9){return true;}else {return false;}}
}
解析:
1. 接口實現:ConstraintValidator<ValidN1, Integer>
- ? ? ? ? 第一個泛型參數是注解類型;
- ? ? ? ? 第二個泛型參數是要校驗的數據類型,這里是Integer。?
2. 方法實現:isValid(Integer value, ConstraintValidatorContext context)
- ????????核心校驗邏輯,判斷傳入的值是否符合要求。
三、在實體類中添加注解
public class User {private String name;@ValidN1private Integer sex;
}
四、統一返回錯誤信息(可選)
為了統一返回錯誤信息,我們可以使用 @RestControllerAdvice 來捕獲校驗異常。
@RestControllerAdvice
@Slf4j
public class ValidationExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<RequestDto> handleValidationExceptions(MethodArgumentNotValidException ex) {BindingResult result = ex.getBindingResult();List<String> errors = result.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());RequestDto dto = new RequestDto();dto.setCode(-1);dto.setMessage("參數校驗失敗:" + errors);return ResponseEntity.badRequest().body(dto);}
}
這樣當用戶傳入非法參數時,系統會返回類似如下格式的響應:
{"code": -1,"message": "參數校驗失敗:[時間戳格式錯誤]"
}