En aquest tema, aprendrem com gestionar les excepcions en una aplicació Spring Boot que exposa serveis web RESTful. La gestió adequada d'excepcions és crucial per proporcionar respostes coherents i informatives als clients de l'API.
Objectius
- Entendre la importància de la gestió d'excepcions en serveis RESTful.
- Aprendre a utilitzar les anotacions de Spring per gestionar excepcions.
- Implementar un controlador d'excepcions global.
- Proporcionar respostes personalitzades per a diferents tipus d'errors.
- Importància de la Gestió d'Excepcions en REST
Quan es desenvolupa una API RESTful, és important gestionar les excepcions de manera que els clients rebin respostes clares i coherents. Això ajuda a:
- Millorar l'experiència de l'usuari.
- Facilitar el depurament i la resolució de problemes.
- Mantenir la seguretat de l'aplicació evitant la divulgació d'informació sensible.
- Utilitzant @ExceptionHandler
Spring Boot proporciona l'anotació @ExceptionHandler per gestionar excepcions específiques en un controlador. Vegem un exemple:
@RestController
@RequestMapping("/api")
public class ProductController {
@GetMapping("/products/{id}")
public ResponseEntity<Product> getProductById(@PathVariable Long id) {
Product product = productService.findById(id);
if (product == null) {
throw new ProductNotFoundException("Product not found with id: " + id);
}
return ResponseEntity.ok(product);
}
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ErrorResponse> handleProductNotFoundException(ProductNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
}En aquest exemple:
ProductControllerté un mètodegetProductByIdque llança una excepcióProductNotFoundExceptionsi el producte no es troba.- El mètode
handleProductNotFoundExceptionestà anotat amb@ExceptionHandlerper gestionar aquesta excepció i retornar una resposta personalitzada.
- Creant un Controlador d'Excepcions Global
Per evitar repetir el codi de gestió d'excepcions en cada controlador, podem crear un controlador d'excepcions global utilitzant @ControllerAdvice.
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ErrorResponse> handleProductNotFoundException(ProductNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An unexpected error occurred");
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}En aquest exemple:
GlobalExceptionHandlerés una classe anotada amb@ControllerAdviceque gestiona excepcions a nivell global.- Té dos mètodes per gestionar excepcions específiques (
ProductNotFoundException) i genèriques (Exception).
- Proporcionant Respostes Personalitzades
Podem crear una classe ErrorResponse per estructurar les respostes d'error de manera coherent.
public class ErrorResponse {
private int status;
private String message;
public ErrorResponse(int status, String message) {
this.status = status;
this.message = message;
}
// Getters and setters
}Exercici Pràctic
Objectiu
Implementar la gestió d'excepcions en un controlador RESTful.
Passos
- Crea una excepció personalitzada
UserNotFoundException. - Implementa un controlador
UserControlleramb un mètode per obtenir un usuari per ID. - Afegeix un mètode
@ExceptionHandlerper gestionarUserNotFoundException. - Crea un controlador d'excepcions global per gestionar excepcions genèriques.
Solució
- Excepció personalitzada:
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}- Controlador
UserController:
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/users/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.findById(id);
if (user == null) {
throw new UserNotFoundException("User not found with id: " + id);
}
return ResponseEntity.ok(user);
}
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
}- Controlador d'excepcions global:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An unexpected error occurred");
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}Resum
En aquesta secció, hem après com gestionar les excepcions en una aplicació Spring Boot que exposa serveis web RESTful. Hem vist com utilitzar @ExceptionHandler per gestionar excepcions específiques i com crear un controlador d'excepcions global amb @ControllerAdvice. També hem après a proporcionar respostes personalitzades per a diferents tipus d'errors. La gestió adequada d'excepcions és essencial per proporcionar una API robusta i fàcil de depurar.
Curs de Spring Boot
Mòdul 1: Introducció a Spring Boot
- Què és Spring Boot?
- Configuració del teu entorn de desenvolupament
- Creant la teva primera aplicació Spring Boot
- Entenent l'estructura del projecte Spring Boot
Mòdul 2: Conceptes bàsics de Spring Boot
- Anotacions de Spring Boot
- Injecció de dependències a Spring Boot
- Configuració de Spring Boot
- Propietats de Spring Boot
Mòdul 3: Construint serveis web RESTful
- Introducció als serveis web RESTful
- Creant controladors REST
- Gestionant mètodes HTTP
- Gestió d'excepcions en REST
Mòdul 4: Accés a dades amb Spring Boot
- Introducció a Spring Data JPA
- Configuració de fonts de dades
- Creant entitats JPA
- Utilitzant repositoris de Spring Data
- Mètodes de consulta a Spring Data JPA
Mòdul 5: Seguretat a Spring Boot
- Introducció a Spring Security
- Configuració de Spring Security
- Autenticació i autorització d'usuaris
- Implementant autenticació JWT
Mòdul 6: Proves a Spring Boot
Mòdul 7: Funcions avançades de Spring Boot
Mòdul 8: Desplegant aplicacions Spring Boot
Mòdul 9: Rendiment i monitorització
- Optimització del rendiment
- Monitorització amb Spring Boot Actuator
- Utilitzant Prometheus i Grafana
- Gestió de registres i logs
