SoFunction
Updated on 2025-05-11

Guide to using 9 data verification tools in Spring Validation

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@ValidatedAnnotation 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@ValidAnnotation, 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])(?=.*[@#$%^&amp;+=]).*$", 
         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&lt;?&gt;[] groups() default {};
    Class&lt;? extends Payload&gt;[] 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&lt;?&gt;[] groups() default {};
    Class&lt;? extends Payload&gt;[] 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!