Eu passei os últimos anos programando em Node, TypeScript, PHP… aí do nada bateu aquela nostalgia do Spring Boot. Sabe quando você lembra de uma coisa que funcionava bem e você meio que abandonou sem motivo? Foi isso. Resolvi voltar pro básico e percebi que tinha esquecido praticamente tudo. E olha, tem muita gente que nunca mexeu direito com Spring Boot porque achou complicado demais ou porque ficou com medo do Java.

A real é que Spring Boot é simples. Mas tem tanta coisa acontecendo por baixo dos panos que quando você tá começando parece que tem magia demais rolando. Então vou fazer o seguinte: vou te mostrar o essencial, sem enrolação. O suficiente pra você subir uma API REST funcional e entender o que tá acontecendo.

O que você precisa saber antes

Spring Boot é um framework que facilita a criação de aplicações Java. Ele já vem com servidor embutido (Tomcat), já configura um monte de coisa automaticamente, e você consegue subir uma aplicação em minutos. É tipo o Express do Node, mas com esteroides e um sistema de injeção de dependência que realmente funciona.

Você vai precisar de Java instalado (qualquer versão 17+ tá ótima) e Maven ou Gradle pra gerenciar dependências. Eu prefiro Maven pela praticidade, e copiar configuração dos outros é sempre útil.

Criando o projeto

A forma mais fácil é usar o Spring Initializr: https://start.spring.io

Você escolhe:

  • Project: Maven
  • Language: Java
  • Spring Boot: 3.x (a versão mais recente estável)
  • Dependencies: Spring Web, Spring Data JPA, H2 Database

Clica em Generate, baixa o zip, descompacta. Pronto, você tem um projeto Spring Boot.

Ou se você quiser fazer na unha, cria um pom.xml básico e deixa o Maven baixar tudo. Mas sinceramente? Usa o Initializr. Não tem porque sofrer.

A estrutura que importa

Quando você abre o projeto, vai ver algo assim:

src/
  main/
    java/
      com.exemplo.projeto/
        ProjetoApplication.java
        controller/
        service/
        repository/
        model/
    resources/
      application.properties

Basicamente:

  • ProjetoApplication.java é o ponto de entrada. Tem a main e a annotation @SpringBootApplication.
  • controller/ é onde ficam seus endpoints REST
  • service/ é onde fica a lógica de negócio
  • repository/ é onde fica o acesso ao banco
  • model/ é onde ficam suas entidades
  • application.properties é onde você configura tudo (pode usar application.yaml também)

Simples. Sem firula.

O código que funciona

Vamos fazer um CRUD de produto. Nada muito elaborado, só o suficiente pra você entender o fluxo.

1. Model (Entidade)

Java
package com.example.demo.model;

import jakarta.persistence.*;

@Entity
@Table(name = "products")
public class Product {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private Double price;
    
    // Constructors
    public Product() {}
    
    public Product(String name, Double price) {
        this.name = name;
        this.price = price;
    }
    
    // Getters and Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public Double getPrice() { return price; }
    public void setPrice(Double price) { this.price = price; }
}

@Entity diz pro Spring que isso é uma tabela. @Id marca o campo de ID. @GeneratedValue diz que o ID é auto increment. Fim. O Spring cria a tabela sozinho.

2. Repository (Acesso ao banco)

Java
package com.example.demo.repository;

import com.example.demo.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
    
}

Olha isso. Você cria uma interface, estende JpaRepository, e automaticamente você tem métodos prontos: findAll(), findById(), save(), deleteById(). É isso. Não precisa implementar nada. O Spring cria tudo em tempo de execução.

3. Service (Lógica de negócio)

Java
package com.example.demo.service;

import com.example.demo.model.Product;
import com.example.demo.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class ProductService {
    
    @Autowired
    private ProductRepository repository;
    
    public List<Product> findAll() {
        return repository.findAll();
    }
    
    public Optional<Product> findById(Long id) {
        return repository.findById(id);
    }
    
    public Product save(Product product) {
        return repository.save(product);
    }
    
    public void delete(Long id) {
        repository.deleteById(id);
    }
}

