Saltar al contenido principal

Quiz: Capa de Servicio y Arquitectura

Ponga a prueba sus conocimientos sobre la capa de servicio, la validación y la arquitectura MVC.

30 preguntas - Haga clic en cada pregunta para revelar la respuesta.


Preguntas 1-10: Capa de Servicio​

Pregunta 1: ¿Cuál es el rol de la capa de Servicio en la arquitectura MVC?

Respuesta: La capa de Servicio contiene la lógica de negocio de la aplicación. Esta:

  • Orquesta las operaciones entre controladores y repositorios
  • Aplica las reglas de negocio
  • Gestiona las transacciones
  • Es independiente del protocolo HTTP

Pregunta 2: ¿Qué anotación se utiliza para declarar un servicio en Spring?

Respuesta: @Service - Es un estereotipo especializado de @Component que indica que la clase contiene lógica de negocio.

@Service
public class UserService {
// lógica de negocio
}

Pregunta 3: ¿Por qué no poner la lógica de negocio en el controlador?

Respuesta: Separar la lógica de negocio del controlador permite:

  • Reutilización: el servicio puede ser llamado por varios controladores
  • Testabilidad: probar la lógica sin HTTP
  • Mantenibilidad: código más organizado
  • Separación de responsabilidades: cada capa tiene un rol específico

Pregunta 4: ¿Cómo inyectar un Repository en un Service?

Respuesta: Por inyección de constructor (recomendado):

@Service
public class UserService {

private final UserRepository userRepository;

public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}

Pregunta 5: ¿Qué es un DTO (Data Transfer Object)?

Respuesta: Un DTO es un objeto simple utilizado para transferir datos entre capas. Este:

  • No contiene lógica de negocio
  • Expone solo los datos necesarios
  • Protege la entidad JPA de la exposición directa
  • Permite formatear los datos para la API

Pregunta 6: ¿Por qué usar DTOs en lugar de las entidades JPA directamente?

Respuesta:

  1. Seguridad: no exponer campos sensibles (password)
  2. Rendimiento: evitar la carga lazy de relaciones
  3. Flexibilidad: formato diferente al de la entidad
  4. Desacoplamiento: cambios internos no afectan la API
  5. Validación: reglas específicas para entrada/salida

Pregunta 7: ¿Cómo convertir una entidad en un DTO?

Respuesta: Varias aproximaciones:

// 1. Método manual
public UserDto toDto(User user) {
return new UserDto(user.getId(), user.getName(), user.getEmail());
}

// 2. Con MapStruct
@Mapper
public interface UserMapper {
UserDto toDto(User user);
}

// 3. Con ModelMapper
modelMapper.map(user, UserDto.class);

Pregunta 8: ¿Cuál es la diferencia entre un RequestDTO y un ResponseDTO?

Respuesta:

  • RequestDTO: datos entrantes (creación, actualización), contiene la validación
  • ResponseDTO: datos salientes, formateados para el cliente
// Request
public class CreateUserRequest {
@NotBlank
private String email;
@Size(min = 8)
private String password;
}

// Response
public class UserResponse {
private Long id;
private String email;
// ¡Sin password!
}

Pregunta 9: ¿Cómo manejar los errores en la capa de Servicio?

Respuesta: Lanzar excepciones personalizadas:

@Service
public class UserService {

public User findById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found: " + id));
}
}

Estas excepciones luego son gestionadas por @ControllerAdvice.


Pregunta 10: ¿Qué es @Transactional en un servicio?

Respuesta: @Transactional gestiona automáticamente las transacciones:

  • Inicia una transacción al principio del método
  • Commit si tiene éxito
  • Rollback si hay excepción
@Service
@Transactional
public class OrderService {
// Todos los métodos son transaccionales
}

Preguntas 11-20: Validación​

Pregunta 11: ¿Qué dependencia agregar para la validación?

Respuesta: spring-boot-starter-validation

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Pregunta 12: ¿Cómo activar la validación en un controlador?

Respuesta: Con @Valid o @Validated en el parámetro:

@PostMapping
public ResponseEntity<User> create(@Valid @RequestBody CreateUserRequest request) {
// Si la validación falla, se lanza MethodArgumentNotValidException
}

Pregunta 13: ¿Cuáles son las anotaciones de validación más comunes?

Respuesta:

AnotaciónDescripción
@NotNullNo debe ser null
@NotBlankNo null, no vacío, sin espacios
@NotEmptyNo null y no vacío
@Size(min, max)Tamaño entre min y max
@Min, @MaxValor numérico mínimo/máximo
@EmailFormato de email válido
@PatternRegex personalizada
@Past, @FutureFecha en pasado/futuro

Pregunta 14: ¿Cómo personalizar el mensaje de error de validación?

Respuesta: Con el atributo message:

public class CreateUserRequest {

@NotBlank(message = "El email es obligatorio")
@Email(message = "Formato de email inválido")
private String email;

@Size(min = 8, message = "La contraseña debe tener al menos 8 caracteres")
private String password;
}

Pregunta 15: ¿Cómo crear una validación personalizada?

Respuesta: Crear una anotación y un validador:

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueEmailValidator.class)
public @interface UniqueEmail {
String message() default "Email ya utilizado";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
// Verificar si el email existe
}
}

Pregunta 16: ¿Cuál es la diferencia entre @Valid y @Validated?

Respuesta:

  • @Valid: estándar Java (JSR-380), cascada la validación
  • @Validated: Spring, soporta grupos de validación
// Grupos de validación
public interface OnCreate {}
public interface OnUpdate {}

@NotNull(groups = OnUpdate.class)
private Long id;

