La lógica de negocio de nuestra aplicación
En esta parte construiremos la lógica de negocio de nuestra aplicación. El Service Layer es el cerebro que procesa las peticiones del Controller y comunica con el Repository para manejar los datos.
El Service Layer es el corazón de nuestra arquitectura, donde reside toda la lógica de negocio:
¿Qué es? Un contrato que define QUÉ métodos debe tener nuestro servicio.
¿Qué es? La clase que implementa la interface y contiene la lógica real.
@AllArgsConstructor: Genera un constructor con todos los campos como parámetros.
@NoArgsConstructor(force = true): Genera un constructor sin parámetros, inicializando campos final con valores por defecto.
@Data: Genera automáticamente getters, setters, toString, equals y hashCode.
Esta anotación le dice a Spring que esta clase es un componente de servicio:
El repository se inyecta como dependencia:
Usamos @Autowired
junto con final
para garantizar que la dependencia no pueda cambiar después de la construcción.
@Override: Garantiza que estamos implementando correctamente los métodos de la interface.
Cada método delega la operación al repository correspondiente, manteniendo la separación de responsabilidades.
Obtiene todas las mascotas de la base de datos. Delega completamente al repository sin lógica adicional.
Guarda una nueva mascota o actualiza una existente. JPA decide automáticamente según el ID.
Busca por ID y retorna null si no encuentra la mascota. Maneja el Optional de JPA con orElse().
Elimina una mascota por su ID. Si el ID no existe, JPA lanza una excepción que debería ser manejada.
Aunque el código funciona, hay algunas mejoras que podríamos implementar:
El método findById()
retorna null
cuando no encuentra una mascota. Es mejor lanzar una excepción específica:
public MascotaEntity findById(Long id) { return repository.findById(id) .orElseThrow(() -> new EntityNotFoundException("Mascota no encontrada con ID: " + id)); }
Podríamos agregar validaciones antes de guardar:
public MascotaEntity guardarMascota(MascotaEntity entity) { if (entity.getNombre() == null || entity.getNombre().trim().isEmpty()) { throw new IllegalArgumentException("El nombre de la mascota es obligatorio"); } return repository.save(entity); }
En aplicaciones grandes, es recomendable usar DTOs (Data Transfer Objects) en lugar de exponer las entidades directamente.
Cada servicio debe tener una única responsabilidad bien definida. Nuestro MascotaService solo maneja operaciones de mascotas.
Para operaciones complejas, usa @Transactional para garantizar la consistencia de los datos.
Siempre define interfaces para tus servicios. Facilita el testing y permite múltiples implementaciones.
Los controllers deben ser "tontos". Toda la lógica de negocio debe estar en los servicios.
Prefiere la inyección por constructor sobre @Autowired en campos. Es más testeable y seguro.
Agrega logs informativos para operaciones importantes, especialmente en métodos de creación y eliminación.
Agregamos control transaccional:
Agregamos logging para rastrear operaciones:
Mejoramos el manejo de errores:
Agregamos validaciones específicas:
politica de privacidad
Terminos y condiciones del vlog elingaldo
Descargo de responsabilidades.
Donaciones, sabes? el servidor no se mantiene del aire.