it-swarm.com.de

Spring Boot REST Service-Ausnahmebehandlung

Ich versuche, einen großen REST Services-Server einzurichten. Wir verwenden Spring Boot 1.2.1 Spring 4.1.5 und Java 8. Unsere Controller implementieren @RestController und die Standardanmerkungen @RequestMapping.

Mein Problem ist, dass Spring Boot eine Standardumleitung für Controller-Ausnahmen auf /error einrichtet. Aus den Dokumenten:

Spring Boot bietet standardmäßig eine/error-Zuordnung, die alle Fehler auf vernünftige Weise behandelt, und sie wird als "globale" Fehlerseite im Servlet-Container registriert. 

Nach Jahren der Erstellung von REST -Anwendungen mit Node.js ist dies für mich alles andere als sinnvoll. Jede Ausnahme, die ein Serviceendpunkt generiert, sollte in der Antwort zurückgegeben werden. Ich kann nicht verstehen, warum Sie eine Weiterleitung an einen Angular- oder JQuery SPA-Verbraucher senden, der nur nach einer Antwort sucht und bei einer Weiterleitung keine Maßnahmen ergreifen kann oder will.

Ich möchte einen globalen Fehlerbehandler einrichten, der eine Ausnahme annehmen kann - entweder absichtlich aus einer Anforderungszuordnungsmethode geworfen oder automatisch von Spring generiert (404, wenn keine Handlermethode für die Anforderungspfadsignatur gefunden wird) und einen Wert zurückgeben Standardmäßig formatierte Fehlerantwort (400, 500, 503, 404) an den Client ohne MVC-Weiterleitungen. Insbesondere nehmen wir den Fehler auf, protokollieren ihn mit einer UUID in NoSQL und geben dann den richtigen HTTP-Fehlercode mit der UUID des Protokolleintrags im JSON-Body an den Client zurück.

Die Dokumente waren vage, wie dies zu tun ist. Es scheint mir, dass Sie entweder Ihre eigene ErrorController - Implementierung erstellen oder ControllerAdvice auf eine Art und Weise verwenden müssen, aber alle Beispiele, die ich gesehen habe, beinhalten immer noch das Weiterleiten der Antwort auf eine Art Fehlerzuordnung, die hilft nicht Andere Beispiele legen nahe, dass Sie jeden Ausnahmetyp auflisten müssen, den Sie behandeln möchten, anstatt nur "Throwable" aufzulisten und alles zu erhalten.

Kann mir jemand sagen, was ich vermisst habe, oder mich in die richtige Richtung weisen, wie man das macht, ohne die Kette vorzuschlagen, mit der Node.js einfacher umgehen könnte? 

131
ogradyjd

Neue Antwort (2016-04-20)

Spring Boot 1.3.1.RELEASE verwenden

Neuer Schritt 1 - Es ist einfach und weniger aufdringlich, den Eigenschaften von application.properties die folgenden Eigenschaften hinzuzufügen:

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

Viel einfacher als das Ändern der vorhandenen DispatcherServlet-Instanz (siehe unten)! - JO '

Wenn Sie mit einer vollständigen RESTful-Anwendung arbeiten, ist es sehr wichtig, die automatische Zuordnung statischer Ressourcen zu deaktivieren. Wenn Sie die standardmäßige Konfiguration von Spring Boot für die Verarbeitung statischer Ressourcen verwenden, wird der Ressourcen-Handler die Anforderung verarbeiten (diese wird zuletzt geordnet und/zugeordnet. ** Dies bedeutet, dass alle Anforderungen übernommen werden, die von keinem anderen Handler in der Anwendung bearbeitet wurden. Das Dispatcher-Servlet hat also keine Chance, eine Ausnahme auszulösen.


Neue Antwort (2015-12-04)

Spring Boot 1.2.7.RELEASE verwenden

Neuer Schritt 1 - Ich habe eine weit weniger aufdringliche Methode gefunden, das Flag "throExceptionIfNoHandlerFound" zu setzen. Ersetzen Sie den folgenden DispatcherServlet-Ersetzungscode (Schritt 1) ​​durch diesen in Ihrer Anwendungsinitialisierungsklasse:

@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);
    }

In diesem Fall setzen wir das Flag für das vorhandene DispatcherServlet, wodurch die automatische Konfiguration durch das Spring Boot-Framework beibehalten wird. 

Eine weitere Sache habe ich gefunden - die Annotation @EnableWebMvc ist für Spring Boot tödlich. Ja, diese Annotation ermöglicht es beispielsweise, alle Controller-Ausnahmen wie unten beschrieben abzufangen, aber sie bringt auch eine Menge der hilfreichen automatischen Konfiguration mit sich, die Spring Boot normalerweise bereitstellt. Verwenden Sie diese Anmerkung mit äußerster Vorsicht, wenn Sie Spring Boot verwenden.


