Java Spring MVC Rest服务控制器的错误处理是否正确?

Java Spring MVC Rest服务控制器的错误处理是否正确?,java,spring,rest,spring-mvc,Java,Spring,Rest,Spring Mvc,我想知道如何正确地实现一个Spring控制器,它应该作为REST服务。特别是我想尝试使界面尽可能的RESTful。此外,我还希望使用HTTP错误代码,以便我的客户机可以相应地采取行动 我想知道如何实现我的方法,所以如果一切正常(在响应的主体中),它们会返回JSON,或者抛出http错误代码以及无法工作的自定义原因(可能是来自DAO或数据库的错误)。但是我不确定哪一个是正确的方法?返回一个字符串并添加值以返回到模型,或者返回一个HashMap并将我的内容放在其中?还是直接返回对象?但如果发生错误,

我想知道如何正确地实现一个Spring控制器,它应该作为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;
    }
}
我意识到代码不是“恰到好处的”,但我不知道如何使它成为需要的样子。也许一些经验会有所帮助?首先,我认为在返回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!"}
使用
映射
将起作用,但我建议您编写一些资源类来定义要返回的对象。它们更容易维护<代码>映射不提供任何结构,而结构是创建REST服务时非常重要的一部分


我认为您不应该返回嵌入原始异常消息的资源。它可能会泄露您不希望任何人看到的信息。

您还可以在Rest控制器中使用
@ExceptionHandler
注释方法捕获异常

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

这将使您的acutal控制器/业务逻辑更干净。

您可以将
@ExceptionHandler
@ControllerAdvice
一起使用
>

您可以尝试以下代码:

@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)); 
}
@RequestMapping(value=“/profile”,method=RequestMethod.GET)
@responseboody@ResponseStatus(值=HttpStatus.OK)
公共响应性getUserProfile()
{ 
字符串userName=getUserAuthentication().getName();
if(StringUtils.isEmpty(userName))RestUtil.defaultJsonResponse(“”);
User=userService.getUserByUserNameWithCounters(用户名);
返回RestUtil.getJsonResponse(newuservo(user));
}

如果您想将stackTrace的整个异常传输到您的客户端,正如@Bart所说的,您应该发送一个“ErrorResource”对象

图书馆已将其下架:

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

com.github.zg2pro


这将很好地处理您的错误

所以你会说我有一个主类“ReturnResource”,我打算从中返回的所有其他类,不管是错误还是实际值应该从中继承?否则我真的不明白你打算怎么做,如果你有一个方法,比如说
public User getUser(){…}
,它爆炸了,你不能只返回另一个类,你必须返回用户类。或者您认为它应该是
公共对象getUser(){…}
?我可能还应该补充一点,我打算使用Angular编写端点。在这里,根据http响应代码进行操作非常方便。然而,我仍然同意json对象比默认的tomcat错误页面更好。那么,如何返回对象而不是response.senderro方法?我的意思是,在设置http错误代码的同时,您可以创建一个接口
Resource
,并将其用作返回类型。如果一个名为
User
的类可以作为资源返回,它应该实现接口。因此它变成了
公共资源getUser(){…}
。由于
ErrorResource
也实现了相同的接口。您可以毫无麻烦地返回它。这似乎有点好,但也使我不得不将实体代码与控制器问题混为一谈。我想返回一个对象用户,它也被持久化到数据库中,必须让该对象实现一个接口,这是使我的控制器代码“绿色”在我看来不是那么干净的。我知道这是可行的,但是感觉不太对。但是我喜欢一个ErrorResource类的想法,它可以放在响应体中。再加上里根的回答,我喜欢这个想法,我真的做到了!我按照Bart的建议创建了一个error ressource,然后在此方法中处理ctrl中的所有错误。我可能会在应用程序范围内进一步概括和处理错误,但一步一个脚印。您可以在控制器中创建多个ExceptionHandler,对于每种异常类型。我发现,如果每个控制器只有一个exceptionhandler方法,而不是它们的整个数组,然后检查在这个handlerwell中抛出的错误,看起来会更干净,我更喜欢每异常异常解析方法:-)您可以轻松地处理异常层次结构小心使用此方法,因为这将隐藏Spring的内部异常处理,例如MissingPathVariableException或ConversionNotSupportedException,并返回500而不是400的状态代码。如果为Exception.class添加处理程序,请确保扩展了类ResponseEntityExceptionHandler。添加更多解释。很抱歉,我无法很好地设置格式,但请尝试以下代码->
@RequestMapping(value=“/profile”,method=RequestMethod.get)@responseBy@ResponseStatus(value=HttpStatus.OK)public ResponseEntity getUserProfile(){String userName=getUserAuthentication().getName();if(StringUtils.isEmpty(userName))RestUtil.defaultJsonResponse(“”);用户