web-dev-qa-db-fra.com

Botte de printemps REST gestion des exceptions de service

J'essaie de configurer un serveur de services REST à grande échelle. Nous utilisons Spring Boot 1.2.1 Spring 4.1.5 et Java 8. Nos contrôleurs implémentent @RestController et les annotations standard @RequestMapping.

Mon problème est que Spring Boot configure une redirection par défaut pour les exceptions de contrôleur à /error. De la docs:

Spring Boot fournit par défaut un mappage/error qui gère toutes les erreurs de manière rationnelle. Il est enregistré en tant que page d’erreur «globale» dans le conteneur de servlets. 

Venant d’années au cours desquelles REST a écrit des applications avec Node.js, c’est pour moi tout sauf sensé. Toute exception générée par un noeud final de service doit être renvoyée dans la réponse. Je ne comprends pas pourquoi vous enverriez une redirection vers ce qui est probablement un consommateur angulaire ou JQuery SPA qui recherche uniquement une réponse et ne peut ou ne veut effectuer aucune action sur une redirection.

Ce que je veux faire, c’est configurer un gestionnaire d’erreur global qui peut accepter toute exception, soit délibérément renvoyé d’une méthode de mappage de demande, soit généré automatiquement par Spring (404 si aucune méthode de gestionnaire n’est trouvée pour la signature du chemin de demande), et renvoyer une réponse d'erreur formatée standard (400, 500, 503, 404) au client sans aucune redirection MVC. Plus précisément, nous allons prendre l'erreur, la consigner dans NoSQL avec un UUID, puis renvoyer au client le code d'erreur HTTP approprié avec l'UUID de l'entrée de journal dans le corps JSON.

Les docs ont été vagues sur la façon de procéder. Il me semble que vous devez soit créer votre propre ErrorController implémentation, soit utiliser ControllerAdvice d'une certaine manière, mais tous les exemples que j'ai vus incluent toujours le transfert de la réponse à une sorte de mappage d'erreurs, qui n'aide pas. D'autres exemples suggèrent que vous auriez à répertorier chaque type d'exception que vous souhaitez gérer au lieu de simplement lister "Throwable" et de tout récupérer.

Quelqu'un peut-il me dire ce que j'ai manqué ou me diriger dans la bonne direction sur la façon de procéder sans suggérer la chaîne que Node.js serait plus facile à gérer? 

131
ogradyjd

Nouvelle réponse (2016-04-20)

Utilisation de Spring Boot 1.3.1.RELEASE

New Step 1 - Il est facile et moins intrusif d’ajouter les propriétés suivantes au fichier application.properties:

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

Beaucoup plus facile que de modifier l'instance DispatcherServlet existante (comme ci-dessous)! - JO '

Si vous travaillez avec une application RESTful complète, il est très important de désactiver le mappage automatique des ressources statiques, car si vous utilisez la configuration par défaut de Spring Boot pour gérer les ressources statiques, le gestionnaire de ressources traitera la demande (elle est commandée en dernier et mappée sur/** ce qui signifie qu'il prend en charge toutes les demandes qui n'ont pas été traitées par un autre gestionnaire de l'application) afin que le servlet de répartiteur n'ait pas la possibilité de lancer une exception.


Nouvelle réponse (2015-12-04)

Utilisation de Spring Boot 1.2.7.RELEASE

New Step 1 - J'ai trouvé un moyen beaucoup moins intrusif de définir l'indicateur "throExceptionIfNoHandlerFound". Remplacez le code de remplacement DispatcherServlet ci-dessous (étape 1) par ceci dans votre classe d'initialisation d'application:

@ComponentScan()
@EnableAutoConfiguration
public class MyApplication extends SpringBootServletInitializer {
    private static Logger LOG = LoggerFactory.getLogger(MyApplication.class);
    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
        DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
    }

Dans ce cas, nous définissons l'indicateur sur le DispatcherServlet existant, qui conserve toute configuration automatique par la structure Spring Boot. 

Une dernière chose que j'ai trouvée: l'annotation @EnableWebMvc est mortelle pour Spring Boot. Oui, cette annotation permet, par exemple, de récupérer toutes les exceptions de contrôleur décrites ci-dessous, mais elle détruit également BEAUCOUP de la configuration automatique utile fournie par Spring Boot. Utilisez cette annotation avec une extrême prudence lorsque vous utilisez Spring Boot.


Réponse originale:

Après de nombreuses recherches et un suivi des solutions postées ici (merci de l'aide!) Et du nombre de traces d'exécution dans le code Spring, j'ai finalement trouvé une configuration qui gérera toutes les exceptions (pas les erreurs, mais la suite). y compris les 404.

Étape 1 - dites à SpringBoot de cesser d'utiliser MVC pour les situations de "gestionnaire introuvable". Nous voulons que Spring lève une exception au lieu de renvoyer au client une vue redirigée vers "/ error". Pour ce faire, vous devez avoir une entrée dans l'une de vos classes de configuration:

// NEW CODE ABOVE REPLACES THIS! (2015-12-04)
@Configuration
public class MyAppConfig {
    @Bean  // Magic entry 
    public DispatcherServlet dispatcherServlet() {
        DispatcherServlet ds = new DispatcherServlet();
        ds.setThrowExceptionIfNoHandlerFound(true);
        return ds;
    }
}

L'inconvénient est qu'il remplace la servlet de répartition par défaut. Cela ne nous a pas encore posé de problème, sans effets secondaires ni problèmes d'exécution. Si vous voulez faire autre chose avec la servlet de répartiteur pour d'autres raisons, nous vous invitons à le faire.

Étape 2 - Maintenant que spring boot lève une exception lorsqu'aucun gestionnaire n'est trouvé, cette exception peut être gérée avec toutes les autres dans un gestionnaire d'exception unifié:

@EnableWebMvc
@ControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(Throwable.class)
    @ResponseBody
    ResponseEntity<Object> handleControllerException(HttpServletRequest req, Throwable ex) {
        ErrorResponse errorResponse = new ErrorResponse(ex);
        if(ex instanceof ServiceException) {
            errorResponse.setDetails(((ServiceException)ex).getDetails());
        }
        if(ex instanceof ServiceHttpException) {
            return new ResponseEntity<Object>(errorResponse,((ServiceHttpException)ex).getStatus());
        } else {
            return new ResponseEntity<Object>(errorResponse,HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        Map<String,String> responseBody = new HashMap<>();
        responseBody.put("path",request.getContextPath());
        responseBody.put("message","The URL you have reached is not in service at this time (404).");
        return new ResponseEntity<Object>(responseBody,HttpStatus.NOT_FOUND);
    }
    ...
}

Gardez à l'esprit que je pense que l'annotation "@EnableWebMvc" est importante ici. Il semble que rien de tout cela ne fonctionne sans elle. Et c'est tout - votre application de démarrage Spring intercepte désormais toutes les exceptions, y compris les 404, dans la classe de gestionnaire ci-dessus et vous pouvez les utiliser à votre guise.

Un dernier point - il ne semble pas y avoir de moyen de faire en sorte que cela attrape les Erreurs levées. J'ai une idée farfelue d'utiliser des aspects pour détecter les erreurs et les transformer en Exceptions que le code ci-dessus peut ensuite traiter, mais je n'ai pas encore eu le temps d'essayer de les mettre en œuvre. J'espère que ça aide quelqu'un.

Tous commentaires/corrections/améliorations seront appréciés.

111
ogradyjd

Avec Spring Boot 1.4+, de nouvelles classes intéressantes facilitant la gestion des exceptions ont été ajoutées afin de supprimer le code standard.

Un nouveau @RestControllerAdvice est fourni pour la gestion des exceptions. Il combine @ControllerAdvice et @ResponseBody. Vous pouvez supprimer le @ResponseBody sur la méthode @ExceptionHandler lorsque vous utilisez cette nouvelle annotation.

c'est à dire. 

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(value = { Exception.class })
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiErrorResponse unknownException(Exception ex, WebRequest req) {
        return new ApiErrorResponse(...);
    }
}

Pour gérer les erreurs 404, l'ajout de l'annotation @EnableWebMvc et des éléments suivants dans application.properties était suffisant:
spring.mvc.throw-exception-if-no-handler-found=true

Vous pouvez trouver et jouer avec les sources ici:
https://github.com/magiccrafter/spring-boot-exception-handling

34
magiccrafter

Je pense que ResponseEntityExceptionHandler répond à vos exigences. Un exemple de code pour HTTP 400:

@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

  @ResponseStatus(value = HttpStatus.BAD_REQUEST)
  @ExceptionHandler({HttpMessageNotReadableException.class, MethodArgumentNotValidException.class,
      HttpRequestMethodNotSupportedException.class})
  public ResponseEntity<Object> badRequest(HttpServletRequest req, Exception exception) {
    // ...
  }
}

Vous pouvez vérifier ceci poster

23
Efe Kahraman

Qu'en est-il de ce code? J'utilise un mappage de demande de secours pour intercepter les erreurs 404.

@Controller
@ControllerAdvice
public class ExceptionHandlerController {

    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception ex) {
        //If exception has a ResponseStatus annotation then use its response code
        ResponseStatus responseStatusAnnotation = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);

        return buildModelAndViewErrorPage(request, response, ex, responseStatusAnnotation != null ? responseStatusAnnotation.value() : HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @RequestMapping("*")
    public ModelAndView fallbackHandler(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return buildModelAndViewErrorPage(request, response, null, HttpStatus.NOT_FOUND);
    }

    private ModelAndView buildModelAndViewErrorPage(HttpServletRequest request, HttpServletResponse response, Exception ex, HttpStatus httpStatus) {
        response.setStatus(httpStatus.value());

        ModelAndView mav = new ModelAndView("error.html");
        if (ex != null) {
            mav.addObject("title", ex);
        }
        mav.addObject("content", request.getRequestURL());
        return mav;
    }

}
13
Ludovic Martin

Bien qu’il s’agisse d’une question plus ancienne, j’aimerais faire part de mes réflexions à ce sujet. J'espère que cela sera utile à certains d'entre vous.

Je suis en train de construire une API REST qui utilise Spring Boot 1.5.2.RELEASE avec Spring Framework 4.3.7.RELEASE. J'utilise l'approche de configuration Java (par opposition à la configuration XML). De plus, mon projet utilise un mécanisme global de gestion des exceptions utilisant l'annotation @RestControllerAdvice (voir plus bas).

Mon projet a les mêmes exigences que le vôtre: je souhaite que mon API REST renvoie un HTTP 404 Not Found avec une charge JSON associée dans la réponse HTTP au client de l'API lorsqu'il tente d'envoyer une demande à une URL inexistante. Dans mon cas, la charge JSON ressemble à ceci (ce qui diffère clairement de la valeur par défaut de Spring Boot, btw.):

{
    "code": 1000,
    "message": "No handler found for your request.",
    "timestamp": "2017-11-20T02:40:57.628Z"
}

Je l'ai finalement fait fonctionner. Voici les tâches principales que vous devez faire en bref:

  • Assurez-vous que la variable NoHandlerFoundException est générée si les clients de l'APIcall sont des URL pour lesquelles aucune méthode de gestionnaire n'existe (voir l'étape 1 ci-dessous).
  • Créez une classe d'erreur personnalisée (dans mon cas, ApiError) contenant toutes les données à renvoyer au client de l'API (voir l'étape 2).
  • Créez un gestionnaire d'exceptions qui réagit sur la NoHandlerFoundException Et renvoie un message d'erreur approprié au client de l'API (voir l'étape 3).
  • Ecrivez un test et assurez-vous que cela fonctionne (voir étape 4).

Ok, passons maintenant aux détails:

Étape 1: Configurez application.properties

J'ai dû ajouter les deux paramètres de configuration suivants au fichier application.properties du projet:

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

Cela permet de s'assurer que la variable NoHandlerFoundException est émise dans les cas où un client tente d'accéder à une URL pour laquelle il n'existe aucune méthode de contrôleur capable de gérer la demande.

Étape 2: Créer une classe pour les erreurs d'API

J'ai fait un cours similaire à celui suggéré dans cet article sur le blog de Eugen Paraschiv. Cette classe représente une erreur d'API. Ces informations sont envoyées au client dans le corps de la réponse HTTP en cas d'erreur.

public class ApiError {

    private int code;
    private String message;
    private Instant timestamp;

    public ApiError(int code, String message) {
        this.code = code;
        this.message = message;
        this.timestamp = Instant.now();
    }

    public ApiError(int code, String message, Instant timestamp) {
        this.code = code;
        this.message = message;
        this.timestamp = timestamp;
    }

    // Getters and setters here...
}

Étape 3: Créer/configurer un gestionnaire d'exception global

J'utilise la classe suivante pour gérer les exceptions (par souci de simplicité, j'ai supprimé les instructions d'importation, le code de journalisation et certains autres éléments de code non pertinents):

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ApiError noHandlerFoundException(
            NoHandlerFoundException ex) {

        int code = 1000;
        String message = "No handler found for your request.";
        return new ApiError(code, message);
    }

    // More exception handlers here ...
}

Étape 4: écrivez un test

Je veux m'assurer que l'API renvoie toujours les messages d'erreur corrects au client appelant, même en cas d'échec. Ainsi, j'ai écrit un test comme celui-ci:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SprintBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ActiveProfiles("dev")
public class GlobalExceptionHandlerIntegrationTest {

    public static final String ISO8601_DATE_REGEX =
        "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$";

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser(roles = "DEVICE_SCAN_HOSTS")
    public void invalidUrl_returnsHttp404() throws Exception {
        RequestBuilder requestBuilder = getGetRequestBuilder("/does-not-exist");
        mockMvc.perform(requestBuilder)
            .andExpect(status().isNotFound())
            .andExpect(jsonPath("$.code", is(1000)))
            .andExpect(jsonPath("$.message", is("No handler found for your request.")))
            .andExpect(jsonPath("$.timestamp", RegexMatcher.matchesRegex(ISO8601_DATE_REGEX)));
    }

    private RequestBuilder getGetRequestBuilder(String url) {
        return MockMvcRequestBuilders
            .get(url)
            .accept(MediaType.APPLICATION_JSON);
    }

L'annotation @ActiveProfiles("dev") peut être laissée. Je ne l'utilise que lorsque je travaille avec des profils différents. La RegexMatcher est une coutume Hamcrest matcher que j'utilise pour mieux gérer les champs d'horodatage. Voici le code (je l'ai trouvé ici ):

public class RegexMatcher extends TypeSafeMatcher<String> {

    private final String regex;

    public RegexMatcher(final String regex) {
        this.regex = regex;
    }

    @Override
    public void describeTo(final Description description) {
        description.appendText("matches regular expression=`" + regex + "`");
    }

    @Override
    public boolean matchesSafely(final String string) {
        return string.matches(regex);
    }

    // Matcher method you can call on this matcher class
    public static RegexMatcher matchesRegex(final String string) {
        return new RegexMatcher(regex);
    }
}

Quelques notes supplémentaires de ma part:

  • Dans beaucoup d'autres publications sur StackOverflow, des personnes ont suggéré de définir l'annotation @EnableWebMvc. Ce n'était pas nécessaire dans mon cas.
  • Cette approche fonctionne bien avec MockMvc (voir le test ci-dessus).
13
André Gasser

Par défaut, Spring Boot donne à JSON des détails sur l'erreur.

curl -v localhost:8080/greet | json_pp
[...]
< HTTP/1.1 400 Bad Request
[...]
{
   "timestamp" : 1413313361387,
   "exception" : "org.springframework.web.bind.MissingServletRequestParameterException",
   "status" : 400,
   "error" : "Bad Request",
   "path" : "/greet",
   "message" : "Required String parameter 'name' is not present"
}

Cela fonctionne également pour tout type d'erreurs de mappage de demandes. Consultez cet article http://www.jayway.com/2014/10/19/spring-boot-error-responses/

Si vous voulez créer, connectez-le à NoSQL. Vous pouvez créer @ControllerAdvice dans lequel vous voudriez vous connecter puis relancer l'exception. Il existe des exemples dans la documentation https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

5
PaintedRed

Pour les contrôleurs REST, je recommanderais d'utiliser Zalando Problem Spring Web.

https://github.com/zalando/problem-spring-web

Si Spring Boot vise à intégrer une configuration automatique, cette bibliothèque en fait plus pour la gestion des exceptions. Il vous suffit d'ajouter la dépendance:

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>problem-spring-web</artifactId>
    <version>LATEST</version>
</dependency>

Et ensuite, définissez un ou plusieurs traits de conseil pour vos exceptions (ou utilisez ceux fournis par défaut)

public interface NotAcceptableAdviceTrait extends AdviceTrait {

    @ExceptionHandler
    default ResponseEntity<Problem> handleMediaTypeNotAcceptable(
            final HttpMediaTypeNotAcceptableException exception,
            final NativeWebRequest request) {
        return Responses.create(Status.NOT_ACCEPTABLE, exception, request);
    }

}

Ensuite, vous pouvez définir les conseils du contrôleur pour la gestion des exceptions comme suit:

@ControllerAdvice
class ExceptionHandling implements MethodNotAllowedAdviceTrait, NotAcceptableAdviceTrait {

}
2
JeanValjean

@RestControllerAdvice est une nouvelle fonctionnalité de Spring Framework 4.3 permettant de gérer Exception avec RestfulApi à l'aide d'une solution intersectorielle:

 package com.khan.vaquar.exception;

import javax.servlet.http.HttpServletRequest;

import org.owasp.esapi.errors.IntrusionException;
import org.owasp.esapi.errors.ValidationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.khan.vaquar.domain.ErrorResponse;

/**
 * Handles exceptions raised through requests to spring controllers.
 **/
@RestControllerAdvice
public class RestExceptionHandler {

    private static final String TOKEN_ID = "tokenId";

    private static final Logger log = LoggerFactory.getLogger(RestExceptionHandler.class);

    /**
     * Handles InstructionExceptions from the rest controller.
     * 
     * @param e IntrusionException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = IntrusionException.class)
    public ErrorResponse handleIntrusionException(HttpServletRequest request, IntrusionException e) {       
        log.warn(e.getLogMessage(), e);
        return this.handleValidationException(request, new ValidationException(e.getUserMessage(), e.getLogMessage()));
    }

    /**
     * Handles ValidationExceptions from the rest controller.
     * 
     * @param e ValidationException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = ValidationException.class)
    public ErrorResponse handleValidationException(HttpServletRequest request, ValidationException e) {     
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);

        if (e.getUserMessage().contains("Token ID")) {
            tokenId = "<OMITTED>";
        }

        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(),
                                    e.getUserMessage());
    }

    /**
     * Handles JsonProcessingExceptions from the rest controller.
     * 
     * @param e JsonProcessingException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = JsonProcessingException.class)
    public ErrorResponse handleJsonProcessingException(HttpServletRequest request, JsonProcessingException e) {     
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(),
                                    e.getOriginalMessage());
    }

    /**
     * Handles IllegalArgumentExceptions from the rest controller.
     * 
     * @param e IllegalArgumentException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = IllegalArgumentException.class)
    public ErrorResponse handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = UnsupportedOperationException.class)
    public ErrorResponse handleUnsupportedOperationException(HttpServletRequest request, UnsupportedOperationException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    /**
     * Handles MissingServletRequestParameterExceptions from the rest controller.
     * 
     * @param e MissingServletRequestParameterException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ErrorResponse handleMissingServletRequestParameterException( HttpServletRequest request, 
                                                                        MissingServletRequestParameterException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    /**
     * Handles NoHandlerFoundExceptions from the rest controller.
     * 
     * @param e NoHandlerFoundException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = NoHandlerFoundException.class)
    public ErrorResponse handleNoHandlerFoundException(HttpServletRequest request, NoHandlerFoundException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.NOT_FOUND.value(), 
                                    e.getClass().getSimpleName(), 
                                    "The resource " + e.getRequestURL() + " is unavailable");
    }

    /**
     * Handles all remaining exceptions from the rest controller.
     * 
     * This acts as a catch-all for any exceptions not handled by previous exception handlers.
     * 
     * @param e Exception
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public ErrorResponse handleException(HttpServletRequest request, Exception e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.error(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.INTERNAL_SERVER_ERROR.value(), 
                                    e.getClass().getSimpleName(), 
                                    "An internal error occurred");
    }   

}
1
vaquar khan

Pour les personnes qui souhaitent répondre en fonction du code de statut http, vous pouvez utiliser la méthode ErrorController:

@Controller
public class CustomErrorController extends BasicErrorController {

    public CustomErrorController(ServerProperties serverProperties) {
        super(new DefaultErrorAttributes(), serverProperties.getError());
    }

    @Override
    public ResponseEntity error(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status.equals(HttpStatus.INTERNAL_SERVER_ERROR)){
            return ResponseEntity.status(status).body(ResponseBean.SERVER_ERROR);
        }else if (status.equals(HttpStatus.BAD_REQUEST)){
            return ResponseEntity.status(status).body(ResponseBean.BAD_REQUEST);
        }
        return super.error(request);
    }
}

La ResponseBean ici est mon pojo personnalisé pour la réponse.

0
Lym Zoy

La solution avec dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); et @EnableWebMvc @ControllerAdvice.__ a fonctionné pour moi avec Spring Boot 1.3.1 alors qu'elle ne fonctionnait pas sur 1.2.7

0
Dennis R