Curso de Spring Boot

Cuando las aplicaciones crecen, el código puede volverse difícil de mantener.

Por eso es importante organizar bien el proyecto desde el principio.

En este capítulo aprenderemos:

  • la arquitectura por capas
  • cómo organizar paquetes
  • qué es un Controller
  • qué es un Service
  • qué es un Repository
  • qué son los DTO

Esta arquitectura es la más usada en proyectos Spring Boot profesionales.


4.1 Arquitectura por capas

La arquitectura más común en Spring Boot es la arquitectura en capas.

El flujo típico de una aplicación es:

Cliente
   ↓
Controller
   ↓
Service
   ↓
Repository
   ↓
Base de datos

Cada capa tiene una responsabilidad diferente.


4.2 Estructura recomendada de paquetes

Una estructura típica es esta:

com.example.app

controller
service
repository
entity
dto
config

Ejemplo completo:

src/main/java/com/example/app

controller
   UserController.java

service
   UserService.java

repository
   UserRepository.java

entity
   User.java

dto
   UserDTO.java

Esta organización hace el código mucho más claro.


4.3 Controller

El Controller recibe las peticiones HTTP.

Por ejemplo:

GET /users
POST /users
DELETE /users

El controller no debe contener lógica compleja.

Su función es:

  • recibir peticiones
  • llamar al service
  • devolver respuesta

Ejemplo

1@RestController
2@RequestMapping("/users")
3public class UserController {
4
5    private final UserService service;
6
7    public UserController(UserService service) {
8        this.service = service;
9    }
10
11    @GetMapping
12    public List<User> getUsers() {
13        return service.getAllUsers();
14    }
15
16}

El controller simplemente llama al service.


4.4 Service

La capa Service contiene la lógica de negocio.

Ejemplos de lógica de negocio:

  • validar datos
  • aplicar reglas
  • procesar información
  • coordinar repositorios

Ejemplo

1@Service
2public class UserService {
3
4    private final UserRepository repository;
5
6    public UserService(UserRepository repository) {
7        this.repository = repository;
8    }
9
10    public List<User> getAllUsers() {
11        return repository.findAll();
12    }
13
14}

El service utiliza el repository para acceder a la base de datos.


4.5 Repository

El Repository se encarga de acceder a la base de datos.

En Spring Boot normalmente usamos Spring Data JPA.

Ejemplo:

1@Repository
2public interface UserRepository extends JpaRepository<User, Long> {
3
4}

Esto automáticamente genera:

findAll()
findById()
save()
delete()

Sin escribir código.


4.6 Entity

Una Entity representa una tabla de la base de datos.

Ejemplo:

Tabla:

users

Entidad:

1@Entity
2public class User {
3
4    @Id
5    @GeneratedValue
6    private Long id;
7
8    private String name;
9
10    private String email;
11
12}

Cada objeto corresponde a un registro de la tabla.


4.7 DTO (Data Transfer Object)

Un DTO es un objeto que se usa para transferir datos entre capas.

Se utiliza para evitar enviar entidades directamente.


Por qué no devolver entidades

Si devolvemos entidades:

  • podemos exponer datos sensibles
  • podemos generar problemas de rendimiento
  • podemos acoplar la API a la base de datos

Por eso se usan DTOs.


Ejemplo DTO

1public class UserDTO {
2
3    private Long id;
4    private String name;
5
6}

Este DTO no incluye el email.


4.8 Flujo completo de una petición

Supongamos esta petición:

GET /users

El flujo sería:

Cliente
   ↓
UserController
   ↓
UserService
   ↓
UserRepository
   ↓
Base de datos

Después vuelve la respuesta.


4.9 Ejemplo completo

Entity

1@Entity
2public class User {
3
4    @Id
5    @GeneratedValue
6    private Long id;
7
8    private String name;
9
10}

Repository

1@Repository
2public interface UserRepository extends JpaRepository<User, Long> {
3
4}

Service

1@Service
2public class UserService {
3
4    private final UserRepository repository;
5
6    public UserService(UserRepository repository) {
7        this.repository = repository;
8    }
9
10    public List<User> getUsers() {
11        return repository.findAll();
12    }
13
14}

Controller

1@RestController
2@RequestMapping("/users")
3public class UserController {
4
5    private final UserService service;
6
7    public UserController(UserService service) {
8        this.service = service;
9    }
10
11    @GetMapping
12    public List<User> getUsers() {
13        return service.getUsers();
14    }
15
16}

4.10 Ventajas de esta arquitectura

Esta arquitectura tiene muchas ventajas.

Código más organizado

Cada clase tiene una función clara.


Más fácil de mantener

Podemos modificar una capa sin afectar a otras.


Más fácil de probar

Podemos probar services sin controllers.


Más fácil de escalar

Las aplicaciones grandes siguen esta estructura.


4.11 Buenas prácticas

Algunas recomendaciones importantes.


Controller ligero

El controller debe ser simple.

❌ Incorrecto:

controller con lógica compleja

✔ Correcto:

controller llama al service

Service con lógica

La lógica de negocio debe estar en el service.


Repository solo para datos

El repository solo accede a la base de datos.


Usar DTOs

Evita devolver entidades directamente.

  • Loading...