it-swarm.com.de

Spring MVC Rest Service Controller mit Fehlerbehandlung richtig gemacht?

Ich habe mich gefragt, wie man einen Spring Controller korrekt implementiert, der als REST Dienst dienen soll. Ich möchte vor allem versuchen, die Schnittstelle so restlos wie möglich zu machen. Außerdem möchte ich HTTP-Fehlercodes verwenden, damit meine Clients entsprechend agieren können.

Ich habe mich gefragt, wie ich meine Methoden implementieren kann, also geben sie JSON zurück, wenn alles einwandfrei funktioniert (im Hauptteil der Antwort) oder werfen Sie einen http - Fehlercode sowie einen benutzerdefinierten Grund, warum es nicht funktionierte (möglicherweise Fehler, die vom DAO oder die Datenbank). Ich bin mir jedoch nicht sicher, welcher der richtige Weg ist? einen String zurückgeben und die Werte hinzufügen, um zu einem Modell zurückzukehren, oder eine HashMap zurückgeben und meine Sachen dort einfügen? oder die Objekte direkt zurücksenden? aber was dann, wenn ein Fehler auftritt und ich die besagte Klasse nicht zurückgeben kann? Stattdessen null zurückgeben? Ich poste 2-3 Möglichkeiten, die ich mir vorstellen könnte: 

@RequestMapping(value="/addUser", method= RequestMethod.POST)
public String addUser(@RequestBody User user, HttpServletResponse response, Model model) throws Exception{

    try{
        userService.addUser(user);
        model.addAttribute("user", userService.getUser(user.getUsername(), user.getPassword()));
        return "user";
    }catch(Exception e){
        model.addAttribute("error", e.toString());
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
        return "error";
    }
}

Oder eher so:

@RequestMapping(value="/addUser", method= RequestMethod.POST)
public @ResponseBody Map addUser(@RequestBody User user, HttpServletResponse response){
    Map map = new HashMap();
    try{
        userService.addUser(user);
        map.put("success", true);
        map.put("username", user.getUsername());
    }catch (KeyAlreadyExistsException e){
        map.put("success", false);
        map.put("Error", e.toString());
        response.sendError(HttpServletResponse.SC_FORBIDDEN, e.toString());
    }catch(Exception e){
        map.put("success", false);
        map.put("Error", e.toString());
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
    }
    finally {
        return map;
    }
}

Ich weiß, dass Code nicht "genau richtig" ist, aber ich kann nicht herausfinden, wie er so erstellt wird, wie er sein muss. Vielleicht würden einige Erfahrungsantworten helfen? Danke für die Unterstützung schon

24
pascalwhoop

Sie können Ihre Ausnahmen auch mit @ExceptionHandler kommentierten Methoden in Ihrem Rest Controller abfangen.

@ExceptionHandler(Exception.class)
@ResponseBody
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleException(Exception e) {
    return "return error object instead";
}

dadurch wird Ihr aktueller Controller/Ihre Geschäftslogik sauberer.

29
marco.eig

Erstens sollten Sie bei der Rückgabe von JSON immer ein Objekt zurückgeben. Auch wenn etwas schief geht.

Wenn etwas schief geht, setzen Sie einfach response.setStatus() und geben eine Ressource zurück, die den Fehler beschreibt.

public class ErrorResource implements Resource {
    private final int status;
    private final String message;

    public ErrorResource(int s, String m) {
        status = s;
        message = m;
    }

    public int getStatus() {
        return status;
    }

    public String getMessage() {
        return message;
    }
}

Die Ressource wird serialisiert und das Ergebnis wäre

{"status":500, "message":"Yay!"}

Die Verwendung einer Map wird funktionieren, aber ich möchte Ihnen raten, einige Ressourcenklassen zu schreiben, die das zurückgegebene Objekt definieren. Sie wären einfacher zu warten. Maps bietet keine Struktur an, während die Struktur beim Erstellen eines REST -Dienstes eine sehr wichtige Rolle spielt. 

Ich denke nicht, dass Sie eine Ressource mit der eingebetteten Ausnahmemeldung zurückgeben sollten. Dadurch können Informationen verloren gehen, die niemand sehen soll.

16
Bart

sie können @ExceptionHandler mit @ControllerAdvice verwenden, überprüfen Sie diesen link

8

verwenden Sie die ResponseEntity-Klasse, um einen Fehler mit dem HTTP-Statuscode auszunutzen.

Sie könnten den folgenden Code ausprobieren:

@RequestMapping(value = "/profile", method = RequestMethod.GET) 
@ResponseBody @ResponseStatus(value = HttpStatus.OK) 

public ResponseEntity<UserVO> getUserProfile() 
{ 
   string userName = getUserAuthentication().getName(); 
   if (StringUtils.isEmpty(userName)) RestUtil.defaultJsonResponse(""); 
   User user = userService.getUserByUserNameWithCounters(userName); 
   return RestUtil.getJsonResponse(new UserVO(user)); 
}
0
agus w

Wenn Sie möchten, dass Ihre gesamte Ausnahme mit stackTrace zu Ihrem Client übertragen wird, sollten Sie, wie @Bart sagte, ein "ErrorResource" -Objekt senden.

Eine Bibliothek hat es von der Stange:

<dependency>
  <groupId>com.github.zg2pro</groupId>
  <artifactId>spring-rest-basis</artifactId>
  <version>0.2</version>
</dependency>

fügen Sie es Ihrem Projekt hinzu und fügen Sie einfach eine "@ControllerAdvice" -Klasse zu Ihren Beans hinzu, wie im Projekt-Wiki erklärt.

Das sollte deine Fehler gut behandeln!

0
zg2pro