我有一个简单的基于REST的RESTful API,它使用JPA连接的MySQL数据库。到目前为止,此API仅支持实体的完整更新。这意味着必须在请求正文中提供所有字段。
@ResponseBody
@PutMapping(value = "{id}")
public ResponseEntity<?> update(@Valid @RequestBody Article newArticle, @PathVariable("id") long id) {
return service.updateById(id, newArticle);
}
这里的真正问题是验证,如何在创建过程中仅验证提供的字段而又需要所有字段?
@Entity
public class Article {
@NotEmpty @Size(max = 100) String title;
@NotEmpty @Size(max = 500) String content;
// Getters and Setters
}
部分更新请求正文为{"content": "Just a test"}
而不是{"title": "Title", "content": "Just a test"}
的示例。
实际的部分更新通过检查给定字段是否不为空来完成:
if(newArticle.getTitle() != null) article.setTitle(newArticle.getTitle());
但是验证当然不会成功!我必须停用对update方法的验证才能运行RESTful服务。我本质上有两个问题:
答案 0 :(得分:1)
部分更新和Spring JPA的复杂性在于,您可能会发送一半填充的字段,甚至还需要从数据库中提取整个实体,然后仅“合并”实体和pojo,因为否则,您将通过向数据库发送空值来冒险数据。
但是合并本身有点棘手,因为您需要对每个字段进行操作并做出将新值发送到数据库或仅保留当前值的决定。在添加字段时,需要更新验证,并且测试变得更加复杂。在一个声明中:无法缩放。想法是始终编写开放的代码以进行扩展,封闭的代码以进行修改。如果添加更多字段,则理想情况下无需更改验证块。
在REST模型中处理此问题的方式是,每次需要时对整个实体进行操作。假设您有用户,然后先拉一个用户:
GET /user/100
然后,您的网页中将包含用户ID = 100的所有字段。然后,您更改其姓氏。您传播更改,并使用PUT动词调用相同的资源URL:
PUT /user/100
然后,您将所有字段(或者更确切地说是“相同实体”)发送回新的姓氏。您会忘记验证,验证将只不过是一个黑匣子。如果添加更多字段,则添加更多@NotNull或所需的任何验证。当然,在某些情况下,您需要实际编写代码块进行验证。即使在这种情况下,验证也不会受到影响,因为您将有一个用于验证的主for循环,并且每个字段都有自己的验证器。如果添加字段,则添加验证器,但是主验证块仍然不可触摸。
答案 1 :(得分:0)
这些是用于实体验证的最基本选项:
@NotNull
注释列,就像使用其他约束一样。@Column(nullable = false)
对该字段进行注释。 @Valid
在输入方法之前先验证对象。