Gestion globale des exceptions dans Spring Boot

Dans Spring Boot, la gestion centralisée des exceptions permet d'intercepter et de traiter les erreurs de manière uniforme à travers l'application. Voici comment implémenter cette approche avec des exemples de code modifiés pour plus de clarté et d'originalité.

La classe principale pour capturer les exceptions est définie comme suit :

package com.example.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public String missingParamHandler(MissingServletRequestParameterException ex) {
        log.error("Paramètre de requête manquant", ex);
        return "Paramètre de requête manquant";
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public String parsingFailureHandler(HttpMessageNotReadableException ex) {
        log.error("Échec de l'analyse des paramètres", ex);
        return "Échec de l'analyse des paramètres";
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String validationFailureHandler(MethodArgumentNotValidException ex) {
        log.error("Échec de la validation des paramètres", ex);
        BindingResult result = ex.getBindingResult();
        FieldError error = result.getFieldError();
        String champ = error.getField();
        String message = error.getDefaultMessage();
        return "Validation échouée : " + champ + " - " + message;
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public String bindingFailureHandler(BindException ex) {
        log.error("Échec de la liaison des paramètres", ex);
        BindingResult result = ex.getBindingResult();
        FieldError error = result.getFieldError();
        String champ = error.getField();
        String message = error.getDefaultMessage();
        return "Liaison échouée : " + champ + " - " + message;
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public String constraintViolationHandler(ConstraintViolationException ex) {
        log.error("Violation de contrainte de validation", ex);
        Set<constraintviolation>> violations = ex.getConstraintViolations();
        if (!violations.isEmpty()) {
            ConstraintViolation> violation = violations.iterator().next();
            return "Violation de contrainte : " + violation.getMessage();
        }
        return "Violation de contrainte inconnue";
    }

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public String notFoundHandler(NoHandlerFoundException ex) {
        log.error("Ressource non trouvée", ex);
        return "Ressource non trouvée : " + ex.getRequestURL();
    }

    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public String methodNotAllowedHandler(HttpRequestMethodNotSupportedException ex) {
        log.error("Méthode HTTP non supportée", ex);
        return "Méthode HTTP non supportée";
    }

    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public String unsupportedMediaTypeHandler(HttpMediaTypeNotSupportedException ex) {
        log.error("Type de média non supporté", ex);
        return "Type de média non supporté";
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(BusinessException.class)
    public String businessExceptionHandler(BusinessException ex) {
        log.error("Exception métier", ex);
        return "Exception métier : " + ex.getMessage();
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(DatabaseOperationException.class)
    public String databaseOperationHandler(DatabaseOperationException ex) {
        log.error("Exception d'opération en base de données", ex);
        return "Exception d'opération en base de données : " + ex.getMessage();
    }

    @ExceptionHandler(Exception.class)
    public String generalExceptionHandler(Exception ex) {
        log.error("Exception générale", ex);
        return "Exception générale : " + ex.getMessage();
    }
}</constraintviolation>

Les exceptions personnalisées sont définies pour des cas spécifiques :

package com.example.exception;

public class BusinessException extends RuntimeException {
    public BusinessException(String message) {
        super(message);
    }
}
package com.example.exception;

public class DatabaseOperationException extends RuntimeException {
    public DatabaseOperationException(String message) {
        super(message);
    }
}

Pour que Spring MVC lance des exceptions sur les routes non gérées, ajoutez cette configuraton dans le fichier application.yml :

spring:
    mvc:
      throw-exception-if-no-handler-found: true
    resources:
      add-mappings: false

Cette configuration garantit que les requêtes sans gestionnaire défini déclenchent une exception, facilitant ainsi la gestion globale des erreurs 404.

Étiquettes: spring-boot Java exception-handling YAML mvc

Publié le 29 juin à 20h09