Capítulo 2: Estructura de un Proyecto Spring Boot
Introducción
Un proyecto Spring Boot sigue una estructura estandarizada basada en las convenciones de Maven. Esta organización facilita la navegación en el código y permite a los desarrolladores encontrar rápidamente los archivos necesarios.
Objetivos del Capítulo
Al finalizar este capítulo, usted será capaz de:
- Comprender la organización de los directorios de un proyecto Spring Boot
- Identificar el rol de cada archivo importante
- Organizar su código según las buenas prácticas
- Navegar eficazmente en un proyecto Spring Boot
Vista General de la Estructura
Árbol Completo
greeting-app/
├── .mvn/ # Maven Wrapper
│ └── wrapper/
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── src/
│ ├── main/
│ │ ├── java/ # Código fuente Java
│ │ │ └── com/example/greeting/
│ │ │ └── GreetingApplication.java
│ │ └── resources/ # Recursos de la aplicación
│ │ ├── static/ # Archivos estáticos (CSS, JS, imágenes)
│ │ ├── templates/ # Plantillas (Thymeleaf, Freemarker)
│ │ ├── application.properties # Configuración principal
│ │ └── application.yml # Configuración YAML (alternativa)
│ └── test/
│ ├── java/ # Tests unitarios y de integración
│ │ └── com/example/greeting/
│ │ └── GreetingApplicationTests.java
│ └── resources/ # Recursos de test
│ └── application-test.properties
├── target/ # Archivos compilados (generado)
├── .gitignore # Archivos a ignorar por Git
├── mvnw # Maven wrapper (Unix/macOS)
├── mvnw.cmd # Maven wrapper (Windows)
├── pom.xml # Configuración Maven
├── HELP.md # Documentación generada
└── README.md # Documentación del proyecto
Directorio Raíz
1. Archivo pom.xml
Rol: Archivo de configuración Maven (Project Object Model)
Contenido principal:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Parent Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<!-- Identifiants du projet -->
<groupId>com.example</groupId>
<artifactId>greeting</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>greeting</name>
<description>Application de salutation</description>
<!-- Propriétés -->
<properties>
<java.version>17</java.version>
</properties>
<!-- Dépendances -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Plugin de build -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Secciones importantes:
| Sección | Descripción |
|---|---|
<parent> | Hereda la configuración de Spring Boot |
<groupId>, <artifactId>, <version> | Coordenadas Maven del proyecto |
<properties> | Configuración global (versión de Java, codificación, etc.) |
<dependencies> | Lista de dependencias del proyecto |
<build> | Configuración del proceso de build |
2. Maven Wrapper (mvnw, mvnw.cmd)
Rol: Permite ejecutar Maven sin instalarlo globalmente
Ventajas:
- Versión de Maven garantizada para todos los desarrolladores
- No es necesario instalar Maven manualmente
- Scripts incluidos en el proyecto
Uso:
Linux/macOS:
./mvnw clean install
./mvnw spring-boot:run
Windows:
mvnw.cmd clean install
mvnw.cmd spring-boot:run
3. Archivo .gitignore
Rol: Lista de archivos que no se deben versionar con Git
Contenido típico:
# Fichiers compilés
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# IDE
.idea/
*.iml
.vscode/
.classpath
.project
.settings/
# Système
.DS_Store
Thumbs.db
# Logs
*.log
# Fichiers temporaires
*.tmp
*.bak
Directorio src/main/java
Estructura de los Packages
Convención: Organizar el código en capas funcionales
src/main/java/com/example/greeting/
├── GreetingApplication.java # Clase principal
├── controller/ # Controladores REST/MVC
│ ├── GreetingController.java
│ └── UserController.java
├── service/ # Lógica de negocio
│ ├── GreetingService.java
│ └── UserService.java
├── repository/ # Acceso a datos
│ ├── UserRepository.java
│ └── ProductRepository.java
├── model/ # Entidades y DTOs
│ ├── entity/
│ │ ├── User.java
│ │ └── Product.java
│ └── dto/
│ ├── UserDTO.java
│ └── ProductDTO.java
├── config/ # Configuración de Spring
│ ├── SecurityConfig.java
│ └── DatabaseConfig.java
├── exception/ # Gestión de errores
│ ├── ResourceNotFoundException.java
│ └── GlobalExceptionHandler.java
└── util/ # Clases utilitarias
└── DateUtil.java
Arquitectura en Capas
Responsabilidades de cada capa:
| Capa | Rol | Anotaciones |
|---|---|---|
| Controller | Gestión de las solicitudes HTTP | @RestController, @Controller |
| Service | Lógica de negocio | @Service |
| Repository | Acceso a datos | @Repository, interfaz JPA |
| Model | Representación de los datos | @Entity, POJO |
Clase Principal: GreetingApplication.java
Contenido:
package com.example.greeting;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GreetingApplication {
public static void main(String[] args) {
SpringApplication.run(GreetingApplication.class, args);
}
}
Anotación @SpringBootApplication:
Esta anotación es un atajo que combina tres anotaciones:
@SpringBootApplication
=
@SpringBootConfiguration // Configuración de Spring
+ @EnableAutoConfiguration // Auto-configuración
+ @ComponentScan // Escaneo de componentes
Rol de cada anotación:
Directorio src/main/resources
Vista General
src/main/resources/
├── static/ # Archivos estáticos
│ ├── css/
│ │ └── style.css
│ ├── js/
│ │ └── script.js
│ └── images/
│ └── logo.png
├── templates/ # Plantillas (Thymeleaf)
│ ├── index.html
│ └── user.html
├── application.properties # Configuración principal
├── application-dev.properties # Configuración desarrollo
├── application-prod.properties # Configuración producción
├── application.yml # Configuración YAML (alternativa)
├── banner.txt # Banner personalizado al inicio
└── data.sql # Script SQL de inicialización
1. Directorio static/
Rol: Contiene los archivos estáticos servidos directamente
Tipos de archivos:
- CSS (hojas de estilo)
- JavaScript (scripts del lado del cliente)
- Imágenes (PNG, JPG, SVG)
- Fonts (tipografías personalizadas)
Acceso:
http://localhost:8080/css/style.css
http://localhost:8080/js/script.js
http://localhost:8080/images/logo.png
Estructura recomendada:
static/
├── css/
├── js/
├── images/
├── fonts/
└── favicon.ico
2. Directorio templates/
Rol: Contiene las plantillas de vistas (si utiliza un motor de plantillas)
Motores de plantillas soportados:
- Thymeleaf (recomendado)
- Freemarker
- Mustache
- Groovy Templates
Ejemplo Thymeleaf:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Greeting</title>
</head>
<body>
<h1 th:text="${message}">Default message</h1>
</body>
</html>
3. Archivo application.properties
Rol: Configuración principal de la aplicación
Formato: clave=valor
Ejemplos de configuraciones:
# Puerto del servidor
server.port=8080
# Nombre de la aplicación
spring.application.name=greeting-app
# Configuración de la base de datos
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=postgres
spring.datasource.password=secret
# JPA/Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
# Logs
logging.level.root=INFO
logging.level.com.example=DEBUG
# Formato de fechas
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=America/Montreal
4. Archivo application.yml (Alternativa)
Rol: Igual que application.properties pero en formato YAML
Formato: Jerárquico con indentación
Ejemplo equivalente:
server:
port: 8080
spring:
application:
name: greeting-app
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: postgres
password: secret
jpa:
hibernate:
ddl-auto: update
show-sql: true
logging:
level:
root: INFO
com.example: DEBUG
Comparación:
| Formato | Ventajas | Desventajas |
|---|---|---|
| properties | Simple, familiar | Repetitivo para estructuras complejas |
| yml | Legible, jerárquico | Sensible a la indentación |
5. Perfiles de Configuración
Concepto: Configuraciones diferentes según el entorno
Archivos de perfiles:
application.properties # Configuración por defecto
application-dev.properties # Desarrollo
application-test.properties # Tests
application-prod.properties # Producción
Activación de un perfil:
Vía application.properties:
spring.profiles.active=dev
Vía línea de comandos:
java -jar app.jar --spring.profiles.active=prod
Vía variable de entorno:
export SPRING_PROFILES_ACTIVE=prod
Ejemplo de configuración por entorno:
application-dev.properties:
server.port=8080
spring.datasource.url=jdbc:h2:mem:testdb
logging.level.root=DEBUG
application-prod.properties:
server.port=80
spring.datasource.url=jdbc:postgresql://prod-server:5432/mydb
logging.level.root=WARN
Directorio src/test/java
Estructura de los Tests
src/test/java/com/example/greeting/
├── GreetingApplicationTests.java # Test de arranque
├── controller/
│ └── GreetingControllerTest.java # Tests del controlador
├── service/
│ └── GreetingServiceTest.java # Tests del servicio
└── repository/
└── UserRepositoryTest.java # Tests del repository
Test de Arranque por Defecto
package com.example.greeting;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class GreetingApplicationTests {
@Test
void contextLoads() {
// Vérifie que le contexte Spring se charge correctement
}
}
Rol: Verificar que la aplicación arranca sin errores
Directorio target/
Rol: Contiene los archivos compilados y el JAR final
Generado por: Maven durante el build
Contenido:
target/
├── classes/ # Clases compiladas (.class)
├── test-classes/ # Tests compilados
├── generated-sources/ # Fuentes generadas
├── maven-status/ # Estado de Maven
└── greeting-0.0.1-SNAPSHOT.jar # JAR ejecutable final
Importante: Este directorio es ignorado por Git (en .gitignore)
Limpieza:
mvn clean
Organización por Funcionalidad vs por Capa
Enfoque 1: Por Capa (Recomendado para proyectos pequeños)
com.example.greeting/
├── controller/
│ ├── UserController.java
│ └── ProductController.java
├── service/
│ ├── UserService.java
│ └── ProductService.java
├── repository/
│ ├── UserRepository.java
│ └── ProductRepository.java
└── model/
├── User.java
└── Product.java
Ventajas:
- Simple y claro
- Fácil de entender para principiantes
- Estándar Spring Boot
Desventajas:
- Difícil de escalar para proyectos grandes
- Acoplamiento entre funcionalidades
Enfoque 2: Por Funcionalidad (Recomendado para proyectos grandes)
com.example.greeting/
├── user/
│ ├── UserController.java
│ ├── UserService.java
│ ├── UserRepository.java
│ └── User.java
├── product/
│ ├── ProductController.java
│ ├── ProductService.java
│ ├── ProductRepository.java
│ └── Product.java
└── order/
├── OrderController.java
├── OrderService.java
├── OrderRepository.java
└── Order.java
Ventajas:
- Alta cohesión
- Bajo acoplamiento
- Facilita la transición a una arquitectura de microservicios
Desventajas:
- Menos estándar
- Puede ser confuso al principio
Convenciones de Nomenclatura
Packages
Convención: Todo en minúsculas, palabras separadas por puntos
com.example.greeting // ✅ Bien
com.example.greeting.service // ✅ Bien
com.Example.Greeting // ❌ Mal (mayúsculas)
com.example.greeting_service // ❌ Mal (underscore)
Clases
Convención: PascalCase (primera letra de cada palabra en mayúscula)
UserController // ✅ Bien
GreetingService // ✅ Bien
userController // ❌ Mal (comienza con minúscula)
user_controller // ❌ Mal (underscore)
Sufijos recomendados:
| Tipo | Sufijo | Ejemplo |
|---|---|---|
| Controlador | Controller | UserController |
| Servicio | Service | UserService |
| Repository | Repository | UserRepository |
| Entidad | Ninguno | User, Product |
| DTO | DTO | UserDTO, CreateUserDTO |
| Excepción | Exception | ResourceNotFoundException |
| Configuración | Config | SecurityConfig |
Métodos
Convención: camelCase (primera letra minúscula)
getUserById() // ✅ Bien
findAllUsers() // ✅ Bien
GetUserById() // ❌ Mal (comienza con mayúscula)
get_user_by_id() // ❌ Mal (underscore)
Variables y Atributos
Convención: camelCase
String userName; // ✅ Bien
int userId; // ✅ Bien
String UserName; // ❌ Mal (comienza con mayúscula)
String user_name; // ❌ Mal (underscore)
Constantes
Convención: SCREAMING_SNAKE_CASE (todo en mayúsculas, underscores)
public static final int MAX_USERS = 100; // ✅ Bien
public static final String API_BASE_URL = "/api/v1"; // ✅ Bien
public static final int maxUsers = 100; // ❌ Mal (camelCase)
Ejercicios Prácticos
Ejercicio 1: Explorar la Estructura
Objetivo: Familiarizarse con la estructura de un proyecto
Instrucciones:
- Cree un proyecto con Spring Initializr (solo Spring Web)
- Importe el proyecto en VS Code
- Identifique:
- El archivo pom.xml
- La clase principal
- El archivo application.properties
- El directorio de tests
- Dibuje el árbol de directorios en papel
Ejercicio 2: Crear una Estructura de Packages
Objetivo: Organizar el código en capas
Instrucciones:
- En el proyecto anterior, cree la estructura:
com.example.demo/
├── controller/
├── service/
├── repository/
└── model/ - Cree clases vacías en cada package
- Verifique la compilación
Ejercicio 3: Configurar Perfiles
Objetivo: Crear configuraciones por entorno
Instrucciones:
- Cree
application-dev.properties:server.port=8080
logging.level.root=DEBUG - Cree
application-prod.properties:server.port=80
logging.level.root=WARN - Pruebe la activación de cada perfil
Preguntas de Repaso
-
¿Qué archivo contiene las dependencias de Maven?
-
¿Para qué sirve el directorio
target/? -
¿Cuál es la diferencia entre
static/ytemplates/? -
¿Qué contiene la anotación
@SpringBootApplication? -
¿Cómo nombrar un archivo de configuración para el entorno de desarrollo?
-
¿Cuál es la convención de nomenclatura para las clases de controlador?
-
¿Dónde coloca los archivos CSS y JavaScript?
-
¿Cuál es la diferencia entre
application.propertiesyapplication.yml?
Resumen del Capítulo
Puntos Clave
- La estructura Spring Boot sigue las convenciones de Maven
- El código fuente está en
src/main/java - Los recursos están en
src/main/resources - Organización en capas: Controller → Service → Repository
- Los tests están en
src/test/java - Los archivos de configuración utilizan perfiles
Buenas Prácticas
- Respetar las convenciones de nomenclatura de Java
- Organizar el código en packages lógicos
- Separar las configuraciones por entorno
- Utilizar sufijos descriptivos para las clases
- Comentar el código complejo
- Mantener una estructura clara y coherente
Próximos Pasos
En el siguiente capítulo profundizaremos en:
Capítulo 3: Configuración con application.properties
- Propiedades disponibles de Spring Boot
- Configuración de la base de datos
- Configuración de logs
- Propiedades personalizadas