Skip to content

Spring Boot

Estructura de Proyecto

La estructura de un proyecto Spring Boot debe seguir las siguientes convenciones:

Arquitectura repository pattern (tradicional)

El patrón de repositorio es un patrón de diseño que abstrae la capa de acceso a datos y permite trabajar con la lógica de negocio sin tener que preocuparse por los detalles de la persistencia de datos.

El patrón de repositorio se compone de tres partes principales:

  • Interfaz de repositorio: Define los métodos que se pueden utilizar para acceder a los datos.
  • Implementación de repositorio: Proporciona la implementación concreta de los métodos definidos en la interfaz de repositorio.
  • Entidades: Representan los objetos de dominio que se almacenan en la base de datos.
Terminal window
├── src
├── main
├── java
└── com
└── example
└── myproject
├── controller # Manejo de peticiones HTTP
├── model # Define las entidades y DTOs
├── repository # Gestiona el acceso a la base de datos
├── service # Implementa la lógica de negocio
└── MyProjectApplication.java
└── resources
├── application.properties
├── static
└── templates
└── test
├── java
└── com
└── example
└── myproject
└── MyProjectApplicationTests.java
└── resources
└── application.properties

Arquitectura por dominio

La arquitectura por dominio es un enfoque de diseño de software que organiza el código en torno a los conceptos del dominio del problema que se está resolviendo.

En una arquitectura por dominio, los objetos de dominio son el núcleo del sistema y representan los conceptos clave del problema que se está resolviendo. Estos objetos de dominio se utilizan para modelar la lógica de negocio y las reglas del sistema.

La arquitectura por dominio se compone de tres partes principales:

  • Entidades: Representan los objetos de dominio que se almacenan en la base de datos.
  • Servicios de dominio: Contienen la lógica de negocio y las reglas del sistema.
  • Repositorios: Abstraen la capa de acceso a datos y permiten trabajar con los objetos de dominio sin tener que preocuparse por los detalles de la persistencia de datos.
Terminal window
├── src
├── main
├── java
└── com
└── example
└── myproject
├── domain
├── model
└── service
├── infrastructure
└── repository
└── application
└── controller
└── resources
├── application.properties
├── static
└── templates
└── test
├── java
└── com
└── example
└── myproject
└── MyProjectApplicationTests.java
└── resources
└── application.properties

Buenas prácticas

Uso de Anotaciones

El uso de anotaciones es una característica clave de Spring Boot que permite configurar y personalizar la aplicación de forma declarativa.

Algunos ejemplos comunes de anotaciones en Spring Boot son:

Uso de anotaciones

  • @RestController: Anota una clase que define un controlador REST.
  • @RequestMapping: Anota un método de controlador para mapear una solicitud HTTP a un método de controlador.
  • @GetMapping: Anota un método de controlador para mapear una solicitud GET a un método de controlador.
  • @PostMapping: Anota un método de controlador para mapear una solicitud POST a un método de controlador.
  • @PutMapping: Anota un método de controlador para mapear una solicitud PUT a un método de controlador.
  • @DeleteMapping: Anota un método de controlador para mapear una solicitud DELETE a un método de controlador.
  • @RequestBody: Anota un parámetro de método de controlador que se vincula al cuerpo de la solicitud HTTP.
  • @RequestParam: Anota un parámetro de método de controlador que se vincula a un parámetro de solicitud HTTP.
  • @ExceptionHandler: Anota un método de controlador para manejar excepciones lanzadas por métodos de controlador.
  • @Service: Anota una clase que define un servicio.
  • @Repository: Anota una clase que define un repositorio.
  • @Component: Anota una clase genérica que se puede administrar automáticamente por Spring.

Rererencias:

Cómo Estructurar Controladores REST Efectivos

Utiliza las anotaciones específicas de Spring y organiza tus controladores por recursos.

@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
// Inyección por constructor (preferible a @Autowired en propiedades)
public UserController(UserService userService) {
this.userService = userService;
}
// GET específico con path variable
@GetMapping("/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
// POST para creación de recursos
@PostMapping
@ResponseStatus(HttpStatus.CREATED) // Mejor que hardcodear 201 en ResponseEntity
public UserDto createUser(@RequestBody @Valid UserDto userDto) {
return userService.create(userDto);
}
// Búsqueda con parámetros opcionales
@GetMapping
public List<UserDto> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
return userService.search(name, page, size);
}
// Manejo de excepción específica del recurso
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleUserNotFound(UserNotFoundException ex) {
return new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
}
}

Referencias:

Uso de propiedades

  • application.properties: Archivo de propiedades de configuración principal.
  • application-dev.properties: Archivo de propiedades de configuración para el entorno de desarrollo.
  • application-prod.properties: Archivo de propiedades de configuración para el entorno de producción.

Uso de record en vez de POJO

Los registros son una nueva característica de Java 14 que proporciona una forma concisa de definir clases de datos inmutables. Los registros son una alternativa más simple y legible a las clases de POJO (Plain Old Java Object) que se utilizan comúnmente para representar datos en una aplicación Java.

public record User(String name, int age) {}

En vez de todo el boilerplate de un POJO

public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

Es recomendable usar records en vez de POJOs para clases de datos inmutables. Por ejemplo un buen lugar donde usar seria al recibir datos de un request en un controlador.

@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
// Create user
return ResponseEntity.ok(user);
}
public record User(String name, int age) {}

Referencias: