0% acharam este documento útil (0 voto)
3 visualizações27 páginas

Java Spring Boot FullStack

O documento é um guia prático para desenvolvedores Front-End que desejam aprender Java e Spring Boot, cobrindo desde fundamentos de Java até a construção de APIs REST completas. Inclui tópicos como segurança, testes automatizados e deploy, com projetos reais desde o primeiro capítulo. A versão é voltada para Java 21 e Spring Boot 3.x, com foco em práticas de mercado e desenvolvimento full-stack.

Enviado por

Fidelino Masta
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
3 visualizações27 páginas

Java Spring Boot FullStack

O documento é um guia prático para desenvolvedores Front-End que desejam aprender Java e Spring Boot, cobrindo desde fundamentos de Java até a construção de APIs REST completas. Inclui tópicos como segurança, testes automatizados e deploy, com projetos reais desde o primeiro capítulo. A versão é voltada para Java 21 e Spring Boot 3.x, com foco em práticas de mercado e desenvolvimento full-stack.

Enviado por

Fidelino Masta
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

Java & Spring Boot

Do Zero ao Full-Stack

Guia prático para Developers Front-End que querem dominar o Back-End


Foco total em Spring Boot • REST APIs • JPA • Segurança • Deploy
Projectos reais desde o Capítulo 1

Versão 1.0 • Java 21 • Spring Boot 3.x • 2026


Índice
01 Fundamentos de Java para Quem Vem do TypeScript/Angular
• Tipos, variáveis e controlo de fluxo
• Classes, interfaces e generics
• Streams e Lambdas (equivalente ao RxJS/Array methods)
• Tratamento de erros com exceptions

02 Arquitectura Spring Boot — O Ecossistema


• O que é o Spring e IoC/DI
• Estrutura de um projecto Spring Boot
• [Link] / [Link]
• Comparação com Angular (Modules → @Configuration)

03 Projecto 1 — API REST de Gestão de Tarefas


• Controller → Service → Repository
• CRUD completo com Spring MVC
• Validações com Bean Validation
• Testes com Postman / curl

04 Base de Dados com Spring Data JPA


• Entidades, relacionamentos e migrations com Flyway
• Repositórios e queries derivadas
• JPQL e @Query personalizada
• PostgreSQL em produção

05 Projecto 2 — API de E-Commerce (Produtos & Pedidos)


• Relacionamentos @OneToMany / @ManyToMany
• DTOs e MapStruct
• Paginação e filtros
• Tratamento global de erros

06 Segurança com Spring Security + JWT


• Autenticação stateless
• Registo e Login de utilizadores
• Proteção de rotas por roles
• Integração com o front-end Angular

07 Projecto 3 — API Completa com Autenticação JWT


• Sistema de utilizadores e perfis
• Upload de ficheiros
• Envio de e-mails
• Documentação com Swagger/OpenAPI

08 Testes Automatizados
• Unit tests com JUnit 5 e Mockito

Java & Spring Boot — Do Zero ao Full-Stack Pág. 2


• Testes de integração com @SpringBootTest
• Testes de controller com MockMvc

09 Deploy e Produção
• Docker e docker-compose
• Variáveis de ambiente
• Deploy no Railway / Render
• Boas práticas de produção

10 Próximos Passos no Mercado de Trabalho


• Padrões de projecto mais usados
• Microserviços — introdução
• Portfolio e GitHub

Java & Spring Boot — Do Zero ao Full-Stack Pág. 3


Fundamentos de Java

Introdução
Se já dominas TypeScript e Angular, aprender Java vai ser mais rápido do que pensas. As bases são
semelhantes: tipagem estática, classes, interfaces, generics. A grande diferença é que Java compila
para bytecode que corre na JVM (Java Virtual Machine), e toda a sua sintaxe é explicitamente
orientada a objectos. Neste capítulo vais aprender exactamente o que precisas para começar a
escrever código Spring Boot sem perder tempo.

Tipos e Variáveis
Conceito TypeScript Java

String string String

Número inteiro number int / Integer

Número decimal number double / Double

Booleano boolean boolean / Boolean

Lista Array<T> / T[] List<T>

Mapa Map<K,V> Map<K,V>

Sem valor null / undefined null

Constante const x = 1 final int x = 1

Inferência de tipo let x = 1 var x = 1 (Java 10+)

