Spring MVC – REST服务中bean列表上的@Valid
在Spring MVC REST服务(json)中,我有一个像这样的控制器方法:
@RequestMapping(method = RequestMethod.POST, value = { "/doesntmatter" }) @ResponseBody public List myMethod(@Valid @RequestBody List request, BindingResult bindingResult) {
MyBean类具有beanvalidation注释的位置。
在这种情况下似乎没有进行validation,尽管它适用于其他控制器。
我不想将列表封装在dto中,这将改变json输入。
为什么没有对bean列表进行validation? 有哪些替代方案?
@Valid
是JSR-303注释,JSR-303适用于JavaBeans上的validation。 java.util.List
不是JavaBean(根据JavaBean的官方描述 ),因此无法使用符合JSR-303的validation器直接validation它。 两项意见支持这一点。
JSR-303规范的 3.1.3节说:
除了支持实例validation之外,还支持对象图的validation。 图validation的结果作为一组统一的约束违规返回。 考虑bean X包含Y类型字段的情况 。 通过使用@Valid注释注释字段Y ,Validator 将在validationX时validationY(及其属性) 。 在类型Y(子类,实现)声明的字段中包含的值的确切类型Z在运行时确定。 使用Z的约束定义。 这确保了标记为@Valid的关联的正确多态行为。
集合值,数组值和通常可迭代的字段和属性也可以使用@Valid注释进行修饰 。 这会导致validation迭代器的内容。 支持实现java.lang.Iterable的任何对象。
我用粗体标出了重要的信息。 本节暗示为了validation集合类型,必须将其封装在bean中(隐含于Consider the situation where bean X contains a field of type Y
); 而且集合不能直接validation(由Collection-valued, array-valued and generally Iterable fields and properties may also be decorated
暗示Collection-valued, array-valued and generally Iterable fields and properties may also be decorated
,重点是字段和属性 )。
实际的JSR-303实现
我有一个示例应用程序 ,它使用Hibernate Validator和Apache Beans Validator测试集合validation。 如果你在这个样本上运行mvn clean test -Phibernate
(使用Hibernate Validator)和mvn clean test -Papache
(对于Beans Validator),则两者都拒绝直接validation集合,这似乎符合规范。 由于Hibernate Validator是JSR-303的参考实现,因此该示例进一步certificate了需要将集合封装在bean中以便进行validation。
有了这个,我会说在试图将问题中显示的方式直接传递给控制器方法时也存在设计问题。 即使validation直接用于集合,控制器方法也无法使用备用数据表示,例如自定义XML,SOAP,ATOM,EDI,Google协议缓冲区等,它们不直接映射到集合。 为了支持这些表示,控制器必须接受并返回对象实例。 这将需要以任何方式将集合封装在对象实例中。 因此,强烈建议将List
包装在另一个对象中,如其他答案所示。
我能找到的唯一方法是包装列表, 这也意味着JSON输入必须改变 。
@RequestMapping(method = RequestMethod.POST, value = { "/doesntmatter" }) @ResponseBody public List<...> myMethod(@Valid @RequestBody List request, BindingResult bindingResult) {
变为:
@RequestMapping(method = RequestMethod.POST, value = { "/doesntmatter" }) @ResponseBody public List<...> myMethod(@Valid @RequestBody MyBeanList request, BindingResult bindingResult) {
我们还需要:
import javax.validation.Valid; import java.util.List; public class MyBeanList { @Valid List list; //getters and setters.... }
看起来它也可以用于列表的自定义validation,但我还没有那么远。
@Valid注释是标准JSR-303 Bean Validation API的一部分,并不是Spring特定的构造。 只要配置了适当的Validator,Spring MVC就会在绑定后validation@Valid对象。
参考: http : //docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
尝试直接validation。 像这样的东西:
@Autowired Validator validator; @RequestMapping(method = RequestMethod.POST, value = { "/doesntmatter" }) @ResponseBody public Object myMethod(@RequestBody List
使用org.springframework.validation.beanvalidation.LocalValidatorFactoryBean作为成员实现您自己的validation器,并为每个项调用该validation器。
public class CheckOutValidator implements Validator { private Validator validator; @Override public void validate(Object target, Errors errors) { List request = (List) target; Iterator it = request.iterator() while(it.hasNext()) { MyBean b = it.next(); validator.validate(b, errors); } } //setters and getters }
有一种优雅的方法可以在自定义java.util.List
包装您的请求,该自定义java.util.List
同时充当List
和JavaBean
。 看这里
如果您不想为每个List编写包装器,可以使用通用包装器:
public class ListWrapper { private List list; public ListWrapper() { list = new ArrayList<>(); } public ListWrapper(List list) { this.list = list; } @Valid public List getList() { return list; } public void setList(List list) { this.list = list; } public boolean add(E e) { return list.add(e); } public void clear() { list.clear(); } }
我认为你最好的选择是包装列表 – 如果它不是Spring MVC中的bean,如何validation请求参数?
没有办法说@Valid适用于集合的元素。
- unit testing的良好模式形成了在Spring MVC中具有基于注释的validation的bean
- 可参数化的JSR-303validation值
- beanvalidation默认参数的顺序?
- 由于@Constraint validatedBy,如何避免层之间的交叉依赖?
- Autowired Repository在Custom Constraint Validator中为空
- 自动级联bean-validation递归validation,@ Valid注释
- 使用JSR-303和Spring的Validator的组合为spring引导端点实现自定义validation逻辑
- Hibernate Validator方法或构造函数validation
- hibernate唯一密钥validation