Ich verwende Spring MVC für eine einfache JSON-API mit einem @ResponseBody
basierten Ansatz wie dem folgenden. (Ich habe bereits eine Service-Schicht, die JSON direkt produziert.)
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
// TODO: how to respond with e.g. 400 "bad request"?
}
return json;
}
Die Frage ist im gegebenen Szenario, was die einfachste und sauberste Möglichkeit ist, mit einem HTTP 400-Fehler zu antworten .
Ich bin auf Ansätze gestoßen wie:
return new ResponseEntity(HttpStatus.BAD_REQUEST);
... aber ich kann es hier nicht verwenden, da der Rückgabetyp meiner Methode String und nicht ResponseEntity ist.
java
spring
spring-mvc
http-error
Jonik
quelle
quelle
ResponseEntity
. Dies funktioniert gut und ist nur eine einfache Änderung des Originalcodes - danke!So etwas sollte funktionieren, ich bin mir nicht sicher, ob es einen einfacheren Weg gibt oder nicht:
quelle
body
undrequest
Parameter entfernt werden.)Nicht unbedingt die kompakteste Art dies zu tun, aber IMO ziemlich sauber
Bearbeiten Sie können @ResponseBody in der Exception-Handler-Methode verwenden, wenn Sie Spring 3.1+ verwenden. Andernfalls verwenden Sie a
ModelAndView
oder etwas.https://jira.springsource.org/browse/SPR-6902
quelle
ERROR org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: public controller.TestController$MyError controller.TestController.handleException(controller.TestController$BadThingException) org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
Fehlt etwas in der Antwort?javax.validation.ValidationException
stattdessen. (Frühling 3.1.4)Ich würde die Implementierung leicht ändern:
Zuerst erstelle ich ein
UnknownMatchException
:Beachten Sie die Verwendung von @ResponseStatus , die von Spring's erkannt wird
ResponseStatusExceptionResolver
. Wenn die Ausnahme ausgelöst wird, wird eine Antwort mit dem entsprechenden Antwortstatus erstellt. (Ich habe mir auch erlaubt, den Statuscode zu ändern,404 - Not Found
den ich für diesen Anwendungsfall besser finde, aber Sie können sich daran halten,HttpStatus.BAD_REQUEST
wenn Sie möchten.)Als nächstes würde ich das ändern
MatchService
, um die folgende Signatur zu haben:Schließlich würde ich den Controller aktualisieren und an Spring delegieren,
MappingJackson2HttpMessageConverter
um die JSON-Serialisierung automatisch durchzuführen (sie wird standardmäßig hinzugefügt, wenn Sie Jackson zum Klassenpfad hinzufügen und entweder@EnableWebMvc
oder<mvc:annotation-driven />
zu Ihrer Konfiguration hinzufügen , siehe Referenzdokumente ):Beachten Sie, dass es sehr häufig vorkommt, die Domänenobjekte von den Ansichtsobjekten oder DTO-Objekten zu trennen. Dies kann leicht erreicht werden, indem eine kleine DTO-Factory hinzugefügt wird, die das serialisierbare JSON-Objekt zurückgibt:
quelle
Match
und ein anderes Objekt ist.Hier ist ein anderer Ansatz. Erstellen Sie eine benutzerdefinierte
Exception
Annotation mit@ResponseStatus
, wie die folgende.Und werfen Sie es, wenn nötig.
Lesen Sie die Spring-Dokumentation hier: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-annotated-exceptions .
quelle
Wie in einigen Antworten erwähnt, besteht die Möglichkeit, für jeden HTTP-Status, den Sie zurückgeben möchten, eine Ausnahmeklasse zu erstellen. Ich mag die Idee nicht, für jedes Projekt eine Klasse pro Status erstellen zu müssen. Hier ist, was ich mir stattdessen ausgedacht habe.
Kommen wir zum Code
Dann erstelle ich eine Controller-Beratungsklasse
Um es zu benutzen
http://javaninja.net/2016/06/throwing-exceptions-messages-spring-mvc-controller/
quelle
Ich verwende dies in meiner Spring Boot-Anwendung
quelle
Am einfachsten ist es, einen zu werfen
ResponseStatusException
quelle
Bei Spring Boot bin ich mir nicht ganz sicher, warum dies notwendig war (ich habe den
/error
Fallback erhalten, obwohl er@ResponseBody
auf einem definiert wurde@ExceptionHandler
), aber Folgendes hat an sich nicht funktioniert:Es gab immer noch eine Ausnahme, anscheinend, weil keine produzierbaren Medientypen als Anforderungsattribut definiert wurden:
Also habe ich sie hinzugefügt.
Und das brachte mich dazu, einen "unterstützten kompatiblen Medientyp" zu haben, aber dann funktionierte es immer noch nicht, weil mein
ErrorMessage
Fehler war:JacksonMapper hat es nicht als "konvertierbar" behandelt, daher musste ich Getter / Setter hinzufügen, und ich habe auch
@JsonProperty
Anmerkungen hinzugefügtDann erhielt ich meine Nachricht wie beabsichtigt
quelle
Sie können auch nur
throw new HttpMessageNotReadableException("error description")
von der Standardfehlerbehandlung von Spring profitieren .Genau wie bei diesen Standardfehlern wird jedoch kein Antworttext festgelegt.
Ich finde diese nützlich, wenn Anfragen abgelehnt werden, die vernünftigerweise nur von Hand hergestellt werden konnten, was möglicherweise auf eine böswillige Absicht hinweist, da sie die Tatsache verschleiern, dass die Anfrage aufgrund einer tieferen, benutzerdefinierten Validierung und ihrer Kriterien abgelehnt wurde.
Hth, dtk
quelle
HttpMessageNotReadableException("error description")
ist veraltet.Ein anderer Ansatz ist die Verwendung
@ExceptionHandler
mit@ControllerAdvice
allen Ihren Handler in der gleichen Klasse zu zentralisieren, wenn nicht Sie die Handler Methoden in jedem Controller setzen müssen Sie eine Ausnahme verwalten möchten.Ihre Handlerklasse:
Ihre benutzerdefinierte Ausnahme:
Jetzt können Sie Ausnahmen von jedem Ihrer Controller auslösen und andere Handler in Ihrer Beratungsklasse definieren.
quelle
Ich denke, dieser Thread hat tatsächlich die einfachste und sauberste Lösung, die die von Spring bereitgestellten JSON-Martialing-Tools nicht opfert:
https://stackoverflow.com/a/16986372/1278921
quelle