@Validated(OnCreate.class)
public void create(...) { }

Pregunta 17: ¿Cómo validar los parámetros de consulta (query params)?

Respuesta: Agregar @Validated en el controlador:

@RestController
@Validated
public class UserController {

@GetMapping("/users")
public List<User> search(
@RequestParam @Min(0) int page,
@RequestParam @Max(100) int size) {
// ...
}
}

Pregunta 18: ¿Cómo validar un objeto anidado?

Respuesta: Usar @Valid en el campo anidado:

public class OrderRequest {

@Valid // Cascada la validación
@NotNull
private AddressDto shippingAddress;
}

public class AddressDto {
@NotBlank
private String street;
@NotBlank
private String city;
}

Pregunta 19: ¿Cómo recuperar los errores de validación?

Respuesta: Vía BindingResult o @ExceptionHandler:

// Opción 1: BindingResult
@PostMapping
public ResponseEntity<?> create(@Valid @RequestBody Request req, BindingResult result) {
if (result.hasErrors()) {
return ResponseEntity.badRequest().body(result.getAllErrors());
}
}

// Opción 2: ControllerAdvice (recomendado)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidation(MethodArgumentNotValidException ex) {
// Extraer los errores
}

Pregunta 20: ¿Qué es la validación a nivel de servicio?

Respuesta: Validación de la lógica de negocio (no solo el formato):

@Service
public class OrderService {

public Order createOrder(OrderRequest request) {
// Validación de negocio
if (request.getQuantity() > productService.getStock(request.getProductId())) {
throw new InsufficientStockException("Stock insuficiente");
}
// ...
}
}

Preguntas 21-30: Arquitectura​

Pregunta 21: ¿Cuáles son las 3 capas principales de la arquitectura MVC?

Respuesta:

  1. Controller (Presentación): gestiona HTTP, validación de entrada
  2. Service (Negocio): lógica de negocio, transacciones
  3. Repository (Datos): acceso a base de datos
Cliente → Controller → Service → Repository → Database

Pregunta 22: ¿En qué capa colocar la gestión de transacciones?

Respuesta: En la capa Service. Es ahí donde se encuentra la lógica de negocio que define lo que constituye una unidad de trabajo atómica.

@Service
@Transactional
public class TransferService {
public void transfer(Long fromId, Long toId, BigDecimal amount) {
// Toda la operación es atómica
}
}

Pregunta 23: ¿Cómo organizar los paquetes de un proyecto Spring Boot?

Respuesta: Por capa o por funcionalidad:

// Por capa
com.example.app
├── controller/
├── service/
├── repository/
├── model/
└── dto/

// Por funcionalidad (recomendado para proyectos grandes)
com.example.app
├── user/
│ ├── UserController
│ ├── UserService
│ └── UserRepository
├── order/
└── product/

Pregunta 24: ¿Qué es el principio de responsabilidad única (SRP)?

Respuesta: Una clase debe tener una sola razón para cambiar. Cada clase tiene una única responsabilidad:

  • Controller: gestionar las solicitudes HTTP
  • Service: lógica de negocio
  • Repository: acceso a datos

Mal ejemplo: un controlador que hace todo (HTTP + negocio + BD).


Pregunta 25: ¿Por qué usar interfaces para los servicios?

Respuesta:

  1. Desacoplamiento: los clientes dependen de la abstracción
  2. Testabilidad: fácil de mockear
  3. Flexibilidad: cambiar la implementación
  4. Proxying: Spring AOP funciona mejor
public interface UserService {
User findById(Long id);
}

@Service
public class UserServiceImpl implements UserService { }

Pregunta 26: ¿Qué es un @ControllerAdvice?

Respuesta: Un componente que gestiona las excepciones globalmente para todos los controladores:

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(UserNotFoundException ex) {
return ResponseEntity.status(404).body(new ErrorResponse(ex.getMessage()));
}
}

Pregunta 27: ¿Cómo estructurar una respuesta de error estándar?

Respuesta: Crear un DTO de error coherente:

public class ErrorResponse {
private LocalDateTime timestamp;
private int status;
private String error;
private String message;
private String path;
}

// O formato ProblemDetail (RFC 7807)

Pregunta 28: ¿Cuál es la diferencia entre @RestController y @Controller?

Respuesta:

  • @Controller: retorna vistas (HTML)
  • @RestController: retorna datos (JSON/XML)

@RestController = @Controller + @ResponseBody

@RestController  // Todo es JSON
public class UserController { }

@Controller
public class ViewController {
@GetMapping("/")
public String home() {
return "index"; // Vista Thymeleaf
}
}

Pregunta 29: ¿Cómo manejar los códigos HTTP apropiados?

Respuesta: Usar ResponseEntity:

@PostMapping
public ResponseEntity<User> create(@RequestBody UserRequest req) {
User user = userService.create(req);
return ResponseEntity
.status(HttpStatus.CREATED) // 201
.body(user);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build(); // 204
}

Pregunta 30: ¿Cuáles son los códigos HTTP comunes en REST?

Respuesta:

CódigoSignificadoUso
200OKGET, PUT exitoso
201CreatedPOST exitoso
204No ContentDELETE exitoso
400Bad RequestValidación fallida
401UnauthorizedNo autenticado
403ForbiddenNo autorizado
404Not FoundRecurso inexistente
500Server ErrorError interno

Puntuación​

PuntuaciónNivel
27-30Excelente - Arquitectura dominada
21-26Bien - Algunas revisiones
15-20Medio - Repase los capítulos
Menos de 15A revisar - Repase los fundamentos

Volver al Módulo 3