Spring Boot

Spring Boot ha revolucionado el desarrollo de aplicaciones Java empresariales, simplificando la configuración y permitiendo a los desarrolladores concentrarse en la lógica de negocio en lugar de la configuración compleja. En esta guía completa, aprenderás todo lo necesario para crear tu primera aplicación Spring Boot.

¿Qué es Spring Boot?

Spring Boot es un framework que facilita la creación de aplicaciones Spring independientes y listas para producción. Proporciona una configuración automática inteligente, servidores embebidos y una amplia gama de "starters" que simplifican la gestión de dependencias.

Ventajas de Spring Boot

  • Configuración automática: Configura automáticamente tu aplicación basándose en las dependencias que agregues
  • Servidores embebidos: Incluye Tomcat, Jetty o Undertow directamente
  • Starters: Dependencias preconfiguradas para diferentes tecnologías
  • Production-ready: Métricas, health checks y monitoreo incluidos
  • Sin código XML: Configuración basada en anotaciones y Java

Configuración del Entorno de Desarrollo

Prerequisitos

  • Java JDK 11 o superior
  • IDE (IntelliJ IDEA, Eclipse, o Visual Studio Code)
  • Maven o Gradle

Creando tu Primer Proyecto

La forma más fácil de comenzar es usar Spring Initializr (start.spring.io):

Configuración del proyecto:
- Project: Maven Project
- Language: Java  
- Spring Boot: 3.1.2
- Group: com.simitvespi
- Artifact: mi-primera-app
- Name: mi-primera-app
- Package name: com.simitvespi.miprimeraapp
- Packaging: Jar
- Java: 17

Dependencies:
- Spring Web
- Spring Data JPA
- H2 Database

Estructura del Proyecto

Un proyecto Spring Boot típico tiene la siguiente estructura:

mi-primera-app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/simitvespi/miprimeraapp/
│   │   │       └── MiPrimeraAppApplication.java
│   │   └── resources/
│   │       ├── application.properties
│   │       ├── static/
│   │       └── templates/
│   └── test/
├── pom.xml
└── README.md

Tu Primera Aplicación

Clase Principal

La clase principal es el punto de entrada de tu aplicación:

@SpringBootApplication
public class MiPrimeraAppApplication {
    public static void main(String[] args) {
        SpringApplication.run(MiPrimeraAppApplication.class, args);
    }
}

Primer Controlador

Crea tu primer controlador REST:

@RestController
public class HolaMundoController {
    
    @GetMapping("/")
    public String holaMundo() {
        return "¡Hola Mundo desde Spring Boot!";
    }
    
    @GetMapping("/saludo/{nombre}")
    public String saludar(@PathVariable String nombre) {
        return "¡Hola " + nombre + "!";
    }
    
    @GetMapping("/info")
    public Map<String, Object> informacion() {
        Map<String, Object> info = new HashMap<>();
        info.put("aplicacion", "Mi Primera App Spring Boot");
        info.put("version", "1.0.0");
        info.put("autor", "SimiTvespi");
        return info;
    }
}

Configuración de la Aplicación

application.properties

Configura tu aplicación usando el archivo application.properties:

# Configuración del servidor
server.port=8080
server.servlet.context-path=/api

# Configuración de la base de datos
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password

# Configuración JPA
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true

# Habilitar consola H2
spring.h2.console.enabled=true

Trabajando con Bases de Datos

Entidad JPA

Crea tu primera entidad:

@Entity
@Table(name = "usuarios")
public class Usuario {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, unique = true)
    private String email;
    
    @Column(nullable = false)
    private String nombre;
    
    private int edad;
    
    // Constructores
    public Usuario() {}
    
    public Usuario(String email, String nombre, int edad) {
        this.email = email;
        this.nombre = nombre;
        this.edad = edad;
    }
    
    // Getters y Setters
    // ... métodos getter y setter
}

Repository

Crea un repository para acceder a los datos:

@Repository
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {
    
    Optional<Usuario> findByEmail(String email);
    
    List<Usuario> findByEdadGreaterThan(int edad);
    
    @Query("SELECT u FROM Usuario u WHERE u.nombre LIKE %?1%")
    List<Usuario> buscarPorNombre(String nombre);
}

Service

Implementa la lógica de negocio en una capa de servicio:

@Service
@Transactional
public class UsuarioService {
    
    private final UsuarioRepository usuarioRepository;
    
    public UsuarioService(UsuarioRepository usuarioRepository) {
        this.usuarioRepository = usuarioRepository;
    }
    
    public Usuario crearUsuario(Usuario usuario) {
        // Validaciones
        if (usuarioRepository.findByEmail(usuario.getEmail()).isPresent()) {
            throw new IllegalArgumentException("Email ya existe");
        }
        return usuarioRepository.save(usuario);
    }
    
    public List<Usuario> obtenerTodos() {
        return usuarioRepository.findAll();
    }
    
    public Optional<Usuario> buscarPorId(Long id) {
        return usuarioRepository.findById(id);
    }
    
    public Usuario actualizar(Long id, Usuario usuarioActualizado) {
        return usuarioRepository.findById(id)
            .map(usuario -> {
                usuario.setNombre(usuarioActualizado.getNombre());
                usuario.setEdad(usuarioActualizado.getEdad());
                return usuarioRepository.save(usuario);
            })
            .orElseThrow(() -> new RuntimeException("Usuario no encontrado"));
    }
    