Exemplo — Declaração de Variáveis


// Tipos primitivos
int idade = 25;
double salario = 3500.50;
boolean activo = true;
String nome = "Maria";
// Inferência de tipo (Java 10+) — equivalente ao 'let' do TS
var produto = "Teclado"; // Java infere String
// Constante — equivalente ao 'const' do TS
final double PI = 3.14159;
// Colecções — sempre com generics
List<String> nomes = new ArrayList<>();
Map<String, Integer> idades = new HashMap<>();

Java & Spring Boot — Do Zero ao Full-Stack Pág. 4


[Link]("Ana");
[Link]("Ana", 30);

Classes e Objectos
Em Java, tudo está dentro de classes. Não existem funções soltas como no JavaScript. Uma classe
define o modelo (blueprint) e os objectos são as instâncias. A anotação @Data do Lombok (que vais
usar muito no Spring) gera automaticamente getters, setters, equals e toString, como um interface
TypeScript mas com muito menos código.
// Classe Java tradicional
public class Produto {
private Long id;
private String nome;
private Double preco;
// Constructor
public Produto(Long id, String nome, Double preco) {
[Link] = id;
[Link] = nome;
[Link] = preco;
}
// Getters e Setters (gerados pelo Lombok com @Data)
public String getNome() { return nome; }
public void setNome(String nome) { [Link] = nome; }
}
// Com Lombok — muito mais limpo (recomendado no Spring)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Produto {
private Long id;
private String nome;
private Double preco;
}

Interfaces e Generics
Interfaces em Java funcionam como as interfaces do TypeScript: definem um contrato que as
classes devem implementar. Generics (<T>) são exactamente iguais ao TS. No Spring vais usar
interfaces constantemente (Repository, Service, etc.).
// Interface — define um contrato
public interface Calculavel {
double calcularTotal();
boolean isActivo();
}
// Classe que implementa a interface
public class Pedido implements Calculavel {
private List<Produto> produtos;
@Override

Java & Spring Boot — Do Zero ao Full-Stack Pág. 5


public double calcularTotal() {
return [Link]()
.mapToDouble(Produto::getPreco)
.sum();
}
@Override
public boolean isActivo() { return true; }
}

Streams e Lambdas — o equivalente ao .map/.filter do JS


Streams são uma das funcionalidades mais poderosas do Java moderno. Se já usas .map(), .filter(),
.reduce() em JavaScript/TypeScript, vais sentir-te confortável imediatamente.
List<Produto> produtos = [Link](
new Produto(1L, "Teclado", 120.0),
new Produto(2L, "Rato", 45.0),
new Produto(3L, "Monitor", 850.0)
);
// Equivalente ao .filter() do JS
List<Produto> caros = [Link]()
.filter(p -> [Link]() > 100)
.collect([Link]());
// Equivalente ao .map() do JS
List<String> nomes = [Link]()
.map(Produto::getNome)
.collect([Link]());
// Equivalente ao .reduce()
double total = [Link]()
.mapToDouble(Produto::getPreco)
.sum();
// forEach — equivalente ao .forEach() do JS
[Link](p -> [Link]([Link]()));

■ DICA ANGULAR→SPRING Pensa nos Streams como os operadores RxJS que já conheces:
filter() = filter(), map() = map(), reduce() = scan(). A diferença é que os Streams são síncronos.

Tratamento de Erros — Exceptions


// Lançar uma excepção personalizada
public Produto buscarPorId(Long id) {
return [Link](id)
.orElseThrow(() -> new RuntimeException("Produto não encontrado: " + id)
);
}
// Capturar excepções com try-catch
try {
Produto p = buscarPorId(99L);
} catch (RuntimeException e) {

Java & Spring Boot — Do Zero ao Full-Stack Pág. 6


[Link]("Erro: " + [Link]());
} finally {
[Link]("Executado sempre");
}

Java & Spring Boot — Do Zero ao Full-Stack Pág. 7


Arquitectura Spring Boot

O que é o Spring?
Spring é um framework para Java que resolve um problema central: como ligar e gerir as
dependências entre os componentes da aplicação. Faz isso através de IoC (Inversion of Control) e
DI (Dependency Injection) — conceitos que já conheces do Angular! O @Injectable() do Angular
equivale ao @Service/@Component do Spring. O Angular injeta serviços nos componentes; o Spring
injeta Beans nos seus componentes.

