Spring Validation中9個(gè)數(shù)據(jù)校驗(yàn)工具使用指南
1. Bean Validation基礎(chǔ)注解
Spring Validation集成了JSR-380 (Bean Validation 2.0)規(guī)范,提供了一系列開箱即用的校驗(yàn)注解。
常用注解示例
@Data public class UserDTO { @NotNull(message = "用戶ID不能為空") private Long id; @NotBlank(message = "用戶名不能為空") @Size(min = 4, max = 20, message = "用戶名長(zhǎng)度必須在4到20個(gè)字符之間") 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ī)號(hào)碼格式不正確") 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()) { // 處理驗(yàn)證錯(cuò)誤 throw new ValidationException(bindingResult); } // 處理業(yè)務(wù)邏輯 return ResponseEntity.ok(userDTO); } }
最佳實(shí)踐:使用有意義的錯(cuò)誤消息,保持一致的命名風(fēng)格,避免在實(shí)體類上直接使用驗(yàn)證注解,而是在DTO對(duì)象上應(yīng)用驗(yàn)證規(guī)則。
2. 自定義約束驗(yàn)證器
Spring Validation允許開發(fā)者創(chuàng)建自定義約束,滿足特定業(yè)務(wù)規(guī)則的驗(yàn)證需求。
定義自定義約束注解
@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)驗(yà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; // 其他字段... }
使用場(chǎng)景:驗(yàn)證業(yè)務(wù)特定規(guī)則,如唯一性約束、密碼復(fù)雜度、信用卡格式等。
3. 分組驗(yàn)證
分組驗(yàn)證允許根據(jù)不同場(chǎng)景應(yīng)用不同的驗(yàn)證規(guī)則,例如創(chuàng)建和更新操作可能需要不同的驗(yàn)證邏輯。
定義驗(yàn)證分組
// 定義驗(yàn)證分組接口 public interface ValidationGroups { interface Create {} interface Update {} }
應(yīng)用分組到約束
@Data public class ProductDTO { @Null(groups = ValidationGroups.Create.class, message = "創(chuàng)建產(chǎn)品時(shí)ID必須為空") @NotNull(groups = ValidationGroups.Update.class, message = "更新產(chǎn)品時(shí)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
,因?yàn)橹挥星罢咧С址纸M驗(yàn)證。
4. 嵌套驗(yàn)證
嵌套驗(yàn)證允許驗(yàn)證復(fù)雜對(duì)象結(jié)構(gòu)中的嵌套對(duì)象。
定義嵌套對(duì)象
@Data public class OrderDTO { @NotNull private Long id; @NotNull @Valid // 標(biāo)記需要級(jí)聯(lián)驗(yàn)證的字段 private CustomerDTO customer; @NotEmpty @Valid // 驗(yàn)證集合中的每個(gè)元素 private List<OrderItemDTO> items; } @Data public class CustomerDTO { @NotNull private Long id; @NotBlank private String name; @Email private String email; @Valid // 進(jìn)一步嵌套驗(yàn)證 private AddressDTO address; }
關(guān)鍵點(diǎn):在需要級(jí)聯(lián)驗(yàn)證的字段上添加@Valid
注解,確保驗(yàn)證深入到嵌套對(duì)象中。
5. 方法級(jí)別驗(yàn)證
Spring Validation不僅可以用于控制器參數(shù),還可以應(yīng)用于服務(wù)層的方法。
啟用方法級(jí)別驗(yàn)證
@Configuration @EnableMethodValidation public class ValidationConfig { // 配置內(nèi)容 }
定義帶驗(yàn)證的服務(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)用場(chǎng)景:確保服務(wù)層方法接收到的參數(shù)和返回的結(jié)果符合預(yù)期,增強(qiáng)代碼的健壯性。
6. 錯(cuò)誤消息處理和國(guó)際化
Spring Validation提供了強(qiáng)大的錯(cuò)誤消息處理和國(guó)際化支持。
自定義錯(cuò)誤消息
在ValidationMessages.properties
文件中定義:
# ValidationMessages.properties javax.validation.constraints.NotEmpty.message=字段不能為空 javax.validation.constraints.Email.message=不是有效的電子郵箱地址 user.name.size=用戶名長(zhǎng)度必須在{min}到{max}個(gè)字符之間
國(guó)際化錯(cuò)誤消息
創(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=用戶名長(zhǎng)度必須在{min}到{max}個(gè)字符之間
使用自定義消息
@Size(min = 4, max = 20, message = "{user.name.size}") private String username;
7. 程序化驗(yàn)證
除了注解驅(qū)動(dòng)的驗(yàn)證,Spring Validation還支持以編程方式進(jìn)行驗(yàn)證。
使用Validator手動(dòng)驗(yàn)證對(duì)象
@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()); } }
使用場(chǎng)景:在復(fù)雜業(yè)務(wù)邏輯中需要條件性驗(yàn)證,或者驗(yàn)證非控制器傳入的對(duì)象時(shí)。
8. 組合約束
組合約束允許將多個(gè)基本約束組合成一個(gè)更復(fù)雜的約束,減少代碼重復(fù)。
創(chuàng)建組合約束
@NotNull @Size(min = 8, max = 30) @Pattern(regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$", message = "密碼必須包含至少一個(gè)數(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ù)性,確保驗(yàn)證規(guī)則在整個(gè)應(yīng)用中保持一致。
9. 跨字段驗(yàn)證
跨字段驗(yàn)證允許根據(jù)多個(gè)字段之間的關(guān)系進(jìn)行驗(yàn)證。
創(chuàng)建類級(jí)別約束
@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)驗(yà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)用類級(jí)別約束
@Data @PasswordMatches(field = "newPassword", fieldMatch = "confirmPassword") public class PasswordChangeDTO { @NotBlank private String oldPassword; @StrongPassword private String newPassword; @NotBlank private String confirmPassword; }
使用場(chǎng)景:驗(yàn)證密碼確認(rèn)、日期范圍比較、最小/最大值比較等。
總結(jié)
Spring Validation提供了一套全面而強(qiáng)大的數(shù)據(jù)校驗(yàn)工具,從基本的注解驗(yàn)證到復(fù)雜的自定義約束,從單一字段驗(yàn)證到跨字段關(guān)系驗(yàn)證,都有相應(yīng)的解決方案。
合理利用這些驗(yàn)證工具,不僅能提高應(yīng)用的健壯性和安全性,還能改善代碼質(zhì)量和可維護(hù)性。
以上就是Spring Validation中9個(gè)數(shù)據(jù)校驗(yàn)工具使用指南的詳細(xì)內(nèi)容,更多關(guān)于Spring Validation數(shù)據(jù)校驗(yàn)工具的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于java的包Package中同名類的沖突及其理解
這篇文章主要介紹了關(guān)于java的包Package中同名類的沖突及其理解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08分析講解SpringMVC注解配置如何實(shí)現(xiàn)
這篇文章主要介紹了本文要介紹用注解方式代替web.xml與SpringMVC的配置文件,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05Netty分布式NioEventLoop優(yōu)化selector源碼解析
這篇文章主要介紹了Netty分布式NioEventLoop優(yōu)化selector源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03mybatis-plus的自動(dòng)填充時(shí)間的問題(添加到數(shù)據(jù)庫的時(shí)間比當(dāng)前時(shí)間多4個(gè)小時(shí))
這篇文章主要介紹了mybatis-plus的自動(dòng)填充時(shí)間的問題(添加到數(shù)據(jù)庫的時(shí)間比當(dāng)前時(shí)間多4個(gè)小時(shí)),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09Java基于TCP協(xié)議socket網(wǎng)絡(luò)編程的文件傳送的實(shí)現(xiàn)
這篇文章主要介紹了Java基于TCP協(xié)議socket網(wǎng)絡(luò)編程的文件傳送的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12SpringBoot中分頁插件PageHelper的使用詳解
分頁查詢是為了高效展示大量數(shù)據(jù),通過分頁將數(shù)據(jù)劃分為多個(gè)部分逐頁展示,原生方法需手動(dòng)計(jì)算數(shù)據(jù)起始行,而使用PageHelper插件則簡(jiǎn)化這一過程,本文給大家介紹SpringBoot中分頁插件PageHelper的使用,感興趣的朋友一起看看吧2024-09-09