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();
    }
}