Conceito Angular Spring Boot

Módulo @NgModule @Configuration

Serviço injectável @Injectable() @Service

Componente @Component @Component

Injecção de dependência constructor(private srv: MyService) @Autowired / constructor injection

Rota HTTP RouterModule @RequestMapping / @GetMapping

Middleware HTTP Interceptor Filter / @ControllerAdvice

DTO/Interface TypeScript interface Java class / record

Variáveis de ambiente [Link] [Link]

Servidor embutido ng serve (webpack) Tomcat embutido

Estrutura de um Projecto Spring Boot


Usa o Spring Initializr ([Link]) para gerar o projecto. Selecciona: Maven, Java 21, Spring Boot
3.x, e as dependências: Spring Web, Spring Data JPA, PostgreSQL Driver, Lombok, Validation.
src/
main/
java/com/empresa/projeto/
controller/ ← Recebe requisições HTTP (equivale ao Component Angular)
service/ ← Lógica de negócio (equivale ao Service Angular)
repository/ ← Acesso à base de dados (equivale ao HttpClient Angular)
model/ ← Entidades JPA (tabelas da BD)
dto/ ← Objectos de transferência de dados
exception/ ← Excepções personalizadas
config/ ← Configurações (CORS, Security, etc.)
resources/

Java & Spring Boot — Do Zero ao Full-Stack Pág. 8


[Link] ← Configuração da aplicação
test/ ← Testes unitários e de integração
[Link] ← Dependências (equivale ao [Link])

[Link] — Configuração Central


spring:
application:
name: minha-api
datasource:
url: jdbc:postgresql://localhost:5432/meubanco
username: postgres
password: ${DB_PASSWORD} # variável de ambiente
jpa:
hibernate:
ddl-auto: validate # nunca usar 'create' em produção!
show-sql: true # mostra as queries SQL no log (útil em dev)
server:
port: 8080

Java & Spring Boot — Do Zero ao Full-Stack Pág. 9


Projecto 1 — API de Tarefa

Objectivo do Projecto
Vais construir uma API REST completa para gerir tarefas (To-Do). Este é o projecto clássico de
iniciação mas vamos implementá-lo da forma profissional, com a arquitectura em 3 camadas que é
usada em produção nas empresas. No final terás endpoints GET, POST, PUT, DELETE funcionais e
testáveis.

■ O QUE VAIS APRENDER Controller → Service → Repository. Injecção de dependências.


Mapeamento de rotas HTTP. Validações automáticas. Respostas com ResponseEntity.

1. A Entidade — model/[Link]
@Entity // Mapeia esta classe para uma tabela na BD
@Table(name = "tarefas")
@Data // Lombok: gera getters, setters, equals, toSt
ring
@NoArgsConstructor
@AllArgsConstructor
public class Tarefa {
@Id
@GeneratedValue(strategy = [Link]) // auto-increment
private Long id;
@NotBlank(message = "Título é obrigatório")
@Column(nullable = false)
private String titulo;
private String descricao;
@Column(nullable = false)
private Boolean concluida = false;
@CreationTimestamp // Preenchido automaticamente pelo Hibernat
e
private LocalDateTime criadaEm;
}

2. O Repositório — repository/[Link]
// Extende JpaRepository — já tens CRUD gratuito!
// JpaRepository<Entidade, TipoDoId>
@Repository
public interface TarefaRepository extends JpaRepository<Tarefa, Long> {
// Spring gera o SQL automaticamente pelo nome do método!
List<Tarefa> findByConcluida(Boolean concluida);
// Query personalizada com JPQL

Java & Spring Boot — Do Zero ao Full-Stack Pág. 10


@Query("SELECT t FROM Tarefa t WHERE [Link] LIKE %:termo%")
List<Tarefa> pesquisarPorTitulo(@Param("termo") String termo);
}

3. O Serviço — service/[Link]
@Service // Marca como Bean gerido pelo Spring
@RequiredArgsConstructor // Lombok: constructor injection automático
public class TarefaService {
private final TarefaRepository repositorio; // injectado automaticamente
public List<Tarefa> listarTodas() {
return [Link]();
}
public Tarefa buscarPorId(Long id) {
return [Link](id)
.orElseThrow(() -> new TarefaNaoEncontradaException(id));
}
public Tarefa criar(Tarefa tarefa) {
return [Link](tarefa);
}
public Tarefa actualizar(Long id, Tarefa dados) {
Tarefa tarefa = buscarPorId(id);
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
return [Link](tarefa);
}
public void eliminar(Long id) {
buscarPorId(id); // verifica se existe antes de apagar
[Link](id);
}
}