@Service diz que isso é uma camada de serviço. @Autowired injeta o repository automaticamente. Você não precisa fazer new ProdutoRepository(). O Spring cuida disso.

4. Controller (Endpoints REST)

Java
package com.example.demo.controller;

import com.example.demo.model.Product;
import com.example.demo.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/products")
public class ProductController {
    
    @Autowired
    private ProductService service;
    
    @GetMapping
    public List<Product> list() {
        return service.findAll();
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<Product> get(@PathVariable Long id) {
        return service.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
    
    @PostMapping
    public Product create(@RequestBody Product product) {
        return service.save(product);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<Product> update(@PathVariable Long id, @RequestBody Product product) {
        return service.findById(id)
            .map(p -> {
                product.setId(id);
                return ResponseEntity.ok(service.save(product));
            })
            .orElse(ResponseEntity.notFound().build());
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable Long id) {
        service.delete(id);
        return ResponseEntity.noContent().build();
    }
}

@RestController transforma isso num controller REST. @RequestMapping define a rota base. As annotations @GetMapping, @PostMapping, etc, definem os verbos HTTP. @PathVariable pega variáveis da URL. @RequestBody pega o JSON do corpo da requisição.

Tudo isso funciona automaticamente. O Spring converte JSON pra objeto, objeto pra JSON, sem você precisar fazer nada.

Configuração do banco (H2)

No application.properties:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true

H2 é um banco em memória. Perfeito pra desenvolvimento. Você sobe a aplicação, usa, desliga, e os dados somem. Pra produção você troca pra PostgreSQL ou MySQL, mas a lógica é a mesma.

Rodando a aplicação

Zsh
mvn spring-boot:run

Ou se você tiver uma IDE tipo IntelliJ ou Eclipse, só clica em Run na classe principal (ProjetoApplication.java).

A aplicação sobe em http://localhost:8080 por padrão. Você pode testar com curl ou Postman:

Zsh
curl -X POST http://localhost:8080/api/products \
  -H "Content-Type: application/json" \
  -d '{"name":"Notebook","price":3000.00}'

curl http://localhost:8080/api/products

curl http://localhost:8080/api/products/1

O que tá acontecendo de verdade

Quando você sobe a aplicação, o Spring:

  1. Escaneia todas as classes com annotations (@Component, @Service, @Repository, @Controller)
  2. Cria instâncias de todas elas
  3. Injeta as dependências onde tem @Autowired
  4. Sobe o servidor Tomcat embutido
  5. Configura as rotas baseado nas annotations
  6. Fica esperando requisições

Quando chega uma requisição:

  1. O Spring identifica qual controller atende aquela rota
  2. Converte o JSON do body em objeto Java (se tiver)
  3. Chama o método do controller
  4. O controller chama o service
  5. O service chama o repository
  6. O repository executa a query no banco
  7. Tudo volta na ordem inversa
  8. O Spring converte o objeto Java em JSON
  9. Retorna a resposta

Parece muita coisa, mas acontece em milissegundos. E você não precisa se preocupar com nada disso. Só escreve o código que o Spring cuida do resto.

No fim das contas

Spring Boot não é difícil. É só diferente. Tem aquela curva de aprendizado no começo porque você precisa entender como as annotations funcionam e como a injeção de dependência trabalha. Mas depois que você pega o jeito, é produtivo pra caramba.

E olha, eu ainda uso Node no dia a dia. Mas pra projetos maiores, onde você precisa de estrutura e manutenibilidade, Spring Boot ainda é uma escolha sólida em 2025. O Java moderno (17+) não é mais aquele Java verboso de antigamente. Tá bem gostoso de escrever.

Se você nunca mexeu ou tá enferrujado igual eu tava, pega esse código, sobe um projeto, e vai testando. Você vai ver que não é bicho de sete cabeças. É só questão de prática.