解决@Valid List 无法校验的问题

情况1

@PostMapping
public String doIt(@RequestBody @Valid List<User> users) {
    return "SUCCESS";
}

如果API这样设计的话,经测试,@Valid无法发挥作用。

情况2

@PostMapping
public String doItAgain(@RequestBody @Valid UserList userList) {
    return "SUCCESS";
}
@Data
public class UserList() {
	
	@Valid
    private List<User> users;

}

这种情况是情况1的进阶,这样设计至少@Valid能够发挥作用了。但是太麻烦,需要专门写一个UserList类,简直不优雅。同时外接的JSON需要需要多套一层,如下

{"users": [{"name": "Deolin", "age": 18}, {"name": "Rin", "age": 17}]}

多一层"users"对调用方来说也是麻烦。

分析

情况1那样子设计行不通的原因是,java.util.List(ArrayList)内部通过持有一个数组来保存对象们,而作为Java官方的类,内部肯定不会在数组上声明@Valid,所以内部的对象们没有得到应有的递归校验。

所以,考虑使用一种新的java.util.List实现,来变相的达到列表校验的效果。

解决方案

/**
 * 可被校验的List
 *
 * @param <E> 元素类型
 * @author Deolin
 */
 public class ValidableList<E> implements List<E> {
 
    @Valid
    private List<E> list;
     
    public ValidableList() {
        this.list = new ArrayList<>();
    }
    
    public ValidableList(List<E> list) {
        this.list = list;
    }
    
    public List<E> getList() {
        return list;
    }

    public void setList(List<E> list) {
        this.list = list;
    }
    
    @Override
    public int size() {
        return list.size();
    }

    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }

    // 其他的Override方法省略。它们与size()和isEmpty()类似,直接调用private List list处理。 

 }

可以看到ValidableList具有二象性,ValidableList LIKE-A java.util.List,同时也是个“holder”,对外的方法全部会移交给持有的list处理。

也就是说,ValidableList与java.util.List的对外功能完全一致。

对于Spring参数绑定来说,JSON转换后也能够绑定到ValidableList对象上(就像能绑定到java.util.ArrayList对象上一样。)

实现了上述的效果后,直接在list上声明一个@Valid就解决所有问题了。

最终的解决方案

API

@PostMapping
public String noMore(@RequestBody @Valid ValidableList<User> users) {
    return "SUCCESS";
}

JSON

[{"name": "Deolin", "age": 18}, {"name": "Rin", "age": 17}]
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值