💻 Exemplos: Capítulo 04: Validação com Jakarta Validation (@Valid) e Exception Handling Global
Especialização em Backend com Java & Spring Boot • Demonstrações Práticas Compiláveis
💻 Código de Exemplo 01 — Controller com @Valid e Tratamento Global de Erros (RFC 7807)
package com.empresa.api.usuario.dto;
import jakarta.validation.constraints.*;
public record UsuarioRequestDTO(
@NotBlank(message = "Nome é obrigatório") String nome,
@Email(message = "E-mail inválido") @NotBlank String email,
@Positive @Max(120) int idade
) {}
package com.empresa.api.usuario;
import com.empresa.api.usuario.dto.UsuarioRequestDTO;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/usuarios")
public class UsuarioController {
@PostMapping
public ResponseEntity<String> criar(@Valid @RequestBody UsuarioRequestDTO dto) {
return ResponseEntity.status(HttpStatus.CREATED).body("Usuário " + dto.nome() + " criado.");
}
}
package com.empresa.api.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ProblemDetail> handleValidacao(MethodArgumentNotValidException ex) {
ProblemDetail problema = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);
problema.setTitle("Erro de Validação de Campos");
problema.setProperty("erros", ex.getFieldErrors().stream()
.map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
.toList());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(problema);
}
}
💻 Código de Exemplo 02 — Validador Customizado (@CpfValido) com ConstraintValidator
package com.empresa.api.validacao;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = CpfValidator.class)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CpfValido {
String message() default "CPF inválido";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
package com.empresa.api.validacao;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CpfValidator implements ConstraintValidator<CpfValido, String> {
@Override
public boolean isValid(String cpf, ConstraintValidatorContext context) {
if (cpf == null) return false;
String digitos = cpf.replaceAll("\\D", "");
return digitos.length() == 11 && !digitos.chars().allMatch(c -> c == digitos.charAt(0));
}
}
💻 Código de Exemplo 03 — Validation Groups para Diferenciar POST e PUT
package com.empresa.api.usuario.dto;
public interface OnCreate {}
public interface OnUpdate {}
package com.empresa.api.usuario.dto;
import jakarta.validation.constraints.Null;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
public record UsuarioGrupoDTO(
@Null(groups = OnCreate.class) @NotNull(groups = OnUpdate.class) Long id,
@NotBlank(groups = {OnCreate.class, OnUpdate.class}) String nome
) {}
package com.empresa.api.usuario;
import com.empresa.api.usuario.dto.OnCreate;
import com.empresa.api.usuario.dto.OnUpdate;
import com.empresa.api.usuario.dto.UsuarioGrupoDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/usuarios-grupo")
@Validated
public class UsuarioGrupoController {
@PostMapping
public String criar(@Validated(OnCreate.class) @RequestBody UsuarioGrupoDTO dto) {
return "Criado: " + dto.nome();
}
@PutMapping("/{id}")
public String atualizar(@PathVariable Long id, @Validated(OnUpdate.class) @RequestBody UsuarioGrupoDTO dto) {
return "Atualizado: " + dto.id();
}
}