Spring Validation中9個數(shù)據(jù)校驗工具使用指南
1. Bean Validation基礎(chǔ)注解
Spring Validation集成了JSR-380 (Bean Validation 2.0)規(guī)范,提供了一系列開箱即用的校驗注解。
常用注解示例
@Data public class UserDTO { @NotNull(message = "用戶ID不能為空") private Long id; @NotBlank(message = "用戶名不能為空") @Size(min = 4, max = 20, message = "用戶名長度必須在4到20個字符之間") private String username; @Email(message = "郵箱格式不正確") private String email; @Min(value = 18, message = "年齡必須大于或等于18") @Max(value = 120, message = "年齡必須小于或等于120") private Integer age; @Past(message = "出生日期必須是過去的日期") private LocalDate birthDate; @Pattern(regexp = "^1[3-9]\d{9}$", message = "手機(jī)號碼格式不正確") private String phoneNumber; }
在控制器中應(yīng)用
@RestController @RequestMapping("/api/users") public class UserController { @PostMapping public ResponseEntity<UserDTO> createUser(@RequestBody @Valid UserDTO userDTO, BindingResult bindingResult) { if (bindingResult.hasErrors()) { // 處理驗證錯誤 throw new ValidationException(bindingResult); } // 處理業(yè)務(wù)邏輯 return ResponseEntity.ok(userDTO); } }
最佳實(shí)踐:使用有意義的錯誤消息,保持一致的命名風(fēng)格,避免在實(shí)體類上直接使用驗證注解,而是在DTO對象上應(yīng)用驗證規(guī)則。
2. 自定義約束驗證器
Spring Validation允許開發(fā)者創(chuàng)建自定義約束,滿足特定業(yè)務(wù)規(guī)則的驗證需求。
定義自定義約束注解
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = UniqueUsernameValidator.class) public @interface UniqueUsername { String message() default "用戶名已存在"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
實(shí)現(xiàn)驗證器
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> { @Autowired private UserRepository userRepository; @Override public boolean isValid(String username, ConstraintValidatorContext context) { if (username == null) { return true; // 讓@NotNull處理空值 } return !userRepository.existsByUsername(username); } }
應(yīng)用自定義約束
public class UserRegistrationDTO { @NotBlank @Size(min = 4, max = 20) @UniqueUsername private String username; // 其他字段... }
使用場景:驗證業(yè)務(wù)特定規(guī)則,如唯一性約束、密碼復(fù)雜度、信用卡格式等。
3. 分組驗證
分組驗證允許根據(jù)不同場景應(yīng)用不同的驗證規(guī)則,例如創(chuàng)建和更新操作可能需要不同的驗證邏輯。
定義驗證分組
// 定義驗證分組接口 public interface ValidationGroups { interface Create {} interface Update {} }
應(yīng)用分組到約束
@Data public class ProductDTO { @Null(groups = ValidationGroups.Create.class, message = "創(chuàng)建產(chǎn)品時ID必須為空") @NotNull(groups = ValidationGroups.Update.class, message = "更新產(chǎn)品時ID不能為空") private Long id; @NotBlank(groups = {ValidationGroups.Create.class, ValidationGroups.Update.class}) private String name; @PositiveOrZero(groups = ValidationGroups.Create.class) @Positive(groups = ValidationGroups.Update.class) private BigDecimal price; }
在控制器中指定分組
@RestController @RequestMapping("/api/products") public class ProductController { @PostMapping public ResponseEntity<ProductDTO> createProduct( @RequestBody @Validated(ValidationGroups.Create.class) ProductDTO productDTO) { // 創(chuàng)建產(chǎn)品邏輯 return ResponseEntity.ok(productDTO); } @PutMapping("/{id}") public ResponseEntity<ProductDTO> updateProduct( @PathVariable Long id, @RequestBody @Validated(ValidationGroups.Update.class) ProductDTO productDTO) { // 更新產(chǎn)品邏輯 return ResponseEntity.ok(productDTO); } }
提示:注意使用@Validated
注解而不是@Valid
,因為只有前者支持分組驗證。
4. 嵌套驗證
嵌套驗證允許驗證復(fù)雜對象結(jié)構(gòu)中的嵌套對象。
定義嵌套對象
@Data public class OrderDTO { @NotNull private Long id; @NotNull @Valid // 標(biāo)記需要級聯(lián)驗證的字段 private CustomerDTO customer; @NotEmpty @Valid // 驗證集合中的每個元素 private List<OrderItemDTO> items; } @Data public class CustomerDTO { @NotNull private Long id; @NotBlank private String name; @Email private String email; @Valid // 進(jìn)一步嵌套驗證 private AddressDTO address; }
關(guān)鍵點(diǎn):在需要級聯(lián)驗證的字段上添加@Valid
注解,確保驗證深入到嵌套對象中。
5. 方法級別驗證
Spring Validation不僅可以用于控制器參數(shù),還可以應(yīng)用于服務(wù)層的方法。
啟用方法級別驗證
@Configuration @EnableMethodValidation public class ValidationConfig { // 配置內(nèi)容 }
定義帶驗證的服務(wù)方法
@Service public class UserService { @Validated public User createUser(@Valid UserDTO userDTO) { // 業(yè)務(wù)邏輯 return new User(); } @NotNull public User findById(@Min(1) Long id) { // 查詢邏輯 return new User(); } @Validated(ValidationGroups.Update.class) public void updateUser(@Valid UserDTO userDTO) { // 更新邏輯 } }
應(yīng)用場景:確保服務(wù)層方法接收到的參數(shù)和返回的結(jié)果符合預(yù)期,增強(qiáng)代碼的健壯性。
6. 錯誤消息處理和國際化
Spring Validation提供了強(qiáng)大的錯誤消息處理和國際化支持。
自定義錯誤消息
在ValidationMessages.properties
文件中定義:
# ValidationMessages.properties javax.validation.constraints.NotEmpty.message=字段不能為空 javax.validation.constraints.Email.message=不是有效的電子郵箱地址 user.name.size=用戶名長度必須在{min}到{max}個字符之間
國際化錯誤消息
創(chuàng)建特定語言的屬性文件:
# ValidationMessages_en.properties javax.validation.constraints.NotEmpty.message=Field cannot be empty javax.validation.constraints.Email.message=Not a valid email address user.name.size=Username must be between {min} and {max} characters # ValidationMessages_zh_CN.properties javax.validation.constraints.NotEmpty.message=字段不能為空 javax.validation.constraints.Email.message=不是有效的電子郵箱地址 user.name.size=用戶名長度必須在{min}到{max}個字符之間
使用自定義消息
@Size(min = 4, max = 20, message = "{user.name.size}") private String username;
7. 程序化驗證
除了注解驅(qū)動的驗證,Spring Validation還支持以編程方式進(jìn)行驗證。
使用Validator手動驗證對象
@Service public class ValidationService { private final Validator validator; public ValidationService(Validator validator) { this.validator = validator; } public <T> void validate(T object) { Set<ConstraintViolation<T>> violations = validator.validate(object); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); } } public <T> void validateWithGroup(T object, Class<?>... groups) { Set<ConstraintViolation<T>> violations = validator.validate(object, groups); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); } } public <T> List<String> getValidationErrors(T object) { return validator.validate(object).stream() .map(ConstraintViolation::getMessage) .collect(Collectors.toList()); } }
使用場景:在復(fù)雜業(yè)務(wù)邏輯中需要條件性驗證,或者驗證非控制器傳入的對象時。
8. 組合約束
組合約束允許將多個基本約束組合成一個更復(fù)雜的約束,減少代碼重復(fù)。
創(chuàng)建組合約束
@NotNull @Size(min = 8, max = 30) @Pattern(regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$", message = "密碼必須包含至少一個數(shù)字、小寫字母、大寫字母和特殊字符") @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = {}) public @interface StrongPassword { String message() default "密碼不符合安全要求"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
應(yīng)用組合約束
public class PasswordChangeDTO { @NotBlank private String oldPassword; @StrongPassword private String newPassword; @NotBlank private String confirmPassword; }
優(yōu)點(diǎn):提高代碼可讀性和可維護(hù)性,確保驗證規(guī)則在整個應(yīng)用中保持一致。
9. 跨字段驗證
跨字段驗證允許根據(jù)多個字段之間的關(guān)系進(jìn)行驗證。
創(chuàng)建類級別約束
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = PasswordMatchesValidator.class) public @interface PasswordMatches { String message() default "確認(rèn)密碼與新密碼不匹配"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String field(); String fieldMatch(); }
實(shí)現(xiàn)驗證器
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> { private String field; private String fieldMatch; @Override public void initialize(PasswordMatches constraintAnnotation) { this.field = constraintAnnotation.field(); this.fieldMatch = constraintAnnotation.fieldMatch(); } @Override public boolean isValid(Object value, ConstraintValidatorContext context) { try { Object fieldValue = BeanUtils.getPropertyDescriptor(value.getClass(), field) .getReadMethod().invoke(value); Object fieldMatchValue = BeanUtils.getPropertyDescriptor(value.getClass(), fieldMatch) .getReadMethod().invoke(value); return (fieldValue != null) && fieldValue.equals(fieldMatchValue); } catch (Exception e) { return false; } } }
應(yīng)用類級別約束
@Data @PasswordMatches(field = "newPassword", fieldMatch = "confirmPassword") public class PasswordChangeDTO { @NotBlank private String oldPassword; @StrongPassword private String newPassword; @NotBlank private String confirmPassword; }
使用場景:驗證密碼確認(rèn)、日期范圍比較、最小/最大值比較等。
總結(jié)
Spring Validation提供了一套全面而強(qiáng)大的數(shù)據(jù)校驗工具,從基本的注解驗證到復(fù)雜的自定義約束,從單一字段驗證到跨字段關(guān)系驗證,都有相應(yīng)的解決方案。
合理利用這些驗證工具,不僅能提高應(yīng)用的健壯性和安全性,還能改善代碼質(zhì)量和可維護(hù)性。
以上就是Spring Validation中9個數(shù)據(jù)校驗工具使用指南的詳細(xì)內(nèi)容,更多關(guān)于Spring Validation數(shù)據(jù)校驗工具的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于java的包Package中同名類的沖突及其理解
這篇文章主要介紹了關(guān)于java的包Package中同名類的沖突及其理解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08分析講解SpringMVC注解配置如何實(shí)現(xiàn)
這篇文章主要介紹了本文要介紹用注解方式代替web.xml與SpringMVC的配置文件,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05Netty分布式NioEventLoop優(yōu)化selector源碼解析
這篇文章主要介紹了Netty分布式NioEventLoop優(yōu)化selector源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03mybatis-plus的自動填充時間的問題(添加到數(shù)據(jù)庫的時間比當(dāng)前時間多4個小時)
這篇文章主要介紹了mybatis-plus的自動填充時間的問題(添加到數(shù)據(jù)庫的時間比當(dāng)前時間多4個小時),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09Java基于TCP協(xié)議socket網(wǎng)絡(luò)編程的文件傳送的實(shí)現(xiàn)
這篇文章主要介紹了Java基于TCP協(xié)議socket網(wǎng)絡(luò)編程的文件傳送的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12SpringBoot中分頁插件PageHelper的使用詳解
分頁查詢是為了高效展示大量數(shù)據(jù),通過分頁將數(shù)據(jù)劃分為多個部分逐頁展示,原生方法需手動計算數(shù)據(jù)起始行,而使用PageHelper插件則簡化這一過程,本文給大家介紹SpringBoot中分頁插件PageHelper的使用,感興趣的朋友一起看看吧2024-09-09