4. O Controller — controller/[Link]
@RestController // = @Controller + @ResponseBody
@RequestMapping("/api/tarefas") // URL base de todos os endpoints
@RequiredArgsConstructor
public class TarefaController {
private final TarefaService servico;
@GetMapping // GET /api/tarefas
public ResponseEntity<List<Tarefa>> listar() {
return [Link]([Link]());
}
@GetMapping("/{id}") // GET /api/tarefas/1
public ResponseEntity<Tarefa> buscar(@PathVariable Long id) {
return [Link]([Link](id));
}
@PostMapping // POST /api/tarefas
public ResponseEntity<Tarefa> criar(@RequestBody @Valid Tarefa tarefa) {
Tarefa nova = [Link](tarefa);
URI uri = [Link]("/api/tarefas/" + [Link]());

Java & Spring Boot — Do Zero ao Full-Stack Pág. 11


return [Link](uri).body(nova);
}
@PutMapping("/{id}") // PUT /api/tarefas/1
public ResponseEntity<Tarefa> actualizar(
@PathVariable Long id,
@RequestBody @Valid Tarefa dados) {
return [Link]([Link](id, dados));
}
@DeleteMapping("/{id}") // DELETE /api/tarefas/1
public ResponseEntity<Void> eliminar(@PathVariable Long id) {
[Link](id);
return [Link]().build(); // 204 No Content
}
}

Tratamento Global de Erros


@RestControllerAdvice // Intercepta excepções de todos os controllers
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<Map<String, String>> handleNotFound(TarefaNaoEncontrad
aException e) {
return [Link](HttpStatus.NOT_FOUND)
.body([Link]("erro", [Link]())); // { "erro": "Tarefa 99 não
encontrada" }
}
@ExceptionHandler([Link])
public ResponseEntity<Map<String, String>> handleValidation(MethodArgumentNo
tValidException e) {
Map<String, String> erros = new HashMap<>();
[Link]().getFieldErrors()
.forEach(err -> [Link]([Link](), [Link]()));
return [Link]().body(erros);
}
}

Java & Spring Boot — Do Zero ao Full-Stack Pág. 12


Base de Dados com Spring

JPA e Hibernate
JPA (Jakarta Persistence API) é a especificação; Hibernate é a implementação. O Spring Data JPA é
uma camada acima que torna tudo muito mais simples. Nunca mais vais escrever SQL manual para
operações CRUD — o Spring gera tudo automaticamente a partir dos nomes dos métodos.

Relacionamentos entre Entidades


// @OneToMany — Um utilizador tem muitas tarefas
@Entity
public class Utilizador {
@Id @GeneratedValue(strategy = [Link])
private Long id;
private String nome;
@OneToMany(mappedBy = "utilizador", cascade = [Link], orphanRemoval
= true)
private List<Tarefa> tarefas = new ArrayList<>();
}
// @ManyToOne — Muitas tarefas pertencem a um utilizador
@Entity
public class Tarefa {
@Id @GeneratedValue(strategy = [Link])
private Long id;
private String titulo;
@ManyToOne(fetch = [Link]) // Não carrega utilizador até ser pedido
@JoinColumn(name = "utilizador_id")
private Utilizador utilizador;
}

Migrações de BD com Flyway


