2013-04-30 19 views
24

Zastanawiam się, jak poprawnie wdrożyć Spring Controller, który ma służyć jako usługa REST. Szczególnie chciałbym spróbować uczynić interfejs możliwie jak najwierniejszym. Chciałbym również skorzystać z kodów błędów HTTP, aby moi klienci mogli odpowiednio działać.Sprężynowy kontroler serwisowy MVC z obsługą błędów wykonano poprawnie?

Zastanawiam się, jak wdrożyć moje metody, więc zwracają JSON, jeśli wszystko działa dobrze (w treści odpowiedzi) lub rzucić kod błędu http, jak również niestandardowy powód, dlaczego nie działa (może błędy, które przyszły z DAO lub bazy danych). Jednak nie jestem pewien, która z nich jest właściwa? Zwróć ciąg i dodaj wartości, aby powrócić do Modelu, lub zwróć HashMap i umieść tam moje rzeczy? lub zwrócić obiekty bezpośrednio? ale co wtedy, gdy wystąpi błąd i nie mogę zwrócić tej klasy? zamiast tego zwraca wartość null? Ja po 2-3 sposoby robi to, że można sobie wyobrazić:

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

czy raczej w ten sposób:

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

Zdaję sobie sprawę, kod nie jest „w porządku”, ale nie mogę dowiedzieć się, jak sprawiają, że tak musi być. Może niektóre odpowiedzi na pytania pomogłyby? Thx za wsparcie już

Odpowiedz

28

Możesz również złapać wyjątki dzięki @ExceptionHandler opatrzonym adnotacjami metos w kontrolerze odpoczynku.

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

to sprawi, że Twój kluczowy kontroler/logika biznesowa stanie się czystszy.

+0

Podoba mi się ten pomysł, właśnie to zrobiłem! Stworzyłem ressource błędów zgodnie z zaleceniami Bartka, a następnie wszystkie błędy w ctrl w tej metodzie. Prawdopodobnie mógłbym dalej generalizować i obsługiwać aplikacje błędów szeroko, ale krok po kroku. – pascalwhoop

+0

można utworzyć wiele wyjątków ExceptionHandlers w kontrolerze, dla każdego typu wyjątku. –

+2

znalazłem, że wydaje się być czystsze, jeśli mam tylko jeden wyjątkowy sposób na kontroler, zamiast całej ich tablicy, a następnie zadbać o sprawdzenie, który błąd został zgłoszony w ramach tego obsługi – pascalwhoop

16

Po pierwsze, myślę, że powinieneś zawsze zwrócić obiekt podczas zwracania JSON. Nawet gdy coś pójdzie nie tak.

Gdy coś pójdzie nie tak po prostu ustaw response.setStatus() i zwróć zasób opisujący błąd.

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

Zasób dostaje odcinkach, a wynik byłby

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

Korzystanie z Map będzie działać, ale chciałbym poinformować, aby napisać kilka klas zasobów, które określają przedmiot zostać zwrócone. Będą łatwiejsze do utrzymania. Maps nie oferują żadnej struktury, podczas gdy struktura jest bardzo ważną częścią podczas tworzenia usługi REST.

Nie sądzę, że powinieneś zwrócić zasób z osadzonym oryginalnym komunikatem wyjątku. Może potencjalnie wyciekać informacje, których nie chcesz, aby ktokolwiek zobaczył.

+0

Więc można powiedzieć, że mam główną klasę "returnRessource", z której wszystkie inne klasy, które zamierzam zwrócić, bez względu na to, czy błędy lub rzeczywiste wartości powinny dziedziczyć? W przeciwnym razie naprawdę nie rozumiem, jak masz zamiar przejść, jeśli masz metodę, powiedz "public User getUser() {...}" i to dmucha, nie możesz po prostu zwrócić innej klasy, musisz zwrócić klasę User. Czy myślisz, że powinien to być 'public Object getUser() {...}' ?? – pascalwhoop

+0

Powinienem także dodać, że zamierzam napisać punkt końcowy za pomocą Angular. Tutaj bardzo wygodnie działać zgodnie z kodami odpowiedzi http. jednak nadal zgadzam się, że obiekt json jest lepszy niż domyślna strona błędu tomcat. Jak mogę zwrócić obiekt, a nie metodę response.sendError? Mam na myśli, że wciąż mając kod błędu http set – pascalwhoop

+0

response.setStatus (statusCode) robi lewę ;-) –

8

można użyć @ExceptionHandler z @ControllerAdvice czeku to link

0

użycie klasy ResponseEntity wykorzystać błąd z kodem stanu HTTP.

można spróbować następujący kod:

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

Dodaj więcej objaśnień. – Max

+0

Przykro mi, ale nie próbuję dobrze formatować, ale spróbuj tego kodu -> '@RequestMapping (value ="/profile ", method = RequestMethod.GET) @ResponseBody @ResponseStatus (value = HttpStatus.OK) public ResponseEntity getUserProfile() { \t String userName = getUserAuthentication(). GetName(); \t \t if (StringUtils.isEmpty (nazwa użytkownika)) \t \t RestUtil.defaultJsonResponse (""); \t \t Użytkownik użytkownik = userService.getUserByUserNameWithCounters (userName); \t \t return RestUtil.getJsonResponse (new UserVO (użytkownik)); } ' –

0

Jeśli chcesz całe Wyjątek z StackTrace być transmitowane w kierunku klienta, jak @Bart że należy wysłać „ErrorResource” obiekt.

Biblioteka ma to off-the-shelf:

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

dodać go do projektu, a następnie po prostu dodać klasę "@ControllerAdvice" do fasoli, jak to wyjaśniono w project wiki.

To powinno dobrze poradzić sobie z błędami!

Powiązane problemy