1. Basic Annotations of Bean Validation
Spring Validation integrates the JSR-380 (Bean Validation 2.0) specification and provides a series of out-of-the-box verification annotations.
Common annotation examples
@Data public class UserDTO { @NotNull(message = "User ID cannot be empty") private Long id; @NotBlank(message = "Username cannot be empty") @Size(min = 4, max = 20, message = "The username must be between 4 and 20 characters") private String username; @Email(message = "The email format is incorrect") private String email; @Min(value = 18, message = "Age must be greater than or equal to 18") @Max(value = 120, message = "Age must be less than or equal to 120") private Integer age; @Past(message = "The date of birth must be a past date") private LocalDate birthDate; @Pattern(regexp = "^1[3-9]\d{9}$", message = "Mobile phone number format is incorrect") private String phoneNumber; }
Apply in the controller
@RestController @RequestMapping("/api/users") public class UserController { @PostMapping public ResponseEntity<UserDTO> createUser(@RequestBody @Valid UserDTO userDTO, BindingResult bindingResult) { if (()) { // Handle verification errors throw new ValidationException(bindingResult); } // Handle business logic return (userDTO); } }
Best Practices: Use meaningful error messages, maintain a consistent naming style, avoid using verification annotations directly on entity classes, but apply verification rules on DTO objects.
2. Custom Constraint Verifier
Spring Validation allows developers to create custom constraints that meet the verification needs of specific business rules.
Define custom constraint annotations
@Target({, }) @Retention() @Constraint(validatedBy = ) public @interface UniqueUsername { String message() default "Username already exists"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
Implementing a validator
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> { @Autowired private UserRepository userRepository; @Override public boolean isValid(String username, ConstraintValidatorContext context) { if (username == null) { return true; // Let @NotNull handle null values } return !(username); } }
Apply custom constraints
public class UserRegistrationDTO { @NotBlank @Size(min = 4, max = 20) @UniqueUsername private String username; // Other fields...}
Use scenarios: Verify business-specific rules, such as uniqueness constraints, password complexity, credit card format, etc.
3. Group verification
Grouping verification allows different verification rules to be applied according to different scenarios, such as creation and update operations may require different verification logic.
Define verification grouping
// Define the verification packet interfacepublic interface ValidationGroups { interface Create {} interface Update {} }
Apply grouping to constraints
@Data public class ProductDTO { @Null(groups = , message = "The ID must be empty when creating the product") @NotNull(groups = , message = "The ID cannot be empty when updating the product") private Long id; @NotBlank(groups = {, }) private String name; @PositiveOrZero(groups = ) @Positive(groups = ) private BigDecimal price; }
Specify a group in the controller
@RestController @RequestMapping("/api/products") public class ProductController { @PostMapping public ResponseEntity<ProductDTO> createProduct( @RequestBody @Validated() ProductDTO productDTO) { // Create product logic return (productDTO); } @PutMapping("/{id}") public ResponseEntity<ProductDTO> updateProduct( @PathVariable Long id, @RequestBody @Validated() ProductDTO productDTO) { // Update product logic return (productDTO); } }
hint: Pay attention to use@Validated
Annotation instead of@Valid
, because only the former supports group verification.
4. Nested Verification
Nested validation allows validation of nested objects in complex object structures.
Define nested objects
@Data public class OrderDTO { @NotNull private Long id; @NotNull @Valid // Mark fields that require cascading verification private CustomerDTO customer; @NotEmpty @Valid // Verify each element in the collection private List<OrderItemDTO> items; } @Data public class CustomerDTO { @NotNull private Long id; @NotBlank private String name; @Email private String email; @Valid // Further nested verification private AddressDTO address; }
Key points: Add on fields that require cascading verification@Valid
Annotation, ensure validation is penetrated into nested objects.
5. Method level verification
Spring Validation can not only be used for controller parameters, but also for service layer methods.
Enable method level verification
@Configuration @EnableMethodValidation public class ValidationConfig { //Configuration content}
Define service methods with verification
@Service public class UserService { @Validated public User createUser(@Valid UserDTO userDTO) { // Business logic return new User(); } @NotNull public User findById(@Min(1) Long id) { // Query logic return new User(); } @Validated() public void updateUser(@Valid UserDTO userDTO) { // Update logic } }
Application scenarios: Ensure that the parameters received by the service layer method meet expectations and the results returned are in line with expectations and enhance the robustness of the code.
6. Error message processing and internationalization
Spring Validation provides powerful error message processing and internationalization support.
Custom error message
existDefinition in the file:
# =Field cannot be empty =Not a valid email address =The username length must be{min}arrive{max}Between characters
Internationalization error message
Create a language-specific property file:
# ValidationMessages_en.properties =Field cannot be empty =Not a valid email address =Username must be between {min} and {max} characters # ValidationMessages_zh_CN.properties =Field cannot be empty =Not a valid email address =The username length must be{min}arrive{max}Between characters
Using custom messages
@Size(min = 4, max = 20, message = "{}") private String username;
7. Programmatic verification
In addition to annotation-driven verification, Spring Validation also supports programmatic verification.
Use Validator to manually verify objects
@Service public class ValidationService { private final Validator validator; public ValidationService(Validator validator) { = validator; } public <T> void validate(T object) { Set<ConstraintViolation<T>> violations = (object); if (!()) { throw new ConstraintViolationException(violations); } } public <T> void validateWithGroup(T object, Class<?>... groups) { Set<ConstraintViolation<T>> violations = (object, groups); if (!()) { throw new ConstraintViolationException(violations); } } public <T> List<String> getValidationErrors(T object) { return (object).stream() .map(ConstraintViolation::getMessage) .collect(()); } }
Use scenarios: When conditional verification is required in complex business logic, or when objects passed in by non-controllers are verified.
8. Combination constraints
Combination constraints allow multiple basic constraints to be combined into one more complex constraint, reducing code duplication.
Create combination constraints
@NotNull @Size(min = 8, max = 30) @Pattern(regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$", message = "The password must contain at least one number, lowercase letters, uppercase letters and special characters") @Target({, }) @Retention() @Constraint(validatedBy = {}) public @interface StrongPassword { String message() default "Password does not meet security requirements"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
Apply combination constraints
public class PasswordChangeDTO { @NotBlank private String oldPassword; @StrongPassword private String newPassword; @NotBlank private String confirmPassword; }
advantage: Improve code readability and maintainability, ensuring that verification rules are consistent throughout the application.
9. Cross-field verification
Cross-field verification allows verification based on the relationship between multiple fields.
Create class-level constraints
@Target({}) @Retention() @Constraint(validatedBy = ) public @interface PasswordMatches { String message() default "Confirm your password does not match the new password"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String field(); String fieldMatch(); }
Implementing a validator
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> { private String field; private String fieldMatch; @Override public void initialize(PasswordMatches constraintAnnotation) { = (); = (); } @Override public boolean isValid(Object value, ConstraintValidatorContext context) { try { Object fieldValue = ((), field) .getReadMethod().invoke(value); Object fieldMatchValue = ((), fieldMatch) .getReadMethod().invoke(value); return (fieldValue != null) && (fieldMatchValue); } catch (Exception e) { return false; } } }
Apply class-level constraints
@Data @PasswordMatches(field = "newPassword", fieldMatch = "confirmPassword") public class PasswordChangeDTO { @NotBlank private String oldPassword; @StrongPassword private String newPassword; @NotBlank private String confirmPassword; }
Use scenarios: Verify password confirmation, date range comparison, minimum/maximum comparison, etc.
Summarize
Spring Validation provides a comprehensive and powerful data verification tool, with corresponding solutions from basic annotation verification to complex custom constraints, from single-field verification to cross-field relationship verification.
Rational use of these verification tools can not only improve the robustness and security of the application, but also improve code quality and maintainability.
The above is the detailed content of the 9 data verification tools used in Spring Validation. For more information about Spring Validation data verification tools, please pay attention to my other related articles!