Trilha da Alura Java e Spring Boot: Aprenda a criar aplicações com o framework mais amado do mundo Java.
API REST desenvolvida com Spring Boot para gerenciamento de médicos e pacientes de uma clínica médica, com autenticação de usuários via Spring Security e JWT.
| Tecnologia | Versão | Uso |
|---|---|---|
| Java | 17 | Linguagem principal |
| Spring Boot | 4.1.0 | Framework base |
| Spring Data JPA | - | Persistência e repositórios |
| Spring Validation | - | Validação dos dados de entrada |
| Spring Security | - | Autenticação e controle de acesso |
| Auth0 java-jwt | 4.2.1 | Geração e validação de tokens JWT |
| Flyway | - | Versionamento do banco de dados |
| Lombok | - | Redução de boilerplate (getters, construtores) |
| MySQL | - | Banco de dados relacional |
| Maven | - | Gerenciamento de dependências |
- DTO (Data Transfer Object): Records Java usados para receber e retornar dados da API, separando a camada de transporte da entidade de domínio
- JPA / Hibernate: Mapeamento objeto-relacional com anotações
@Entity,@Table,@Embedded,@Enumerated - Paginação: Resposta paginada com
PageableePage<T>noGETde listagem - Soft Delete: Exclusão lógica — o registro não é removido do banco, apenas o campo
ativoé definido comofalse - Injeção por construtor: Substituição do
@Autowiredno campo pela injeção via construtor (boa prática recomendada pelo Spring) - Bean Validation: Anotações
@Valid,@NotBlank,@NotNull,@Emailnos DTOs para validar os dados recebidos - Flyway Migrations: Versionamento incremental do schema com arquivos
.sqlemresources/db/migration - @Transactional: Controle de transação nas operações de escrita
- Códigos HTTP corretos:
201 Createdcom headerLocationno cadastro,204 No Contentna exclusão,200 OKcom DTO de detalhes na atualização e no detalhamento - Tratamento de erros centralizado: Classe
@RestControllerAdvice(TratadorDeErros) que converte exceções em respostas HTTP:EntityNotFoundException→404 Not FoundMethodArgumentNotValidException→400 Bad Requestcom a lista de campos inválidos (campo/mensagem)- Stacktrace oculto nas respostas de erro (
spring.web.error.include-stacktrace=never)
- Spring Security (stateless): Sessões desabilitadas (
SessionCreationPolicy.STATELESS) e CSRF desabilitado, já que a API é REST e protegida por token - Autenticação de usuários:
AutenticacaoServiceimplementaUserDetailsServiceeUsuarioimplementaUserDetails; senhas armazenadas com hash BCrypt - JWT (JSON Web Token):
TokenServicegera tokens assinados com HMAC256, com issuerAPI Voll.med, subject = login do usuário e expiração de 2 horas - Filtro de segurança:
SecurityFilter(OncePerRequestFilter) lê o headerAuthorization: Bearer <token>, valida o token e autentica o usuário noSecurityContextHolder; é registrado antes doUsernamePasswordAuthenticationFilter
src/main/java/med/voll/api/
├── controller/
│ ├── AutenticacaoController.java (POST /login)
│ ├── MedicoController.java
│ └── PacienteController.java
├── domain/
│ ├── endereco/
│ │ ├── Endereco.java (embeddable)
│ │ └── DadosEndereco.java (DTO)
│ ├── medico/
│ │ ├── Medico.java (entidade)
│ │ ├── MedicoRepository.java
│ │ ├── Especialidade.java (enum)
│ │ ├── DadosCadastroMedico.java (DTO)
│ │ ├── DadosListagemMedico.java (DTO)
│ │ ├── DadosAtualizacaoMedico.java (DTO)
│ │ └── DadosDetalhesMedico.java (DTO)
│ ├── paciente/
│ │ ├── Paciente.java (entidade)
│ │ ├── PacienteRepository.java
│ │ ├── DadosCadastroPaciente.java (DTO)
│ │ ├── DadosListagemPaciente.java (DTO)
│ │ ├── DadosAtualizacaoPaciente.java(DTO)
│ │ └── DadosDetalhesPaciente.java (DTO)
│ └── usuario/
│ ├── Usuario.java (entidade / UserDetails)
│ ├── UsuarioRepository.java
│ ├── AutenticacaoService.java (UserDetailsService)
│ └── DadosAutenticacao.java (DTO)
└── infra/
├── exception/
│ └── TratadorDeErros.java (@RestControllerAdvice)
└── security/
├── SecurityConfigurations.java (SecurityFilterChain, BCrypt, AuthenticationManager)
├── SecurityFilter.java (filtro que valida o JWT)
├── TokenService.java (geração/validação do JWT)
└── DadosTokenJWT.java (DTO)
Com exceção de
POST /login, todas as rotas exigem autenticação. Envie o token no header:Authorization: Bearer <token>
| Método | Rota | Descrição |
|---|---|---|
POST |
/login |
Autentica o usuário e retorna um token JWT |
Exemplo de requisição:
{
"login": "usuario@voll.med",
"senha": "123456"
}Exemplo de resposta:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}| Método | Rota | Descrição |
|---|---|---|
POST |
/medicos |
Cadastra um novo médico (201 Created) |
GET |
/medicos |
Lista médicos ativos (paginado, ordenado por nome) |
GET |
/medicos/{id} |
Detalha um médico |
PUT |
/medicos |
Atualiza dados de um médico |
DELETE |
/medicos/{id} |
Inativa um médico (soft delete, 204 No Content) |
| Método | Rota | Descrição |
|---|---|---|
POST |
/pacientes |
Cadastra um novo paciente (201 Created) |
GET |
/pacientes |
Lista pacientes ativos (paginado, ordenado por nome) |
GET |
/pacientes/{id} |
Detalha um paciente |
PUT |
/pacientes |
Atualiza dados de um paciente |
DELETE |
/pacientes/{id} |
Inativa um paciente (soft delete, 204 No Content) |
V1__create-table-medicos.sql
V2__alter-table-medicos-add-column-telefone.sql
V3__alter-table-medicos-add-column-ativo.sql
V4__create-table-pacientes.sql
V5__alter-table-pacientes-add-column-ativo.sql
V6__create-table-usuarios.sql
Pré-requisitos: Java 17, Maven e MySQL instalados.
-
Configure o banco de dados em
src/main/resources/application.properties:spring.datasource.url=jdbc:mysql://localhost/vollmed_api spring.datasource.username=seu_usuario spring.datasource.password=sua_senha
-
Defina o segredo usado para assinar os tokens JWT pela variável de ambiente
JWT_SECRET(se não for definida, o valor padrão12345678é usado — não use em produção):api.security.token.secret=${JWT_SECRET:12345678} -
Execute:
mvn spring-boot:run
O Flyway criará as tabelas automaticamente na primeira execução.
-
Cadastre um usuário na tabela
usuarioscom a senha em hash BCrypt. Exemplo (senha123456):INSERT INTO usuarios (login, senha) VALUES ('usuario@voll.med', '$2a$12$iIAdFWDsyXIh8z88jt5CoON1fHH60jRpSJWgixrn8kvVs3u4vEUKu');
-
Faça
POST /loginpara obter o token e use-o no headerAuthorizationdas demais requisições.