JavaRush /Blog Java /Random-FR /Gestion des exceptions dans les contrôleurs Spring Boot
Павел
Niveau 11

Gestion des exceptions dans les contrôleurs Spring Boot

Publié dans le groupe Random-FR
CONTENU DU CYCLE D'ARTICLE Rebonjour ! Il est temps de dépoussiérer votre clavier. Créez un projet Spring Boot. À partir des dépendances maven, nous avons besoin de :
<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <java.version>1.8</java.version>
</properties>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.0.RELEASE</version>
    <relativePath/><!-- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
Avant de poursuivre votre lecture, créez une structure de projet : Gestion des exceptions dans les contrôleurs Spring Boot - 1 BusinessException et CustomException :
public class BusinessException extends Exception{
    public BusinessException(String message) {
        super(message);
    }
}

public class CustomException extends Exception{
    public CustomException(String message) {
        super(message);
    }
}
et la classe Réponse
public class Response {

    private String message;

    public Response() {
    }

    public Response(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
Et maintenant, je vais faire un tour avec mes oreilles et donner la parole à Alexey Kutepov, dans son article Exception Handling in Spring Controllers, il nous expliquera comment remplir ces fichiers avec le contenu correct. Lisez lentement, copiez soigneusement tous les exemples dans votre projet, exécutez et testez dans Postman. Si dans l'article d'Alexey la ligne suivante vous a posé des questions : produit = APPLICATION_JSON_VALUE , alors sachez que cela n'a rien à voir avec la gestion des exceptions, elle dit que par défaut toutes les méthodes de ce contrôleur renverront JSON. Si nécessaire, dans une méthode spécifique, cette valeur peut être remplacée par un autre MediaType. Si vous l'avez lu, continuez. L'article ci-dessus traite des différentes options pour les gestionnaires. Le plus flexible d'entre eux : @ControllerAdvice - il vous permet de modifier à la fois le code et le corps de la réponse standard en cas d'erreur. De plus, il vous permet de gérer plusieurs exceptions à la fois en une seule méthode. Mais ce n'est pas tout, si vous continuez à lire, vous obtiendrez le @ControllerAdvice amélioré entièrement gratuitement. Faisons un travail préparatoire : je souhaite que la réponse affiche à la fois des messages d'erreur personnalisés et standard. Pour ce faire, apportons une modification à la classe Response : ajoutons un champ supplémentaire
private String debugMessage;
Créons un constructeur supplémentaire :
public Response(String message, String debugMessage) {
    this.message = message;
    this.debugMessage = debugMessage;
}
et n'oubliez pas de créer un Getter et un Setter pour le nouveau champ. Maintenant au point. Écrivons un autre contrôleur :
@RestController
public class Example7Controller {
    @GetMapping(value = "/testExtendsControllerAdvice")
    public ResponseEntity<?> testExtendsControllerAdvice(@RequestBody Response response) {
        return  ResponseEntity.ok(response);
    }
}
Testons dans Postman : Envoyez JSON à http://localhost:8080/testExtendsControllerAdvice
{
    "message": "message"
}
En réponse, nous recevrons un statut de 200 et un corps
{
    "message": "message",
    "debugMessage": null
}
Maintenant, nous enverrons un JSON manifestement incorrect
{
    11"message": "message"
}
En réponse, nous recevrons un statut de 400 (si vous avez oublié ce que cela signifie, recherchez-le sur Internet) et un corps de réponse vide. Bien sûr, cela ne plaît à personne, luttons contre cela. Auparavant, nous avons créé @ControllerAdvice à partir de zéro, mais dans Spring Boot, il existe un modèle - ResponseEntityExceptionHandler . Il gère déjà de nombreuses exceptions, par exemple : NoHandlerFoundException , HttpMessageNotReadableException , MethodArgumentNotValidException et autres. Cette classe gère les erreurs. Il contient un certain nombre de méthodes dont les noms sont basés sur le principe handle + nom de l'exception. Si nous voulons gérer une exception de base, nous héritons de cette classe et remplaçons la méthode souhaitée . Finalisons la classe consultative par défaut
@ControllerAdvice
public class DefaultAdvice extends ResponseEntityExceptionHandler {//унаследовались от обработчика-заготовки

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response> handleException(BusinessException e) {
        Response response = new Response(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.OK);
    }
//Небольшое отступление: В обработчике выше, обратите внимание на HttpStatus.OK,
//он может быть и HttpStatus.BAD_REQUEST or другим, тут ограничений нет,
//попробуйте поменять статусы и потестить этот обработчик


    @Override//переопределor метод родительского класса
    protected ResponseEntity<Object> handleHttpMessageNotReadable
            (HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        Response response = new Response("Не правильный JSON",ex.getMessage());
        return new ResponseEntity<>(response, status);
    }
}
Comme vous l'avez remarqué, le gestionnaire responsable de HttpMessageNotReadableException a été remplacé . Cette exception se produit lorsque le corps de la requête arrivant à la méthode du contrôleur est illisible (par exemple, un JSON incorrect). La méthode handleHttpMessageNotReadable () est responsable de cette exception . Faisons à nouveau une requête avec un JSON incorrect : vers http://localhost:8080/testExtendsControllerAdvice
{
    11"message": "message"
}
Nous recevons une réponse avec le code 400 (Bad Request) et le corps :
{
    "message": "Не правильный JSON",
    "debugMessage": "JSON parse error: Unexpected character ('1' (code 49)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('1' (code 49)): was expecting double-quote to start field name\n at [Source: (PushbackInputStream); line: 2, column: 6]"
}
Désormais, la réponse contient non seulement le code correct, mais également un corps contenant des messages informatifs. Vérifions comment cela fonctionne avec la requête JSON correcte :
{
    "message": "message"
}
Nous avons reçu la réponse :
{
    "message": "message",
    "debugMessage": null
}
Pour être honnête, je n'aime pas que la réponse contienne un champ avec la valeur null , nous allons rapidement résoudre ce problème maintenant. Accédez à la classe Response et mettez une annotation sur le champ requis
@JsonInclude(JsonInclude.Include.NON_NULL)
private String debugMessage;
On redémarre le projet, on refait la requête précédente, et en réponse on obtient :
{
    "message": "message"
}
Grâce à l' annotation @JsonInclude(JsonInclude.Include.NON_NULL) , ce champ ne sera inclus dans la réponse que si nous le précisons. @JsonInclude est inclus dans la bibliothèque d'annotations Jackson , il est très utile de savoir ce qu'il peut faire. Voici deux articles parmi lesquels choisir : Annotations de Jackson. L'auteur a traduit, mais n'a pas terminé la traduction ; Google Translit fait un excellent travail. Validation Il est nécessaire de compléter ce sujet avec un concept tel que la validation. En termes simples, il s'agit d'une vérification que l'objet est bien l'objet attendu. Par exemple : si dans l'application « Phone Directory » nous devons vérifier la présence de numéros de téléphone dans la base de données, alors avant d'entrer dans la base de données, il est logique de vérifier si l'utilisateur a saisi des lettres au lieu de chiffres. Trois articles sur la validation, de complexité croissante : Validation Bean dans Spring Mise en place de la validation DTO dans le Spring Framework Validation des données dans Spring Boot Nous en avons fini avec la théorie pour aujourd'hui. Pour la formation, je suggère la tâche suivante : Vous devez implémenter l'application NightclubBouncer. Exigences : 1) L'application doit accepter JSON comme entrée et écrire dans la base de données. Exemple JSON :
{
    "name": "Katy Perry"
    “status”:super star”
}
Et le corps de la réponse doit contenir l'inscription suivante : Bienvenue + nom ! 2) L'application doit implémenter les méthodes suivantes : - sortie d'un enregistrement par identifiant de la base de données vers le client (Postman). - suppression d'un enregistrement par champ : nom . 3) Le mappage de la couche dto à l'entité et inversement doit être implémenté . 4) L'application doit générer une erreur KickInTheAssException (vous devez la développer vous-même) si le champ d'état dans le JSON entrant n'est pas égal à : super star 5) L'erreur KickInTheAssException doit être gérée par ControllerAdvice et le corps de la réponse doit contenir le message : « Ne me laisse plus te revoir ici ! L'état de la réponse doit être 400. 6) Erreur standard EntityNotFoundException , qui se produit, par exemple, si seule Katy Perry est venue au club et enregistrée dans la base de données avec id = 1 , et que vous avez appelé la méthode « afficher l'enregistrement par identifiant » et que vous vouliez pour afficher l'enregistrement avec id = 2 , qui n'est pas dans la base de données. Cette erreur doit être gérée par une méthode surchargée de la classe ResponseEntityExceptionHandler , qu'il vous appartient de découvrir vous-même. La réponse doit avoir le statut approprié. 7) Faites la validation : une option simple - les champs JSON ne doivent pas être nuls, ou plus difficile, le champ "nom" doit être composé de deux mots de l'alphabet latin et ils doivent tous deux commencer par une majuscule. Les valeurs non valides doivent lever une exception, la gérer de quelque manière que ce soit, imprimer le code d'erreur approprié et le message d'erreur : Pas de validation. Et implémentez tout cela sans utiliser la bibliothèque Lombok, ne l'incluez pas comme dépendance du projet 😅
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION