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:
ProductController
té un mètodegetProductById
que llança una excepcióProductNotFoundException
si el producte no es troba.- El mètode
handleProductNotFoundException
està anotat amb@ExceptionHandler
per 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@ControllerAdvice
que 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
UserController
amb un mètode per obtenir un usuari per ID. - Afegeix un mètode
@ExceptionHandler
per 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