Ursprüngliche Antwort:

Nach vielem Nachforschen und Nachverfolgen der hier veröffentlichten Lösungen (danke für die Hilfe!) Und nicht allzu langer Laufzeitverfolgung in den Spring-Code, habe ich endlich eine Konfiguration gefunden, die alle Ausnahmen behandelt (keine Fehler, aber lesen Sie weiter). einschließlich 404s.

Schritt 1 - SpringBoot soll die Verwendung von MVC für Situationen "Handler nicht gefunden" einstellen. Wir möchten, dass Spring eine Ausnahme auslöst, anstatt dem Client eine Ansicht zurückzugeben, die auf "/ error" umleitet. Dazu benötigen Sie einen Eintrag in einer Ihrer Konfigurationsklassen:

// 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;
    }
}

Der Nachteil ist, dass es das Standard-Dispatcher-Servlet ersetzt. Dies war bisher noch kein Problem für uns, ohne dass Nebenwirkungen oder Ausführungsprobleme auftauchten. Wenn Sie aus anderen Gründen etwas anderes mit dem Dispatcher-Servlet machen möchten, können Sie dies hier tun.

Schritt 2 - Wenn der Spring-Boot jetzt eine Ausnahme auslöst, wenn kein Handler gefunden wird, kann diese Ausnahme mit allen anderen in einem vereinheitlichten Ausnahmehandler behandelt werden:

@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);
    }
    ...
}

Beachten Sie, dass ich denke, dass die Anmerkung "@EnableWebMvc" hier von Bedeutung ist. Es scheint, dass nichts davon ohne es funktioniert. Und das ist es - Ihre Spring-Boot-App fängt jetzt alle Ausnahmen, einschließlich 404, in der obigen Handler-Klasse, und Sie können sie nach Belieben verwenden.

Ein letzter Punkt - es scheint keine Möglichkeit zu geben, diese Fehler zu beheben. Ich habe die verrückte Idee, mit Aspekten Fehler zu fangen und sie in Ausnahmen umzuwandeln, mit denen der obige Code dann umgehen kann, aber ich hatte noch keine Zeit, um das tatsächlich zu implementieren. Hoffe das hilft jemandem.

Alle Kommentare/Korrekturen/Verbesserungen werden geschätzt.

111
ogradyjd

Mit Spring Boot 1.4+ wurden neue Cool-Klassen für eine einfachere Ausnahmebehandlung hinzugefügt, mit deren Hilfe der Boilerplate-Code entfernt werden kann.

Für die Ausnahmebehandlung wird ein neuer @RestControllerAdvice bereitgestellt, der aus einer Kombination aus @ControllerAdvice und @ResponseBody besteht. Sie können den @ResponseBody von der @ExceptionHandler-Methode entfernen, wenn Sie diese neue Anmerkung verwenden.

d.h. 

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

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

Für die Behandlung von 404-Fehlern war es ausreichend, @EnableWebMvc-Annotation und Folgendes zu application.properties hinzuzufügen:
spring.mvc.throw-exception-if-no-handler-found=true

Sie können die Quellen hier finden und damit spielen:
https://github.com/magiccrafter/spring-boot-exception-handling

34
magiccrafter

Ich denke, ResponseEntityExceptionHandler erfüllt Ihre Anforderungen. Ein Beispielcode für 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) {
    // ...
  }
}

Sie können dieses post überprüfen

23
Efe Kahraman

Was ist mit diesem Code? Ich verwende eine Fallback-Anforderungszuordnung, um 404-Fehler zu finden.

@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

Obwohl dies eine ältere Frage ist, möchte ich meine Gedanken dazu teilen. Ich hoffe, dass es einigen von euch hilfreich sein wird.

Ich baue gerade eine REST - API, die Spring Boot 1.5.2.RELEASE mit Spring Framework 4.3.7.RELEASE verwendet. Ich verwende den Java Config-Ansatz (im Gegensatz zur XML-Konfiguration). Außerdem verwendet mein Projekt einen globalen Ausnahmebehandlungsmechanismus unter Verwendung der Annotation @RestControllerAdvice (siehe unten).

Mein Projekt hat die gleichen Anforderungen wie Ihr Projekt: Ich möchte, dass meine REST - API einen HTTP 404 Not Found mit einer begleitenden JSON-Nutzlast in der HTTP-Antwort an den API-Client zurückgibt, wenn versucht wird, eine Anforderung an eine nicht vorhandene URL zu senden. In meinem Fall sieht die JSON-Payload folgendermaßen aus (was sich deutlich vom Spring Boot-Standard unterscheidet, übrigens).

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

