it-roy-ru.com

Spring MVC Rest Service Controller с обработкой ошибок сделан правильно?

Мне было интересно, как правильно реализовать Spring Controller, который должен служить службой REST. Особенно я хочу попробовать сделать интерфейс как можно RESTful. Также я хотел бы использовать HTTP-коды ошибок, чтобы мои клиенты могли действовать соответственно.

Мне было интересно, как реализовать мои Методы, чтобы они возвращали JSON, если все работает нормально (в теле ответа), или отбрасывали код ошибки http, а также пользовательскую причину, по которой он не работал (возможно, ошибки, пришедшие из DAO или база данных). Однако я не уверен, какой из них правильный? вернуть строку и добавить значения, чтобы вернуться к модели, или вернуть HashMap и положить туда мои вещи? или вернуть объекты напрямую? но что, если произойдет ошибка, и я не смогу вернуть указанный класс? вместо этого вернуть null? Я выкладываю 2-3 способа сделать это, что я могу себе представить: 

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

Вернее так:

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

Я понимаю, что код не «просто правильный», но я не могу понять, как сделать его таким, каким он должен быть. Может быть, некоторые ответы помогут? Спасибо за поддержку уже

24
pascalwhoop

Вы также можете перехватывать исключения с помощью аннотированных методов @ExceptionHandler в вашем Rest Controller.

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

это сделает ваш аккуратный контроллер/бизнес-логику чище.

29
marco.eig

Во-первых, я думаю, что вы всегда должны возвращать объект при возврате JSON. Даже когда что-то идет ужасно неправильно.

Когда что-то идет не так, вы просто устанавливаете response.setStatus() и возвращаете ресурс, описывающий ошибку.

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

Ресурс сериализуется, и результат будет

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

Использование Map будет работать, но я бы посоветовал вам написать некоторые классы ресурсов, которые определяют возвращаемый объект. Их будет проще поддерживать. Maps не предлагает никакой структуры, в то время как структура является очень важной частью при создании службы REST. 

Я не думаю, что вы должны возвращать ресурс со встроенным необработанным сообщением об исключении. Это может привести к утечке информации, которую никто не хочет видеть.

16
Bart

вы можете использовать @ExceptionHandler с @ControllerAdvice проверить это ссылка

8
Bassem Reda Zohdy

используйте класс ResponseEntity для использования ошибки с кодом состояния http.

Вы можете попробовать следующий код:

@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

Если вы хотите, чтобы все ваше Exception с stackTrace передавалось вашему клиенту, как сказал @Bart, вы должны отправить объект «ErrorResource».

У библиотеки есть это в наличии:

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

добавьте его в свой проект, а затем просто добавьте класс "@ControllerAdvice" к своим bean-компонентам, как это объясняется в project wiki .

Это должно справиться с вашими ошибками!

0
zg2pro