Flyway gere as alterações ao schema da base de dados de forma versionada — como o Git mas
para a base de dados. Cada migração é um ficheiro SQL numerado.
-- src/main/resources/db/migration/V1__criar_tabelas.sql
CREATE TABLE utilizadores (
id BIGSERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
criado_em TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE tarefas (
id BIGSERIAL PRIMARY KEY,

Java & Spring Boot — Do Zero ao Full-Stack Pág. 13


titulo VARCHAR(200) NOT NULL,
descricao TEXT,
concluida BOOLEAN DEFAULT FALSE,
utilizador_id BIGINT REFERENCES utilizadores(id),
criada_em TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

■ ATENÇÃO: NUNCA uses ddl-auto: create ou create-drop em produção. Isso apaga e recria as
tabelas a cada restart, perdendo todos os dados. Em produção usa sempre 'validate' e gere o
schema com Flyway.

Java & Spring Boot — Do Zero ao Full-Stack Pág. 14


Projecto 2 — API E-Comme

Arquitectura do Projecto
Neste projecto vais construir uma API para uma loja online com Produtos, Categorias, Utilizadores e
Pedidos. O foco é nos relacionamentos complexos, uso de DTOs para não expor as entidades
directamente, e paginação de resultados.

DTOs — Data Transfer Objects


DTOs são objectos que definem exactamente o que entra e sai da API. É uma boa prática nunca
expor as entidades JPA directamente — pode vazar dados sensíveis ou causar problemas de
serialização.
// DTO de criação — o que o cliente envia no POST
@Data
public class ProdutoCriacaoDTO {
@NotBlank(message = "Nome é obrigatório")
private String nome;
@NotNull @Positive(message = "Preço deve ser positivo")
private Double preco;
@NotNull
private Long categoriaId;
}
// DTO de resposta — o que a API devolve
@Data
@AllArgsConstructor
public class ProdutoRespostaDTO {
private Long id;
private String nome;
private Double preco;
private String categoriaNome; // só o nome, não o objecto inteiro
}
// Mapeamento no Service
public ProdutoRespostaDTO criar(ProdutoCriacaoDTO dto) {
Categoria categoria = [Link]([Link]())
.orElseThrow(() -> new NotFoundException("Categoria"));
Produto produto = new Produto(null, [Link](), [Link](), categoria
);
Produto salvo = [Link](produto);
return new ProdutoRespostaDTO([Link](), [Link](),
[Link](), [Link]());
}

Java & Spring Boot — Do Zero ao Full-Stack Pág. 15


Paginação e Filtros
// Controller com paginação
@GetMapping
public ResponseEntity<Page<ProdutoRespostaDTO>> listar(
@RequestParam(defaultValue = "0") int pagina,
@RequestParam(defaultValue = "10") int tamanho,
@RequestParam(defaultValue = "nome") String ordenarPor) {
Pageable pageable = [Link](pagina, tamanho, [Link](ordenarPor));
Page<ProdutoRespostaDTO> resultado = [Link](pageable);
return [Link](resultado);
}
// Chamada: GET /api/produtos?pagina=0&tamanho;=10&ordenarPor;=preco
// Resposta: { content: [...], totalElements: 50, totalPages: 5 }

Java & Spring Boot — Do Zero ao Full-Stack Pág. 16


Segurança — Spring Secur

Como Funciona a Autenticação JWT


JWT (JSON Web Token) é o padrão mais usado para autenticação stateless em REST APIs. O fluxo
é simples: o utilizador faz login com email/password, a API valida as credenciais e devolve um token
JWT. Nas próximas requisições, o cliente envia o token no header Authorization: Bearer {token} e a
API valida o token sem precisar de consultar a base de dados em cada pedido.

Passo Cliente (Angular) Servidor (Spring)

1 POST /auth/login Valida credenciais na BD


{ email, password }

2 Recebe { token: 'eyJ...' } Gera e assina o JWT

3 Guarda token no localStorage —

4 GET /api/dados Valida a assinatura do token


Authorization: Bearer eyJ...

5 Recebe os dados Retorna os dados se token válido

Dependências necessárias no [Link]


<!-- Spring Security -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.3</version>
</dependency>

JwtService — Geração e Validação de Tokens


@Service
public class JwtService {

Java & Spring Boot — Do Zero ao Full-Stack Pág. 17


@Value("${[Link]}") // lido do [Link]
private String segredo;
@Value("${[Link]}") // 24h em ms por defeito
private long expiracao;
public String gerarToken(UserDetails usuario) {
return [Link]()
.subject([Link]())
.issuedAt(new Date())
.expiration(new Date([Link]() + expiracao))
.signWith(getChave())
.compact();
}
public String extrairEmail(String token) {
return [Link]().verifyWith(getChave())
.build().parseSignedClaims(token).getPayload().getSubject();
}
public boolean isTokenValido(String token, UserDetails usuario) {
String email = extrairEmail(token);
return [Link]([Link]()) && !isTokenExpirado(token);
}
private SecretKey getChave() {
return [Link]([Link](segredo));
}
private boolean isTokenExpirado(String token) {
Date expiracao = [Link]().verifyWith(getChave())
.build().parseSignedClaims(token).getPayload().getExpiration();
return [Link](new Date());
}
}

SecurityConfig — Configuração das Permissões


@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthFilter jwtAuthFilter;
private final UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> [Link]()) // REST APIs não precisam de CSRF
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll() // login e registo: pú
blico
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated() // todo o resto: precisa de token
)
.sessionManagement(s -> [Link](STATELESS))
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter
.class)
.build();

