4

一般来说,我对 Spring 还是很陌生,我正在尝试使用 Spring Boot。我有一个(希望)快速的问题。我正在尝试构建一个将返回 JSON 的 ReSTful 服务。我遵循了构建 RESTful Web 服务指南,并且可以成功返回 JSON。我已将 JPA 集成到我的 Web 服务中,以便我的数据由数据库支持。

现在,我需要创建一个路径,用户可以在其中创建一个对象,并且我希望验证该对象。我遵循了验证表单输入指南,但我并没有真正尝试创建提供 Web 内容的服务。我想要的是,每当发生验证错误时,返回我自己的自定义 JSON。到目前为止,虽然我尝试遵循Petri 的 Sweet Rest API 指南,但我还没有找到任何资源来实现这一点,我发现该指南在多个场合都很有帮助,但在这种情况下似乎不太有效。我正在使用hibernate-validator:5.0.1.Final和休眠以下内容。

@Entity
@Table(name = "PEOPLE")
public class Person{

    @Id
    @Column(unique = true)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Min(18)
    private long age;
    private String name;

    //Necessary for JPA
    protected Person() {}

    public Person(long age, String name) {
        this.age = age;
        this.name = name;
    }

    // Getters Omitted
}

然后我的人控制器:

@Controller
public class PersonController {

    @RequestMapping(value="person/", method=RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<Person> create(@Valid @RequestBody Person person) {
        // Create in DB and return
    }
} 

这以最严格的方式工作,如果您将垃圾 JSON 发送到此路由,它将返回 400,这非常好。但是响应的正文是一个不太好的 HTML 页面。所以,我的问题是,有没有办法捕捉验证错误?我尝试将以下内容添加到我的控制器中,但没有成功:

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity handleError(MethodArgumentNotValidException ex) {
    //generate my own error message
    return new ResponseEntity(customErrorClass, HttpStatus.BAD_GATEWAY);
}

我知道 Bad Gateway 不是有效的返回码,但我用它只是为了证明从未调用过异常处理程序。当我发布到我的休息服务时,我仍然看到 400 Bad Request + HTML。我会假设有一些我可以覆盖的合理默认值,但我似乎无法弄清楚它在哪里。我试过谷歌搜索和搜索stackoverflow,但没有成功。

提前致谢。

更新

如果我修改控制器以BindingResult在方法签名中包含 a:

@Controller
public class PersonController {

    @RequestMapping(value="person/", method=RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<Person> create(@Valid @RequestBody Person person, BindingResult bindingResult) {
        if(bindingResult.hasErrors()){
            //handle errors and return
        } else {
        // Create in DB and return
        }
    }
} 

我可以让它工作。(请注意,我还必须将 jasper-el jar 添加到我的依赖项中)我之前尝试过,但没有让它工作,但原因并不直观。我使用以下 JSON 发布:{ "id" : "foo", "age": 22, "name" : "James Bond" } 根据JSON Spec,这是有效的 JSON。显然,我的 Person 模型不能将字符串“foo”转换为 long。我不会讨论错误是否应该是 400,我的新问题是:我怎样才能捕捉到这个 400?

4

2 回答 2

4

要处理格式错误或不可转换的 JSON,您可以捕获HttpMessageNotReadableException该类

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity handleBadInput(HttpMessageNotReadableException ex) {
   Throwable cause = ex.getCause();
于 2013-12-20T19:01:27.413 回答
1

问题是您将模型中的字段 id 设置为 long,并使用字符串 foo。这就是 400 http 错误的原因。那么让我们说这种异常是由http状态的表达能力正确管理的。关键是您可以考虑管理 400 错误,并且 zeroflagL 的解决方案工作正常,但如果您使用以下@ExceptionHandler类似的解决方案,这是一个很好的解决方案:

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity handleBadInput(HttpMessageNotReadableException ex) {
   // manage the exceptio for instance log it
   .....

   return ResponseEntity.badRequest().body(/** body may be optional if you want send a description of the error*/);
}

非常重要的是,您的异常处理程序在某种意义上管理异常,将其记录为错误以供您的分析,但随后您应该返回具有 400 http 状态的 http 响应。

这很重要,因为 http 响应是正确的,您发布了一个对您的服务没有意义的 json,并且保留此信息可能对您的客户端应用程序中的发现问题至关重要,例如,关键点是这个 http 状态说您的实体对您的端点没有意义。

我希望它可以帮助你

于 2016-03-23T23:11:01.323 回答