Lors de la création d'un contrôleur dans Spring Boot pour gérer toutes les erreurs/exceptions de manière personnalisée, y compris les exceptions personnalisées , quelle technique privilégier?
Le contrôleur doit-il implémenter le ErrorController
de Spring Boot?
Le contrôleur doit-il étendre le ResponseEntityExceptionHandler
de Spring?
Les deux: un seul contrôleur implémentant et étendant les deux classes, y compris leurs deux fonctionnalités?
Les deux: deux contrôleurs distincts, l'un implémentant ErrorController
, l'autre étendant ResponseEntityExceptionHandler
?
La raison de ce message est de trouver un moyen de gestion des exceptions dans Spring Boot avec tous des attributs suivants:
Throwable
se produisant dans les contrôleurs/filtres/intercepteurs pendant le traitement d'une demande doivent être interceptés.Throwable
, nous ne voulons pas exposer la trace de la pile ou d'autres détails d'implémentation au client jamais (sauf si explicitement codé de cette façon).Throwable
s survenus séparément par leur classe. Pour tout autre type non spécifié, une réponse par défaut peut être spécifiée. (Je sais avec certitude que cela est possible avec @ExceptionHandler
. Mais ErrorController
?)J'ai remarqué que les deux contrôleurs (voir 1 et 2 ci-dessus) peuvent contenir des méthodes renvoyant un objet ResponseEntity
, gérant ainsi l'exception survenue et renvoyant une réponse au client. Donc, ils pourraient en théorie produire le même résultat?
Il existe plusieurs didacticiels sur l'utilisation des techniques 1 et 2. Mais je n'ai trouvé aucun article considérant les deux options, les comparant ou les utilisant ensemble, ce qui soulève plusieurs questions supplémentaires:
Doit-on même les considérer ensemble?
Quelles sont les principales différences entre ces deux techniques proposées? Quelles sont les similitudes?
L'un est-il une version plus puissante de l'autre? Y a-t-il quelque chose que l'on peut faire que l'autre ne peut pas et vice versa?
Peuvent-ils être utilisés ensemble? Y a-t-il des situations où cela serait nécessaire?
S'ils sont utilisés ensemble, comment une exception serait-elle gérée? Est-ce que cela passe par les deux gestionnaires ou un seul? Dans le cas de ce dernier, lequel?
S'ils sont utilisés ensemble et qu'une exception est levée à l'intérieur le contrôleur (l'un ou l'autre) pendant la gestion des exceptions , comment cette exception serait-elle gérée? Est-il envoyé à l'autre contrôleur? Les exceptions pourraient-elles théoriquement commencer à rebondir entre les contrôleurs ou créer un autre type de boucle non récupérable?
Existe-t-il une documentation fiable/officielle sur la façon dont Spring Boot utilise ResponseEntityExceptionHandler
de Spring en interne ou comment il s'attend à ce qu'il soit utilisé dans les applications Spring Boot?
Si ResponseEntityExceptionHandler
seul suffit déjà, alors pourquoi ErrorController
existe-t-il?
Lorsque vous regardez le ResponseEntityExceptionHandler
du printemps avec le @ExceptionHandler
annotation, il semble être plus puissant pour gérer séparément différents types d'exceptions et utiliser un code plus propre. Mais parce que Spring Boot est construit au-dessus de Spring, cela signifie-t-il:
ErrorController
au lieu d'étendre ResponseEntityExceptionHandler
?ErrorController
peut-il tout faire ResponseEntityExceptionHandler
peut, y compris gérer différents types d'exceptions séparément?EDIT: Connexes: Spring @ControllerAdvice vs ErrorController
L'application Spring Boot a une configuration par défaut pour la gestion des erreurs - ErrorMvcAutoConfiguration .
Ce qu'il fait essentiellement, si aucune configuration supplémentaire n'est fournie:
BasicErrorController
est câblé à '/ error' par défaut. S'il n'y a pas de vue "erreur" personnalisée dans l'application, en cas d'exception levée par un contrôleur, l'utilisateur accède à la page d'étiquette blanche/error, remplie d'informations par BasicErrorController.
Si l'application a un contrôleur implémentant ErrorController
il remplace BasicErrorController
.
Si une exception se produit dans le contrôleur de gestion des erreurs, elle passera par le filtre d'exception Spring (voir plus de détails ci-dessous) et enfin si rien n'est trouvé, cette exception sera gérée par le conteneur d'application sous-jacent, par ex. Matou. Le conteneur sous-jacent gérera l'exception et affichera une page/un message d'erreur en fonction de son implémentation.
Il y a une information intéressante dans BasicErrorController
javadoc :
Contrôleur d'erreurs globales de base, rendu ErrorAttributes. Des erreurs plus spécifiques peuvent être gérées soit en utilisant des abstractions Spring MVC (par exemple @ ExceptionHandler) soit en ajoutant des pages d'erreur du serveur de servlet.
L'implémentation BasicErrorController
ou ErrorController
est un gestionnaire d'erreur global . Il peut être utilisé conjointement avec @ExceptionHandler.
Nous arrivons ici à ResponseEntityExceptionHandler
Une classe de base pratique pour les classes @ControllerAdvice qui souhaitent fournir une gestion centralisée des exceptions dans toutes les méthodes @RequestMapping via les méthodes @ExceptionHandler. Cette classe de base fournit une méthode @ExceptionHandler pour gérer les exceptions Spring MVC internes.
En d'autres termes, cela signifie que ResponseEntityExceptionHandler
n'est qu'une classe de commodité, qui contient déjà la gestion des exceptions Spring MVC. Et nous pouvons l'utiliser comme classe de base pour notre classe personnalisée pour gérer les exceptions des contrôleurs. Pour que notre classe personnalisée fonctionne, elle doit être annotée avec @ControllerAdvice
.
Classes annotées avec @ControllerAdvice
peut être utilisé en même temps que le gestionnaire d'erreur global (implémentation BasicErrorController
ou ErrorController
). Si notre @ControllerAdvice
la classe annotée (qui peut ou non étendre ResponseEntityExceptionHandler
) ne gère pas une exception, l'exception va au gestionnaire d'erreur global.
Jusqu'à présent, nous avons examiné ErrorHandler
contrôleur et tout ce qui était annoté avec @ControllerAdvice
. Mais c'est beaucoup plus compliqué. J'ai trouvé un aperçu vraiment précieux dans la question - Définition de la priorité de plusieurs @ControllerAdvice @ExceptionHandlers .
Modifier:
Pour faire simple:
Je dois admettre que je ne suis pas trop familier avec ErrorController de Spring, mais en regardant vos objectifs spécifiés, je crois que tous peuvent être atteints proprement en utilisant @ControllerAdvice de Spring. Ce qui suit est un exemple de la façon dont je l'ai utilisé dans mes propres applications:
@ControllerAdvice
public class ExceptionControllerAdvice {
private static final String INCOMING_REQUEST_FAILED = "Incoming request failed:";
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionControllerAdvice.class);
private final MessageSource source;
public ExceptionControllerAdvice2(final MessageSource messageSource) {
source = messageSource;
}
@ExceptionHandler(value = {CustomException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ErrorMessage badRequest(final CustomException ex) {
LOGGER.error(INCOMING_REQUEST_FAILED, ex);
final String message = source.getMessage("exception.BAD_REQUEST", null, LocaleContextHolder.getLocale());
return new ErrorMessage(HttpStatus.BAD_REQUEST.value(), message);
}
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorMessage internalServerError(final Exception ex) {
LOGGER.error(INCOMING_REQUEST_FAILED, ex);
final String message =
source.getMessage("exception.INTERNAL_SERVER_ERROR", null, LocaleContextHolder.getLocale());
return new ErrorMessage(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
}
}