Java & Spring Boot — Do Zero ao Full-Stack Pág. 18


}
}

Java & Spring Boot — Do Zero ao Full-Stack Pág. 19


Projecto 3 — API Completa

Registo e Login de Utilizadores


@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
@PostMapping("/registar")
public ResponseEntity<AuthRespostaDTO> registar(@RequestBody @Valid RegistoD
TO dto) {
return [Link](201).body([Link](dto));
}
@PostMapping("/login")
public ResponseEntity<AuthRespostaDTO> login(@RequestBody @Valid LoginDTO dt
o) {
return [Link]([Link](dto));
}
}
// [Link]
@Service
@RequiredArgsConstructor
public class AuthService {
private final UtilizadorRepository repo;
private final PasswordEncoder encoder;
private final JwtService jwtService;
private final AuthenticationManager authManager;
public AuthRespostaDTO registar(RegistoDTO dto) {
if ([Link]([Link]()))
throw new EmailJaExisteException([Link]());
Utilizador u = new Utilizador(null, [Link](), [Link](),
[Link]([Link]()), [Link]
ER);
[Link](u);
String token = [Link](u);
return new AuthRespostaDTO(token, [Link](), [Link]());
}
public AuthRespostaDTO login(LoginDTO dto) {
[Link](
new UsernamePasswordAuthenticationToken([Link](), [Link]
ord()));
Utilizador u = [Link]([Link]()).orElseThrow();
return new AuthRespostaDTO([Link](u), [Link](), [Link]
mail());
}
}

Java & Spring Boot — Do Zero ao Full-Stack Pág. 20


Documentação com Swagger / OpenAPI
O Swagger gera automaticamente uma interface web interactiva para testar a API. Acedes em
[Link] após adicionar a dependência.
<!-- [Link] -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
// Anotações no Controller para documentação rica
@Operation(summary = "Criar produto",
description = "Cria um novo produto na base de dados")
@ApiResponse(responseCode = "201", description = "Produto criado com sucesso")
@ApiResponse(responseCode = "400", description = "Dados inválidos")
@PostMapping
public ResponseEntity<ProdutoRespostaDTO> criar(@RequestBody @Valid ProdutoCriac
aoDTO dto) {
return [Link](201).body([Link](dto));
}

Java & Spring Boot — Do Zero ao Full-Stack Pág. 21


Testes Automatizados

Unit Tests com JUnit 5 e Mockito


Testa a lógica do Service isoladamente, sem base de dados nem contexto Spring. Mockito simula as
dependências (equivalente ao [Link]() do Angular).
@ExtendWith([Link]) // Activa o Mockito no JUnit
class TarefaServiceTest {
@Mock
private TarefaRepository repositorio; // simulado — não vai à BD
@InjectMocks
private TarefaService servico; // instância real com mock injectado
@Test
@DisplayName("Deve lançar excepção quando tarefa não existe")
void buscarPorId_NaoExiste_LancaExcepcao() {
// Arrange
when([Link](99L)).thenReturn([Link]());
// Act & Assert
assertThrows([Link],
() -> [Link](99L));
}
@Test
@DisplayName("Deve criar tarefa e guardar na BD")
void criar_DadosValidos_RetornaTarefa() {
// Arrange
Tarefa entrada = new Tarefa(null, "Aprender Spring", null, false, null);
Tarefa esperada = new Tarefa(1L, "Aprender Spring", null, false, null);
when([Link](entrada)).thenReturn(esperada);
// Act
Tarefa resultado = [Link](entrada);
// Assert
assertNotNull([Link]());
assertEquals("Aprender Spring", [Link]());
verify(repositorio, times(1)).save(entrada);
}
}

Testes de Controller com MockMvc


@WebMvcTest([Link]) // Carrega só o controller, não a BD
class TarefaControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private TarefaService servico;

