You don't have access to this class

Keep learning! Join and start boosting your career

Aprovecha el precio especial y haz tu profesión a prueba de IA

Antes: $249

Currency
$209
Suscríbete

Termina en:

2 Días
0 Hrs
2 Min
20 Seg
Curso de Java Spring

Curso de Java Spring

Alejandro Ramírez

Alejandro Ramírez

Implementar la anotación @Service

23/35
Resources

How to create a domain service in Spring Boot?

Building a domain service is a crucial part of application development, since it acts as a vital intermediary between our API controller and the repository. This approach allows you to maintain a clear separation of responsibilities, thus improving the maintainability and scalability of your application. In this article, we will dive into the process of creating a ProductService in an application using Spring Boot.

What is a service in Spring Boot?

In the context of Spring Boot, a service is a class that contains application-specific business logic. Generally, these classes are decorated with the @Service annotation, which is imported from the org.springframework.stereotype package. The use of @Service not only provides semantic differentiation, it also facilitates dependency injection management.

@Servicepublic class ProductService { private final ProductRepository productRepository;
 @Autowired public ProductService(ProductRepository productRepository) { this.productRepository = productRepository; }
 // Service methods}

How do you inject the repository into a service?

In Spring Boot, the @Autowired annotation is used to inject dependencies automatically. When we define the repository as an interface type attribute in the service, Spring Boot takes care of creating and mapping the actual implementation of the repository.

What are the essential methods for the product service?

For a product service, it is crucial to implement certain basic methods that handle CRUD (Create, Read, Update, Delete) operations efficiently. Here is a look at some of these fundamental methods:

  • List All Products: This method returns a list of all products.

    public List<Product> getAll() { return productRepository.getAll();}
  • Get a product by ID: Uses an Optional to handle the possibility that the product does not exist.

    public Optional<Product> getProduct(int productId) { return productRepository.getProduct(productId);}
  • Save a product: this method persists a new product in the repository.

    public Product save(Product product) { return productRepository.save(product);}
  • Delete a product: Here, we demonstrate how to return a boolean depending on whether the delete operation was successful.

    public boolean delete(int productId) { return getProduct(productId).map(product -> { productRepository.delete(productId); return true; }).orElse(false);}

What additional considerations to have when creating services?

  1. Using Optional and Map: Optional is an excellent tool for handling results that may be null, promoting safer and cleaner code by avoiding NPE (Null Pointer Exception) exceptions.

  2. Annotations and Dependency Management: Spring annotations such as @Service and @Autowired facilitate dependency management and class establishment within the Spring context.

  3. Semantics and Best Practices: It is important to follow conventions and best practices when using annotations to facilitate code maintenance and understanding.

By understanding and applying these concepts, you will be in a better position to develop services within Spring Boot applications, ensuring a robust and scalability-oriented framework and business understanding. Continue to explore and hone your Spring Boot skills!

Contributions 21

Questions 12

Sort by:

Want to see more contributions, questions and answers from the community?

Estaba un poco confundido con el concepto de Repositorio y Servicio. Así que me puse a indagar un poco y resulta que el repositorio es la capa simple de acceso o de comunicación con el sistema de almacén de datos (ojo, solo comunicación), mientras que el servicio es la lógica de acceso a estos datos desde la aplicación, así pues un ejemplo sería: Entras a un cajero automática y sacas dinero de tu cuenta, el banco es el repositorio, y el cajero es el servicio.

Las implementaciones del método delete son buenos ejemplos de los estilos declarativo e imperativo.
El primero define el qué va a hacer el código mientras que el segundo define el cómo y por consiguiente se ven más detalles. Cabe aclarar que el estilo declarativo no puede existir sin el estilo imperativo ya que el primero se apoya en el segundo para ocultar las estructuras de control (if, else, switch, etc).

¿Porqué es necesario verificar que el producto exista en la base de datos antes de borrarlo? El Id normalmente se obtiene de procesos anteriores como de un listado, y si queremos saber si el borrado es exitoso se podría obtener el número de fila(s) eliminada(s) … lo digo porque esto se ve muy bonito y mantenible, pero es costoso en máquina… ¿no?

@Service:

Intermediario entre el controlador de la API y el repositorio

Nuestros servicios son negociadores entre el repositorio y los controladores

Creo que todo tiene un porque, al principio lo veía como algo repetitivo pero ahora tengo mas claro el porque se programa así.
Gracias profesor, excelente curso.

Para el que quiera entender de donde vienen estos objetos que nombra el profesor como el Optional o el método .map() … esto hace parte de lo que es Programación Funcional (Un paradigma de programación) de la cual Java año tras año ha tratado de adaptarse a este.
Actualmente se encuentra un curso de Java Funcional en platzi y es excelente.
https://platzi.com/cursos/java-funcional/

Creo que de esta forma es más legible el método delete:

    public boolean delete(long id) {
        if (get(id).isEmpty()) {
            return false;
        }
        repository.delete(id);
        return true;
    }
![](https://static.platzi.com/media/user_upload/image-2c9f4bbf-adf6-4115-ae4b-b0e7886f5c8b.jpg)Si tienen errores como este tengan en cuenta no poner un "," de más, me quedé una hora buscando el error ![](https://static.platzi.com/media/user_upload/image-eaea91a3-b9e5-4f08-8a98-21787dff409b.jpg)

Esta linea se puede leer de la siguiente forma?, no entendí muy bien la instrucción
Si existia el producto y fue eliminado responde true de lo contrario response false
return getProduct(productId).map(Product ->{
productoRepository.delete(producttId);
return true;
}).orElse(false);

Significado de @Service

No hace falta usar el @Autowired en este caso porque Spring buscará la instancia de ProductRepository en su contenedor y se dará cuenta que existe creado previamente uno con el nombre productRepository, mismo nombre que el del atributo en ProductService. No obstante es buena práctica anotarlo con @Autowired

Otra opcion para el Delete, es con una lamda, queda mas prolijo me parece.

  public boolean delete(int productId){
        
        return getProduct(productId).map(product -> true).orElse(false);
    }```

Como usar el orElse del metodo map

El delete manejando la exception `public boolean delete(int productId) {` ` Optional<Product> productOpt = getProduct(productId);` ` if (productOpt.isEmpty()) {` ` return false;` ` }` ` try {` ` productRepository.delete(productId);` ` return true;` ` } catch (Exception e) {` ` return false;` ` }` `}`
De verdad esta muy confuso el tema de como se relacionan todas las capas las interfaces y las clases entre sí... quiza sea buena idea mostrar un mapa de la arquitectura que sigue el curso (hexagonal, onion... etc) e ir mostrando el flujo de datos.. es mi opinion
De mi parte creo que lo más importante con la bandera es avisar si el registro fue borrado, bien por mi acción o bien por alguna acción previa a la mía. Quizá por ejemplo, otro usuario en paralelo o concurrente ha dado la misma orden de eliminación antes que yo y mi instruccion puede que falle por eso, o simplemente no haga nada. Si yo recibo la bandera 'false' pienso que mi proceso ha fallado, aunque mi objetivo el cuál es borrar el registro con dicho id en si se ha cumplido. Bajo esta lógica, pensaría que es más importante validar después de la instrucción delete si el producto que quiero eliminar ya No Existe. algo como: try{ productRepository.delete(idProduct); }catch(DeleteException ex){ ... } return ! productRepository.exist(idProduct);
Con los delete a mi me gusta verificar despues de eliminar de esta forma ```js public boolean delete(int productId) { // return getProduct(productId).map(product -> { // productRepository.delete(productId); // return true; // }).orElse(false); // if(getProduct(productId).isPresent()) { // productRepository.delete(productId); // return true; // } // return false; productRepository.delete(productId); return productRepository.getProduct(productId).isPresent(); } ```Ya despues agregar try catch para evitar daños y cambia un poco pero la idea se mantiene

Otra forma de hacerlo

	boolean isPresent = getProduct(productId).isPresent();

        if(isPresent) productRepositoryDomain.delete(productId);

        return isPresent;

Saber un framework de backend como Nest.js me esta ayudando a entender mas rapido estos terminos. Que estemos haciendo varios archivos que obtienen un producto puede ser dificil de entender para un principiante.

Muy útil todo.