Ich habe es endlich geschafft. Hier sind die wichtigsten Aufgaben, die Sie in Kürze tun müssen:

  • Stellen Sie sicher, dass die Variable NoHandlerFoundException ausgegeben wird, wenn API-Clientscall URLS aufgerufen wird, für die keine Handler-Methode vorhanden ist (siehe Schritt 1 unten).
  • Erstellen Sie eine benutzerdefinierte Fehlerklasse (in meinem Fall ApiError), die alle Daten enthält, die an den API-Client zurückgegeben werden sollen (siehe Schritt 2).
  • Erstellen Sie einen Ausnahmehandler, der auf die NoHandlerFoundException Reagiert und eine entsprechende Fehlermeldung an den API-Client zurückgibt (siehe Schritt 3).
  • Schreiben Sie einen Test und stellen Sie sicher, dass es funktioniert (siehe Schritt 4).

Ok, nun zu den Details:

Schritt 1: application.properties konfigurieren

Ich musste der application.properties-Datei des Projekts die folgenden beiden Konfigurationseinstellungen hinzufügen:

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

Dies stellt sicher, dass die Variable NoHandlerFoundException ausgelöst wird, wenn ein Client versucht, auf eine URL zuzugreifen, für die keine Controller-Methode vorhanden ist, die die Anforderung verarbeiten könnte.

Schritt 2: Klasse für API-Fehler erstellen

Ich habe eine Klasse gemacht, die der in diesem Artikel in Eugen Paraschivs Blog vorgeschlagenen ähnelt. Diese Klasse repräsentiert einen API-Fehler. Diese Informationen werden im Fehlercode an den Client im HTTP-Antworttext gesendet.

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...
}

Schritt 3: Erstellen/Konfigurieren eines globalen Ausnahmebehandlers

Ich verwende die folgende Klasse, um Ausnahmen zu behandeln (zur Vereinfachung habe ich Importanweisungen, Protokollierungscode und einige andere, nicht relevante Teile des Codes entfernt):

@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 ...
}

Schritt 4: Schreiben Sie einen Test

Ich möchte sicherstellen, dass die API auch im Fehlerfall immer die richtigen Fehlermeldungen an den aufrufenden Client zurückgibt. So schrieb ich einen Test wie folgt:

@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);
    }

Die @ActiveProfiles("dev")-Anmerkung kann weggelassen werden. Ich verwende es nur, wenn ich mit verschiedenen Profilen arbeite. Die Variable RegexMatcher ist ein benutzerdefinierter Hamcrest-Matcher , mit dem Timestamp-Felder besser verarbeitet werden. Hier ist der Code (ich habe ihn hier gefunden):

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);
    }
}

Einige weitere Anmerkungen von meiner Seite:

  • In vielen anderen Beiträgen in StackOverflow wurde vorgeschlagen, die Annotation @EnableWebMvc festzulegen. Dies war in meinem Fall nicht notwendig.
  • Dieser Ansatz funktioniert gut mit MockMvc (siehe Test oben).
13
André Gasser

Standardmäßig gibt Spring Boot json Fehlerdetails an.

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"
}

Es funktioniert auch für alle Arten von Anforderungszuordnungsfehlern. Überprüfen Sie diesen Artikel http://www.jayway.com/2014/10/19/spring-boot-error-responses/

Wenn Sie erstellen möchten, loggen Sie sich in NoSQL ein. Sie können @ControllerAdvice erstellen, wo Sie es protokollieren und dann die Ausnahme erneut auslösen. Es gibt ein Beispiel in der Dokumentation https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

5
PaintedRed

Für REST - Controller würde ich empfehlen, Zalando Problem Spring Web zu verwenden.

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

Wenn Spring Boot einige Autokonfiguration einbetten möchte, kann diese Bibliothek mehr zur Ausnahmebehandlung beitragen. Sie müssen nur die Abhängigkeit hinzufügen:

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

Definieren Sie dann eine oder mehrere Ratschläge für Ihre Ausnahmen (oder verwenden Sie die standardmäßig bereitgestellten).

public interface NotAcceptableAdviceTrait extends AdviceTrait {

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

}

Dann können Sie die Controller-Hinweise für die Ausnahmebehandlung definieren als:

@ControllerAdvice
class ExceptionHandling implements MethodNotAllowedAdviceTrait, NotAcceptableAdviceTrait {

}
2
JeanValjean

@RestControllerAdvice ist eine neue Funktion von Spring Framework 4.3, um Ausnahmen mit RestfulApi durch eine Querschnittslösung zu behandeln:

 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

Für Personen, die entsprechend dem http-Statuscode antworten möchten, können Sie die ErrorController-Methode verwenden:

@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);
    }
}

Die ResponseBean ist hier mein benutzerdefiniertes Antwortsymbol.

0
Lym Zoy

Lösung mit dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); und @EnableWebMvc @ControllerAdvice Arbeitete für mich mit Spring Boot 1.3.1, während an 1.2.7 nicht gearbeitet wurde

0
Dennis R