MANUAL ETAPA 1 – Configuración Inicial API REST con
Spring Boot
Objetivo
Construir desde cero una API REST en Java (Spring Boot) para la gestión de productos, con conexión a base
de datos MySQL y soporte de validaciones con Jakarta.
Estructura Base del Proyecto
api-productos/
├── src/
│ └── main/
│ ├── java/
│ │ └── com/
│ │ └── espe/
│ │ └── api_productos/
│ │ ├── ApiProductosApplication.java
│ │ └── modelo/
│ │ └── Producto.java
│ └── resources/
│ ├── application.properties
│ └── ...
├── pom.xml
└── ...
Paso 1: Crear el proyecto Spring Boot
1. Ir a: https://start.spring.io
2. Configuración del generador:
o Project: Maven
o Language: Java
o Group: com.ejemplo
o Artifact: api-productos
o Name: api-productos
o Packaging: Jar
o Java: 17 o superior
3. Agregar las siguientes dependencias:
o Spring Web
o Spring Data JPA
o MySQL Driver
o Spring Boot DevTools
o Spring Boot Validation
o Springdoc OpenAPI (Swagger)
4. Descargar y descomprimir el proyecto.
5. Abrir la carpeta con VS Code.
Paso 2: Configurar application.properties
Ubicación: src/main/resources/application.properties
spring.application.name=api-productos
# Puerto del servidor
server.port=8080
# Configuración de MySQL
spring.datasource.url=jdbc:mysql://localhost:3306/productos_db?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
# JPA y Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
# Swagger OpenAPI
springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
Asegúrate de que la base de datos productos_db exista en MySQL y que el usuario y contraseña coincidan.
Paso 3: Crear la entidad Producto
Ubicación: src/main/java/com/espe/api_productos/model/Producto.java
package com.espe.api_productos.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;
@Entity
@Table(name = "productos")
public class Producto {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
private String nombre;
@NotNull
private Double precio;
@Min(0)
private Integer stock;
// Getters y setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getNombre() { return nombre; }
public void setNombre(String nombre) { this.nombre = nombre; }
public Double getPrecio() { return precio; }
public void setPrecio(Double precio) { this.precio = precio; }
public Integer getStock() { return stock; }
public void setStock(Integer stock) { this.stock = stock; }
}
Corrección Importante: Validaciones Jakarta
Si aparece el error: The import jakarta.validation cannot be resolved, se debe al faltante de dependencia.
Solución:
En pom.xml agregar:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Opcionalmente:
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.1.Final</version>
</dependency>
En la tarminal
mvn clean install
Ojo: Todas las dependencias del pom.xml se verían:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
Recomendación
Para evitar estos falsos positivos, asegúrate de tener esta dependencia exacta en tu pom.xml (versión más
reciente sugerida):
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>
PASO 4: Crear ProductoRepositorio
Objetivo
Crear una interfaz que extienda JpaRepository para facilitar las operaciones CRUD sobre la entidad Producto,
sin necesidad de escribir SQL manualmente.
Ubicación sugerida
src/main/java/com/espe/api_productos/repository/ProductoRepositorio.java
package com.espe.api_productos.repository;
import com.espe.api_productos.model.Producto;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductoRepositorio extends JpaRepository<Producto, Long> {
// Puedes agregar métodos personalizados aquí si los necesitas más adelante
}
PASO 5: Crear ProductoService y su implementación
Objetivo
Encapsular la lógica de negocio relacionada con los productos, delegando las operaciones al repositorio.
Estructura de carpetas sugerida
src/main/java/com/espe/api_productos/service/
├── ProductoService.java
└── ProductoServiceImpl.java
1. Interfaz ProductoService.java
package com.espe.api_productos.service;
import com.espe.api_productos.model.Producto;
import java.util.List;
import java.util.Optional;
public interface ProductoService {
List<Producto> listarTodos();
Optional<Producto> obtenerPorId(Long id);
Producto guardar(Producto producto);
void eliminar(Long id);
}
2. Implementación ProductoServiceImpl.java
package com.espe.api_productos.service;
import com.espe.api_productos.repository.ProductoRepositorio;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.espe.api_productos.model.Producto;
import java.util.List;
import java.util.Optional;
@Service
public class ProductoServiceImpl implements ProductoService {
@Autowired
private ProductoRepositorio productoRepositorio;
@Override
public List<Producto> listarTodos() {
return productoRepositorio.findAll();
}
@Override
public Optional<Producto> obtenerPorId(Long id) {
return productoRepositorio.findById(id);
}
@Override
public Producto guardar(Producto producto) {
return productoRepositorio.save(producto);
}
@Override
public void eliminar(Long id) {
productoRepositorio.deleteById(id);
}
}
PASO 6: Crear ProductoControlador
Objetivo
Exponer un conjunto de endpoints HTTP (GET, POST, PUT, DELETE) para realizar operaciones CRUD
sobre los productos.
Ubicación sugerida
src/main/java/com/espe/api_productos/controller/ProductoControlador.java
Código: ProductoControlador.java
package com.espe.api_productos.controller;
import com.espe.api_productos.model.Producto;
import com.espe.api_productos.service.ProductoService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.net.URI;
import java.util.List;
@RestController
@RequestMapping("/api/productos")
@CrossOrigin(origins = "*") // permite llamadas desde el frontend
public class ProductoControlador {
@Autowired
private ProductoService productoService;
// GET /api/productos
@GetMapping("/test")
public String test() {
return "Funciona";
}
@GetMapping
public List<Producto> listarTodos() {
return productoService.listarTodos();
}
// GET /api/productos/{id}
@GetMapping("/{id}")
public ResponseEntity<Producto> obtenerPorId(@PathVariable Long id) {
return productoService.obtenerPorId(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// POST /api/productos
@PostMapping
public ResponseEntity<Producto> crear(@Valid @RequestBody Producto producto) {
Producto creado = productoService.guardar(producto);
return ResponseEntity.created(URI.create("/api/productos/" + creado.getId())).body(creado);
}
// PUT /api/productos/{id}
@PutMapping("/{id}")
public ResponseEntity<Producto> actualizar(@PathVariable Long id, @Valid @RequestBody Producto
producto) {
return productoService.obtenerPorId(id)
.map(p -> {
p.setNombre(producto.getNombre());
p.setPrecio(producto.getPrecio());
p.setStock(producto.getStock());
return ResponseEntity.ok(productoService.guardar(p));
})
.orElse(ResponseEntity.notFound().build());
}
// DELETE /api/productos/{id}
@DeleteMapping("/{id}")
public ResponseEntity<Void> eliminar(@PathVariable Long id) {
if (productoService.obtenerPorId(id).isPresent()) {
productoService.eliminar(id);
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
}
Endpoints expuestos
Método Endpoint Descripción
GET /api/productos Listar todos los productos
GET /api/productos/{id} Obtener producto por ID
POST /api/productos Crear nuevo producto
PUT /api/productos/{id} Actualizar producto existente
DELETE /api/productos/{id} Eliminar producto
Notas
• Se usa @Valid para aplicar validaciones definidas en la entidad Producto.
• Se maneja respuesta HTTP apropiada: 200 OK, 201 Created, 204 No Content, 404 Not Found.
PASO 7: Swagger + Postman
Objetivo
• Documentar y probar los endpoints REST con una interfaz gráfica (Swagger).
• Verificar que la API está funcionando correctamente.
1. Configurar Swagger con Springdoc OpenAPI
Ya debes tener en el pom.xml la siguiente dependencia:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>
Si no la tienes, agrégala y ejecuta mvn clean install.
2. Personalizar Swagger (opcional)
Puedes personalizar el título y descripción con un archivo de configuración:
application.properties
# Swagger
springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
springdoc.swagger-ui.title=Documentación de API de Productos
3. Ejecutar el proyecto
En la terminal de VS Code:
mvn clean install
mvn spring-boot:run
Cuando el servidor esté en ejecución, abre en el navegador:
Swagger UI:
http://localhost:8080/swagger-ui.html
O, si estás usando la ruta por defecto (sin personalizar):
http://localhost:8080/swagger-ui/index.html
4. Probar con Postman
También puedes hacer pruebas directas con Postman:
GET /api/productos
GET http://localhost:8080/api/productos
GET – Obtener producto por ID
GET http://localhost:8080/api/productos/1
POST – Crear un nuevo producto
POST http://localhost:8080/api/productos
Content-Type: application/json
{
"nombre": "Mouse",
"precio": 19.95,
"stock": 50
}
PUT – Actualizar un producto existente
PUT http://localhost:8080/api/productos/1
Content-Type: application/json
{
"nombre": "Mouse inalámbrico",
"precio": 25.50,
"stock": 40
}
DELETE – Eliminar un producto
DELETE http://localhost:8080/api/productos/1