Java & Spring Boot — Do Zero ao Full-Stack Pág. 22


@Test
void GET_tarefas_RetornaLista() throws Exception {
List<Tarefa> tarefas = [Link](new Tarefa(1L, "Tarefa 1", null, false, n
ull));
when([Link]()).thenReturn(tarefas);
[Link](get("/api/tarefas")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].titulo").value("Tarefa 1"));
}
}

Java & Spring Boot — Do Zero ao Full-Stack Pág. 23


Deploy e Produção

Docker — Containerizar a Aplicação


# Dockerfile — na raiz do projecto
FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY [Link] .
COPY src ./src
RUN ./mvnw package -DskipTests
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar [Link]
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "[Link]"]

[Link] — API + PostgreSQL


version: '3.8'
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: meubanco
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
api:
build: .
depends_on:
- postgres
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/meubanco
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
ports:
- "8080:8080"
volumes:
postgres_data:
# Comando para subir: docker-compose up -d

Java & Spring Boot — Do Zero ao Full-Stack Pág. 24


Deploy Gratuito no Railway
[Link] é a plataforma mais simples para fazer deploy de APIs Java Spring Boot. Suporta
deploy directo do GitHub, PostgreSQL gerido, e variáveis de ambiente seguras.

Passo Acção

1 Cria conta em [Link] e liga o teu GitHub

2 New Project → Deploy from GitHub Repo → selecciona o repositório

3 Add a service → Database → PostgreSQL (Railway cria automaticamente)

4 Em Variables, adiciona: JWT_SECRET, e as variáveis da BD geradas pelo Railway

5 Railway detecta o [Link] e faz o build automaticamente

6 Em Settings → Networking, gera um domínio público para a tua API

Java & Spring Boot — Do Zero ao Full-Stack Pág. 25


Próximos Passos no Merca
Trabalho

O Teu Roadmap para Full-Stack


Com os três projectos deste guia já tens as bases para entrar no mercado como desenvolvedor
full-stack. Aqui estão os próximos passos ordenados por prioridade para aumentar a tua
empregabilidade.

Prioridade Tópico Para quê

■ Alta CORS Configuration Ligar o Angular ao Spring sem erros

■ Alta GitHub Portfolio 3 projectos no GitHub com README detalhado

■ Alta Postman Collections Documentar e testar as APIs que constróis

■ Média Redis Cache Caching para APIs de alta performance

■ Média Spring Actuator Monitorização e health checks

■ Média Logging com SLF4J Logs estruturados em produção

■ Média Exception personalizada Hierarquia de erros clara e consistente

■ Futura Microserviços Arquitectura distribuída — após 1 ano de experiência

■ Futura Kafka / RabbitMQ Mensageria assíncrona entre serviços

■ Futura Spring Cloud Service Discovery, API Gateway, etc.

■ Futura Kubernetes Orquestração de containers em escala

Configurar CORS para ligar ao Angular


@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
[Link]("/api/**")
.allowedOrigins(
"[Link] // Angular em desenvolvimento
"[Link] // produção

Java & Spring Boot — Do Zero ao Full-Stack Pág. 26


)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}

Resumo Final — O que sabes agora fazer


■ Competência Usado no Mercado

Estruturar uma API REST com Spring Boot 100% dos projectos

Controller → Service → Repository (3 camadas) Padrão universal em empresas

CRUD completo com Spring Data JPA Em todos os backends

Relacionamentos @OneToMany / @ManyToMany Qualquer app com base de dados

Autenticação stateless com JWT Padrão gold standard de APIs

Validações com Bean Validation Qualidade e segurança de dados

Tratamento global de erros APIs profissionais e robustas

Documentação com Swagger/OpenAPI Colaboração com equipa e front-end

Testes unitários e de integração CI/CD e código de qualidade

Deploy com Docker + Railway Produto real em produção

■ PRÓXIMO PASSO CONCRETO Cria os 3 projectos deste guia, publica-os no GitHub com um
bom README (inclui screenshots do Swagger e instruções de como correr localmente), e
adiciona-os ao teu LinkedIn. Isso diferencia-te imediatamente da maioria dos candidatos que só
têm projectos front-end no portfolio.

Java & Spring Boot — Do Zero ao Full-Stack Pág. 27

Você também pode gostar