Spring é o framework mais usado para construir aplicações backend em Java. Antes de tudo, vale entender uma distinção: o Spring Framework é a base; o Spring Boot é um framework construído sobre ele que facilita a criação de aplicações Spring-based, abstraindo configurações extensas e habilitando o modo "Just Run", você inicia o projeto e ele já está pronto e funcionando, sem configuração manual.
🎥 No vídeo: 00:30
A forma mais simples de começar é pelo Spring Initializr, uma ferramenta online que gera rapidamente um projeto Spring Boot pronto para baixar. No site você define:
- Gestor de dependências: Maven (usado no curso) ou Gradle.
- Versão do Spring Boot: prefira a versão estável marcada (no vídeo,
3.3.2). - Linguagem: Java (também é possível Kotlin ou Groovy).
- Group: o domínio do projeto/empresa (ex.:
com.kipper). Vira o pacote raiz dentro da estrutura. - Artifact: o nome do projeto (ex.:
first-spring-app).
Dependências adicionadas no vídeo:
- Spring Web: módulo para construir aplicações web, incluindo APIs RESTful.
- Spring Boot DevTools: ferramentas de desenvolvimento como Live Reload e fast restart.
- Lombok: biblioteca para gerar código boilerplate (getters, setters, construtores) com anotações.
📌 O
spring-boot-starter-testjá vem por padrão, mesmo sem você adicioná-lo.
Depois é só clicar em Generate, descompactar o .zip e abrir na IDE (no vídeo, IntelliJ).
./mvnw spring-boot:run # roda a aplicação🎥 No vídeo: 01:00
Entender as pastas evita o susto inicial:
pom.xml: arquivo do Maven onde ficam listadas as dependências (cada uma com sua versão)..mvn/: configurações do Maven; só é mexida em projetos mais avançados.src/main/java: onde fica a lógica da aplicação (suas classes).src/main/resources: arquivos de configuração (application.properties), templates, arquivos estáticos (CSS, JS) e scripts SQL (migrations).src/test/java: testes unitários. Já vem um teste padrão que só verifica se o contexto da aplicação carrega (contextLoads).
🎥 No vídeo: 05:30
Sempre tem o nome do projeto seguido do sufixo Application. É o ponto de entrada: chama SpringApplication.run, que carrega todo o contexto e inicializa o resto da aplicação. Assim como qualquer aplicação Java, parte de um public static void main.
@SpringBootApplication
public class FirstSpringAppApplication {
public static void main(String[] args) {
SpringApplication.run(FirstSpringAppApplication.class, args);
}
}A anotação @SpringBootApplication define a porta de entrada do Spring Boot e é, na verdade, uma combinação de três anotações:
| Anotação combinada | O que faz |
|---|---|
@Configuration |
indica que a classe pode definir beans |
@EnableAutoConfiguration |
ativa a autoconfiguração do Spring Boot (os defaults que ele aplica por você) |
@ComponentScan |
escaneia o pacote atrás de componentes, services, controllers e classes de configuração para gerenciá-los |
📌 Todo o Spring funciona em cima de anotações (os
@em cima de classes, métodos e parâmetros). Elas abstraem configurações que o Spring aplica por baixo dos panos, é um design pattern que se popularizou muito por causa do framework.
🎥 No vídeo: 09:00
A primeira classe a criar é um Controller, a classe que recebe requisições HTTP e monta as respostas. Marque-a com @RestController, que combina @Controller + @ResponseBody.
Por que @ResponseBody? Um @Controller puro poderia renderizar uma página HTML (modelo mais antigo, com front e back juntos). Como aqui construímos uma API REST que só devolve dados (JSON/XML) no corpo da resposta, usamos @RestController.
📌 Stateless vs stateful: APIs REST são stateless, o servidor não guarda o estado do cliente, então cada requisição precisa enviar tudo que a API precisa (ex.: um token de autenticação). Numa API stateful, o servidor mantém o estado de cada cliente entre requisições. A instrutora frisa: entenda o porquê, não só replique anotações.
@RestController
@RequestMapping("/hello-world")
public class HelloWorldController {
@GetMapping
public String helloWorld() {
return "Hello World";
}
}@RequestMapping("/hello-world")define o caminho base que esse controller escuta.@GetMappingmapeia o método para o verbo HTTP GET. Sem indicar o verbo, o Spring não sabe se o método responde a GET, POST, DELETE etc.
Ao executar a aplicação (botão Run no IntelliJ), o servidor embutido Tomcat sobe na porta 8080. Acessando http://localhost:8080/hello-world no navegador, você vê a string retornada. Um caminho inexistente devolve a página de erro genérica Whitelabel (404), que expõe a stack trace e idealmente deve ser tratada depois.
🎥 No vídeo: 13:00
No src/main/resources/application.properties ficam as configurações gerais da aplicação. Exemplo: trocar a porta padrão.
server.port=3000Valores podem ser fixos ou vir de variáveis de ambiente, com fallback:
spring.datasource.url=${DB_HOST:jdbc:postgresql://localhost:5432/meudb}
spring.datasource.username=${DB_USER:postgres}
spring.datasource.password=${DB_PASSWORD:senha}O Spring permite ter configurações diferentes por ambiente (produção, teste, dev). Crie arquivos como application-dev.properties e indique o ativo:
# application.properties
spring.profiles.active=${ACTIVE_PROFILE:dev}# application-dev.properties
server.port=8080Assim, com o profile dev ativo, a aplicação usa a porta 8080 definida no arquivo do perfil. O valor do profile também pode vir de variável de ambiente, com dev como fallback.
🎥 No vídeo: 25:00
A lógica de negócio (as regras definidas pelo time/produto) fica nas classes de Service. O Controller só recebe a requisição e delega o trabalho pesado ao Service.
@Service
public class HelloWorldService {
public String helloWorld(String name) {
return "Hello World " + name;
}
}A anotação @Service indica ao Spring que essa classe é gerenciada por ele. Assim, qualquer classe que precisar dela recebe a instância automaticamente, esse é o coração do Spring: o IoC Container cria e injeta os beans, você nunca dá new nele.
Há duas formas de injetar a dependência no Controller:
1. Injeção por construtor (recomendada):
@RestController
@RequestMapping("/hello-world")
public class HelloWorldController {
private final HelloWorldService helloWorldService;
public HelloWorldController(HelloWorldService helloWorldService) {
this.helloWorldService = helloWorldService;
}
@GetMapping
public String helloWorld() {
return helloWorldService.helloWorld("Kipper");
}
}2. Injeção por campo com @Autowired (mais curta e muito comum no código que você vai encontrar):
@Autowired
private HelloWorldService helloWorldService;📌 As duas funcionam. A injeção por construtor deixa as dependências explícitas, facilita testes e permite campos
final.
🎥 No vídeo: 31:00
O Spring gerencia automaticamente as classes suas (anotadas como component/service/controller). Mas às vezes você precisa que ele injete uma classe externa, de uma biblioteca de terceiros (ex.: SDK da AWS ou Oracle) ou uma implementação específica de uma interface. Nesses casos, use uma classe @Configuration com métodos anotados com @Bean:
@Configuration
public class HelloConfiguration {
@Bean
public S3Client s3Client() {
return S3Client.builder().build();
}
}O @Bean diz ao Spring para gerenciar o retorno do método como um bean. Ao escanear a classe @Configuration, o Spring monta um mapa: se alguém pedir uma dependência daquele tipo, ele sabe pegar dessa fábrica.
Outro uso clássico é escolher qual implementação de uma interface injetar (ex.: toda vez que pedirem Transporte, retornar um Carro).
📌 Escopo singleton: por padrão, o
@Beangera uma única instância reutilizada por todas as classes que a pedirem. Se você alterar o estado desse objeto em um lugar, todas veem a mesma instância. Esse comportamento pode ser alterado, mas é o padrão.
🎥 No vídeo: 36:00
Esses são os mecanismos mais importantes para construir APIs.
Usado em endpoints POST (criação de recursos), onde o cliente envia um JSON no corpo. O Spring injeta e mapeia o corpo para uma classe do seu domínio.
public class User {
private String name;
private String email;
// getters/setters/construtor gerados pelo Lombok
}Com o Lombok, dispense o boilerplate:
@Getter
@Setter
@AllArgsConstructor
public class User {
private String name;
private String email;
}No controller:
@PostMapping
public String helloWorldPost(@RequestBody User body) {
return "Hello World " + body.getName();
}Para extrair um valor do próprio caminho, ex.: /hello-world/{id}:
@PostMapping("/{id}")
public String helloWorldPost(@PathVariable String id, @RequestBody User body) {
return "Hello World " + body.getName() + " " + id;
}Para extrair os valores depois do ? na URL, ex.: ?filter=video:
@PostMapping
public String helloWorldPost(@RequestParam(value = "filter", defaultValue = "") String filter,
@RequestBody User body) {
return "Hello World " + filter;
}📌 Use
valuepara nomear o parâmetro mapeado edefaultValuepara um valor padrão quando ele não vier. Se chegar um query param com outro nome, o padrão é usado.
🎥 No vídeo: 42:00
| Anotação | Papel |
|---|---|
@RestController |
recebe requisições HTTP e devolve dados (JSON) |
@Service |
contém a lógica de negócio |
@Repository |
acesso a dados |
@Component |
bean genérico gerenciado pelo Spring |
@Configuration |
classe que define beans manualmente (@Bean) |
A organização em camadas separa responsabilidades:
Controller -> Service -> Repository -> Banco de dados
(HTTP) (regras) (persistência)
📌 Este tema é citado no vídeo como próximo passo (parte da formação/outros vídeos), não construído aqui. Fica como referência de fundamentos.
O JPA mapeia classes Java para tabelas do banco (ORM). O Spring Data elimina o código repetitivo de acesso a dados.
@Entity
@Table(name = "produtos")
public class Produto {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nome;
private double preco;
// getters e setters
}Basta estender JpaRepository e você ganha save, findById, findAll, delete etc. de graça:
public interface ProdutoRepository extends JpaRepository<Produto, Long> {
// queries derivadas do nome do método
List<Produto> findByNomeContaining(String nome);
List<Produto> findByPrecoGreaterThan(double preco);
}spring.datasource.url=jdbc:postgresql://localhost:5432/meudb
spring.datasource.username=postgres
spring.datasource.password=senha
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=trueEvite expor suas entidades diretamente na API. Use DTOs (Data Transfer Objects) para controlar o que entra e sai, geralmente como record:
public record ProdutoDTO(String nome, double preco) {}- Spring Boot abstrai o Spring Framework e configura o essencial automaticamente; comece pelo Spring Initializr (Maven, Spring Web, DevTools, Lombok).
- A classe principal usa
@SpringBootApplication=@Configuration+@EnableAutoConfiguration+@ComponentScan. @RestController(=@Controller+@ResponseBody) expõe uma API REST stateless;@RequestMapping+@GetMapping/@PostMappingmapeiam os endpoints.- O IoC Container cria e injeta os beans; prefira injeção por construtor, mas
@Autowiredtambém é comum. - Use
@Configuration+@Beanpara gerenciar classes externas (escopo singleton por padrão). - Receba dados com
@RequestBody,@PathVariablee@RequestParam(comvalue/defaultValue). - Configure a aplicação no
application.properties, incluindo profiles por ambiente. - Organize em camadas: Controller → Service → Repository.
Para temas além dos fundamentos (tratamento de exceções, Spring Security e migrations), veja o guia Conhecendo o framework Spring (
spring-advanced-guide.md).