Spring MVC, Migrieren @ExceptionHandler zu HandlerExceptionResolver für einen RESTful-Dienst
Hintergrund
Habe ich eine Fehlermeldung Klasse:
@XmlRootElement
public class ErrorMessage {
private String message;
public ErrorMessage() {
}
public ErrorMessage(String message) {
this.message = message;
}
public String getError() {
return message;
}
public void setError(String message) {
this.message = message;
}
}
Dieser Klasse zugewiesen wurde, als einen Rückgabewert an eine @ExceptionHandler in meinem Spring MVC REST-controller:
@ExceptionHandler
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
ErrorMessage handleException(RuntimeException e) {
return new ErrorMessage("something went wrong");
}
Wenn der client löst einen RuntimeException
nach vorheriger Anfrage mit application/json
als Accept
header, erhält er eine Antwort mit der richtigen status-code und eine passende JSON-Körper:
{"error":"something went wrong"}
Alternativ eine XML-Körper empfangen wird, wenn die Accept
header ist application/xml
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<errorMessage><error>something went wrong</error></errorMessage>
Problem
Nun, ich möchte generify diese Lösung durch die Implementierung eines HandlerExceptionResolver statt, so dass ich nicht kopieren /einfügen der @ExceptionHandler
zu jedem controller (oder erstellen Sie einen gemeinsamen "übergeordneten Steuerung", dass die anderen Controller erweitern können).
Jedoch die AbstractHandlerExceptionResolver.doResolveException() Methode gibt eine ModelAndView
und nicht mein Anstand ErrorMessage
, so versuchte ich die folgenden:
public class RuntimeExceptionHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (ex instanceof RuntimeException) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
ModelAndView mav = new ModelAndView();
mav.addObject("error", "something went wrong");
return mav;
}
return null;
}
}
Beim Debuggen kann ich sehen, dass die mav.addObject()
- Methode aufgerufen wird. Die Antwort auf die client-Seite hat den erwarteten status-code, aber der content-type ist text/html
mit html in den Körper, sondern als JSON-oder XML-Inhalte, die angegeben wurde, durch die Accept
- header in der ursprünglichen Anfrage.
(Seite beachten Sie, dass die eigentliche Ausnahme, Antwort-code und text-Nachricht in dem Beispiel oben ist nicht wichtig, Sie dienen lediglich als einfaches Beispiel.)
Spring version: 3.1.1.RELEASE
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bekommen
@ExceptionHandler
s content negotiation verwenden, dieAnnotationMethodHandlerExceptionresolver
hat einesetMessageConverters()
Methode, die bereitgestellt werden muss, mit der Nachricht-Wandler, z.B.:Aber da Sie verwenden eine benutzerdefinierte Methode, werden Sie wahrscheinlich haben, um diese Funktionalität zu implementieren selbst. Der einfachste Weg ist wahrscheinlich zu
Ctrl-C Ctrl-V
von derAnnotationMethodHandlerExceptionresolver
Quelle, insbesondere diehandleResponseBody()
Methode.AnnotationMethodHandlerExceptionResolver
.@ExceptionHandler
s ohne Angabe der Konverter explizit, aber das könnte sich abhängig von einem anderen Aspekt meiner config. LeidersetMessageConverters()
scheint nicht Teil einer Schnittstelle sein, so ist es unwahrscheinlich, dass die Meldung Konverter wird automatisch injiziert werden. Auch Hallo aus Malmö.Ich habe einige Zeit damit verbracht Erforschung der Materie und ich habe geschrieben eine blog-post, in dem ich eine Lösung für das problem.
Update: Wenn Sie mit Spring 3.2, können Sie die Vorteile der @ControllerAdvice annotation. Mehr details finden Sie in meinem zweiter blog-post.