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 = "手機號碼格式不正確")
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);
}
}
最佳實踐:使用有意義的錯誤消息,保持一致的命名風格,避免在實體類上直接使用驗證注解,而是在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 {};
}
實現(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 // 標記需要級聯(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 // 進一步嵌套驗證
private AddressDTO address;
}
關(guā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ù)期,增強代碼的健壯性。
6. 錯誤消息處理和國際化
Spring Validation提供了強大的錯誤消息處理和國際化支持。
自定義錯誤消息
在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還支持以編程方式進行驗證。
使用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)點:提高代碼可讀性和可維護性,確保驗證規(guī)則在整個應(yīng)用中保持一致。
9. 跨字段驗證
跨字段驗證允許根據(jù)多個字段之間的關(guān)系進行驗證。
創(chuàng)建類級別約束
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordMatchesValidator.class)
public @interface PasswordMatches {
String message() default "確認密碼與新密碼不匹配";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String field();
String fieldMatch();
}
實現(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;
}
使用場景:驗證密碼確認、日期范圍比較、最小/最大值比較等。
總結(jié)
Spring Validation提供了一套全面而強大的數(shù)據(jù)校驗工具,從基本的注解驗證到復(fù)雜的自定義約束,從單一字段驗證到跨字段關(guān)系驗證,都有相應(yīng)的解決方案。
合理利用這些驗證工具,不僅能提高應(yīng)用的健壯性和安全性,還能改善代碼質(zhì)量和可維護性。
以上就是Spring Validation中9個數(shù)據(jù)校驗工具使用指南的詳細內(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
Netty分布式NioEventLoop優(yōu)化selector源碼解析
這篇文章主要介紹了Netty分布式NioEventLoop優(yōu)化selector源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03
mybatis-plus的自動填充時間的問題(添加到數(shù)據(jù)庫的時間比當前時間多4個小時)
這篇文章主要介紹了mybatis-plus的自動填充時間的問題(添加到數(shù)據(jù)庫的時間比當前時間多4個小時),本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
Java基于TCP協(xié)議socket網(wǎng)絡(luò)編程的文件傳送的實現(xiàn)
這篇文章主要介紹了Java基于TCP協(xié)議socket網(wǎng)絡(luò)編程的文件傳送的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2020-12-12
SpringBoot中分頁插件PageHelper的使用詳解
分頁查詢是為了高效展示大量數(shù)據(jù),通過分頁將數(shù)據(jù)劃分為多個部分逐頁展示,原生方法需手動計算數(shù)據(jù)起始行,而使用PageHelper插件則簡化這一過程,本文給大家介紹SpringBoot中分頁插件PageHelper的使用,感興趣的朋友一起看看吧2024-09-09

