Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.
Aunque no es indispensable, la implementación de servicios en un proyecto de SpringBoot es habitual y tiene las siguientes ventajas:
- Separación de responsabilidades: Mantener la lógica de negocio separada de la capa de controladores.
- Reutilización: Facilitar la reutilización de la lógica de negocio en diferentes partes de la aplicación.
- Mantenimiento: Hacer que el código sea más fácil de mantener y probar.
En SpringBoot lo servicios son clases que generalmente son llamadas desde los controladores, aunque también pueden ser llamadas desde otros servicios o componentes.
A menudo, los servicios se encargan de mapear los DTO a nuestras entidades del modelo y viceversa.
package com.app.controllers;
import com.app.services.BookServices;
@RestController
@CrossOrigin
@RequestMapping("/locations")
public class BookController {
@Autowired
LocationServices locationServices;
@PostMapping
public ResponseEntity<?> saveBook(@RequestBody LocationTagDTO locationTagDTO) {
try {
BookDTO saveLocation = bookServices.createBook(bookDTO);
return ResponseEntity.status(200).body(saveLocation);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(500).body("Error al crear la ubicación " + e.getMessage());
}
}
package com.app.services.impl
...
@Service
public class BookServicesImpl implements BookServices {
@Autowired
private BookRepository bookRepository;
@Override
public BookDTO createBook(BookDTO bookDTO) {
Book book = new Book();
book.setTitle(bookDTO.getTitle());
bookRepository.save(location);
// Mapear la entidad de vuelta a un DTO para devolverlo (best practices)
BookDTO bookDTO = new BookDTO();
bookDTO.setTitle(book.getTitle());
return bookDTO;
}
}
Usamos la siguiente interfaz para definir un contrato que la clase BookServicesImpl debe cumplir. Esto permite:
- Abstracción: Ocultar los detalles de implementación y exponer solo los métodos necesarios.
- Flexibilidad: Facilitar el cambio de implementación sin afectar a las clases que dependen de la interfaz.
- Testabilidad: Permitir el uso de mocks o stubs en pruebas unitarias.
com.pablomonteserin.prueba.services
public interface BookServices {
BookDTO createLocation (BookDTO bookDTO);
}
Mapeos automáticos
El mapeo que vimos antes para pasar de DTO a Entity se podía haber hecho automáticamente con un mapper.
Para ello, será necesario cargar las siguientes dependencias en el pom.xml:
<!-- MapStruct-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.6.3</version>
</dependency>
package com.app.mapper;
...
@Mapper(componentModel = "spring")
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping(target = "password", expression = "java(passwordEncoderService.encodePassword(source.getPassword()))")
User fromUserDTO(UserDTO source);
@Mapping(source = "owner.id", target = "ownerId")
@Mapping(target = "password", ignore = true)
UserDTO fromUser(User source);
}