    public void eliminar(Long id) {
        usuarioRepository.deleteById(id);
    }
}

API REST Completa

Controlador CRUD

Crea un controlador completo para operaciones CRUD:

@RestController
@RequestMapping("/api/usuarios")
public class UsuarioController {
    
    private final UsuarioService usuarioService;
    
    public UsuarioController(UsuarioService usuarioService) {
        this.usuarioService = usuarioService;
    }
    
    @GetMapping
    public ResponseEntity<List<Usuario>> obtenerTodos() {
        List<Usuario> usuarios = usuarioService.obtenerTodos();
        return ResponseEntity.ok(usuarios);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<Usuario> obtenerPorId(@PathVariable Long id) {
        return usuarioService.buscarPorId(id)
            .map(usuario -> ResponseEntity.ok(usuario))
            .orElse(ResponseEntity.notFound().build());
    }
    
    @PostMapping
    public ResponseEntity<Usuario> crear(@Valid @RequestBody Usuario usuario) {
        Usuario nuevoUsuario = usuarioService.crearUsuario(usuario);
        return ResponseEntity.status(HttpStatus.CREATED).body(nuevoUsuario);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<Usuario> actualizar(
            @PathVariable Long id, 
            @Valid @RequestBody Usuario usuario) {
        try {
            Usuario usuarioActualizado = usuarioService.actualizar(id, usuario);
            return ResponseEntity.ok(usuarioActualizado);
        } catch (RuntimeException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> eliminar(@PathVariable Long id) {
        usuarioService.eliminar(id);
        return ResponseEntity.noContent().build();
    }
}

Manejo de Errores

Exception Handler Global

Implementa un manejador global de excepciones:

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Map<String, String>> manejarArgumentoIlegal(
            IllegalArgumentException ex) {
        Map<String, String> error = new HashMap<>();
        error.put("error", "Argumento inválido");
        error.put("mensaje", ex.getMessage());
        return ResponseEntity.badRequest().body(error);
    }
    
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Map<String, String>> manejarRuntimeException(
            RuntimeException ex) {
        Map<String, String> error = new HashMap<>();
        error.put("error", "Error interno");
        error.put("mensaje", ex.getMessage());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }
}

Testing en Spring Boot

Test de Integración

Crea tests para tu aplicación:

@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class UsuarioServiceTest {
    
    @Autowired
    private UsuarioService usuarioService;
    
    @Test
    public void testCrearUsuario() {
        // Given
        Usuario usuario = new Usuario("[email protected]", "Test User", 25);
        
        // When
        Usuario resultado = usuarioService.crearUsuario(usuario);
        
        // Then
        assertNotNull(resultado.getId());
        assertEquals("[email protected]", resultado.getEmail());
    }
    
    @Test
    public void testEmailDuplicado() {
        // Given
        Usuario usuario1 = new Usuario("[email protected]", "User 1", 25);
        Usuario usuario2 = new Usuario("[email protected]", "User 2", 30);
        
        usuarioService.crearUsuario(usuario1);
        
        // When & Then
        assertThrows(IllegalArgumentException.class, () -> {
            usuarioService.crearUsuario(usuario2);
        });
    }
}

Configuración Avanzada

Profiles

Usa profiles para diferentes entornos:

# application-development.properties
spring.datasource.url=jdbc:h2:mem:devdb
spring.jpa.show-sql=true
logging.level.com.simitvespi=DEBUG

# application-production.properties  
spring.datasource.url=jdbc:postgresql://localhost:5432/proddb
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
spring.jpa.show-sql=false

Actuator

Habilita Spring Boot Actuator para monitoreo:

# En pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

# En application.properties
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always

Mejores Prácticas

Estructura del Código

  • Usa una arquitectura en capas (Controller, Service, Repository)
  • Implementa inyección de dependencias por constructor
  • Usa DTOs para transferencia de datos
  • Valida datos de entrada con Bean Validation

Configuración

  • Usa profiles para diferentes entornos
  • Externaliza configuraciones sensibles
  • Implementa health checks
  • Configura logging apropiadamente

Seguridad

  • Nunca hardcodees credenciales
  • Usa HTTPS en producción
  • Implementa validación de entrada robusta
  • Maneja errores sin exponer información sensible

Próximos Pasos

Una vez que domines los conceptos básicos de Spring Boot, puedes explorar:

  • Spring Security: Para autenticación y autorización
  • Spring Cloud: Para microservicios
  • Spring Data: Para acceso a datos avanzado
  • Spring WebFlux: Para programación reactiva
  • Containerización: Docker y Kubernetes

Conclusión

Spring Boot ha simplificado enormemente el desarrollo de aplicaciones Java empresariales. Con su configuración automática, starters predefinidos y herramientas de desarrollo integradas, permite a los desarrolladores crear aplicaciones robustas y escalables en tiempo record.

Esta guía te ha proporcionado las bases necesarias para comenzar tu viaje con Spring Boot. La práctica constante y la construcción de proyectos reales te ayudarán a dominar este poderoso framework.

¿Quieres Profundizar en Spring Boot?

Nuestros cursos especializados te llevarán desde principiante hasta experto en Spring Boot con proyectos reales y mentorías personalizadas.

Comenzar Ahora