Validation is crucial in Spring Boot applications. Here’s a complete guide to using @Valid and @Validated.
Basic Validation Dependencies <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> Bean Validation public class CreateUserRequest { @NotBlank(message = "Name is required") private String name; @Email(message = "Invalid email format") @NotBlank private String email; @Min(value = 18, message = "Age must be at least 18") @Max(value = 120, message = "Age must be at most 120") private Integer age; } @Valid vs @Validated @Valid @PostMapping("/users") public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request) { // Validates request object } @Validated @RestController @Validated public class UserController { @GetMapping("/users/{id}") public User getUser(@PathVariable @Min(1) Long id) { // Validates path variable } } Custom Validators @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = PhoneNumberValidator.class) public @interface PhoneNumber { String message() default "Invalid phone number"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { return value != null && value.matches("^\\+?[1-9]\\d{1,14}$"); } } Validation Groups public interface CreateGroup {} public interface UpdateGroup {} public class UserRequest { @NotNull(groups = UpdateGroup.class) private Long id; @NotBlank(groups = {CreateGroup.class, UpdateGroup.class}) private String name; } @PostMapping("/users") public ResponseEntity<User> create(@Validated(CreateGroup.class) @RequestBody UserRequest request) { // Only validates CreateGroup fields } Error Handling @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidation( MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getFieldErrors().forEach(error -> errors.put(error.getField(), error.getDefaultMessage()) ); return ResponseEntity.badRequest() .body(new ErrorResponse("Validation failed", errors)); } } Best Practices Validate at controller level Use appropriate annotations Create custom validators Handle validation errors Use validation groups Conclusion Spring Boot validation provides:
...