@Valid注解对List无效
如果前端传入的表单中带有复选框,那后台的怎么用@Valid校验?
比如我想添加一个小组,前端传入的信息包括name小组名字,和userIdList小组成员id的列表(该字段为复选框)。
后台的请求模型如下
@Data
public class GroupAddRequest {
@NotBlank(message = "name不能为空")
@Size(min = 2, max = 10, message = "name长度需要在2~10之间")
private String name;
private List<Long> userIdList;
}
我想对userIdList中的各个成员进行校验,要求传入的userId都必须大于0
但是添加@Min和@Max注解都没用。
如何优雅的对List成员进行校验?
正在回答
同学你好,1、这里老师尝试了一下在ValidList中封装为实体类确实是比较麻烦的,并不好实现。
2、其实这里对于前端传递的集合数据,更多的是在前端里直接进行验证。
3、如果同学想实现在后端的list验证,同学其实可以尝试在这个list集合的set方法中,直接添加一个验证,比如:


如上所示,也可以根据提示信息定位问题。
试了一下,这个做法可以是可以,但是又有新问题
@Data
public class GroupAddRequest {
@NotBlank(message = "name不能为空")
@Size(min = 2, max = 10, message = "name长度需要在2~10之间")
private String name;
@Min(value = 1, message = "adminId不能小于1")
private Long adminId;
private List<Long> userIdList;
public void setUserIdList(List<Long> userIdList) {
for (Long userId : userIdList) {
if (userId < 1) throw new ManagementException(ManagementExceptionEnum.PARA_ERROR);
}
this.userIdList = userIdList;
}
}
但是前端userIdList传入小于1的数据,那返回的数据格式如下
{
"status": 10003,
"msg": "[Property 'userIdList' threw exception; nested exception is ManagementException(code=10003, message=参数错误)]",
"data": null
}
msg的内容和预想的不一样,应该是@Valid把我自定义的异常给捕获了,然后再抛出BindException异常。
如何改变msg的内容?
controller
@RestController
@RequestMapping("/group")
public class GroupController {
@PostMapping("/add")
public ApiRestResponse<Object> add(@Valid GroupAddRequest groupAddRequest) {
System.out.println(groupAddRequest);
return ApiRestResponse.success();
}
}
ValidList
import org.jetbrains.annotations.NotNull;
import javax.validation.Valid;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
public class ValidList<E> implements List<E> {
@Valid
private List<E> list;
public ValidList() {
this.list = new ArrayList<E>();
}
public ValidList(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
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<E> iterator() {
return null;
}
@Override
public void forEach(Consumer<? super E> action) {
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(@NotNull T[] a) {
return null;
}
@Override
public boolean add(E e) {
return false;
}
@Override
public boolean remove(Object o) {
return false;
}
@Override
public boolean containsAll(@NotNull Collection<?> c) {
return false;
}
@Override
public boolean addAll(@NotNull Collection<? extends E> c) {
return false;
}
@Override
public boolean addAll(int index, @NotNull Collection<? extends E> c) {
return false;
}
@Override
public boolean removeAll(@NotNull Collection<?> c) {
return false;
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
return false;
}
@Override
public boolean retainAll(@NotNull Collection<?> c) {
return false;
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
}
@Override
public void sort(Comparator<? super E> c) {
}
@Override
public void clear() {
}
@Override
public E get(int index) {
return null;
}
@Override
public E set(int index, E element) {
return null;
}
@Override
public void add(int index, E element) {
}
@Override
public E remove(int index) {
return null;
}
@Override
public int indexOf(Object o) {
return 0;
}
@Override
public int lastIndexOf(Object o) {
return 0;
}
@Override
public ListIterator<E> listIterator() {
return null;
}
@Override
public ListIterator<E> listIterator(int index) {
return null;
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return null;
}
@Override
public Spliterator<E> spliterator() {
return null;
}
@Override
public Stream<E> stream() {
return null;
}
@Override
public Stream<E> parallelStream() {
return null;
}
}
Admin
import lombok.Data;
import javax.validation.constraints.Min;
@Data
public class Admin {
// @Min(value = 1, message = "userId不能小于1")
Long userId;
}
GroupAddRequest
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
@Data
public class GroupAddRequest {
@NotBlank(message = "name不能为空")
@Size(min = 2, max = 10, message = "name长度需要在2~10之间")
private String name;
@Min(value = 1, message = "adminId不能小于1")
private Long adminId;
private ValidList<Admin> userIdList;
}
postman

报错信息
[11:04 21:05:20.135] [ERROR] [com.fjlonge.management.filter.WebLogAspect] - Exception:org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'groupAddRequest' on field 'userIdList': rejected value [1,2,8,9]; codes [typeMismatch.groupAddRequest.userIdList,typeMismatch.userIdList,typeMismatch.com.fjlonge.management.model.request.ValidList,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [groupAddRequest.userIdList,userIdList]; arguments []; default message [userIdList]]; default message [Failed to convert property value of type 'java.lang.String[]' to required type 'com.fjlonge.management.model.request.ValidList' for property 'userIdList'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String[]' to required type 'com.fjlonge.management.model.request.ValidList' for property 'userIdList': no matching editors or conversion strategy found]
其实我很不明白一点,前端传入的字段,userIdList值为[1,2,8,9],系统可以对应到GroupAddRequest 下的userIdList,但是系统怎么知道把1,2,8,9对应到Admin的userId。所以感觉这个方法应该是行不通的。
同学你好,根据报错信息:Cannot convert value of type 'java.lang.String[]' to required type 'com.fjlonge.management.model.request.ValidList' for property 'userIdList' -->无法转换类型的值java.lang.String[]'到所需类型'com.fjlonge.management.model.request.ValidList'中
猜测是传递数据的问题
1、同学尝试单独传递list集合类型的数据,查看list类型的数据是否能正确传递
2、如果list类型的数据可以正常传递,但是在类GroupAddRequest中ValidList不能传递的话,同学可以将自己完整的测试内容贴出,包括poatman中的测试内容也贴出,老师来复制测试一下。
同学你好,1、@Valid注解并不适用于List ,与List的书写位置并没有关系。
2、同学想在GroupAddRequest 中使用List是有问题的,并不能直接这样用,建议参考如上案例:
同学可以尝试定义一个自定义的ValidList:
public class ValidList<E> implements List<E> {
@Valid
private List<E> list;
public ValidList() {
this.list = new ArrayList<E>();
}
public ValidList(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();
}将userIdList中的Long类型封装到一个实体类Admin中,
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
public class Admin {
@NotNull(message = "用户id不能为null")
@Min(1)
Long userId;
}
在Admin中存在对应Long类型的userId,在controller中
@Data
public class GroupAddRequest {
@NotBlank(message = "name不能为空")
@Size(min = 2, max = 10, message = "name长度需要在2~10之间")
private String name;
@Min(value = 1, message = "adminId不能小于1")
private Long adminId;
private ValidList<Admin> userIdList;
}
通过这样的形式来尝试完成一下。
老师,可能是我没表达清楚。
@RestController
@RequestMapping("/group")
public class GroupController {
@Autowired
private GroupService groupService;
//新增小组
@PostMapping("/add")
public ApiRestResponse<Object> add(@Valid GroupAddRequest groupAddRequest) {
groupService.add(groupAddRequest);
return ApiRestResponse.success();
}
}
这个是我的controller方法,传入的是GroupAddRequest这个请求模型,
@Data
public class GroupAddRequest {
@NotBlank(message = "name不能为空")
@Size(min = 2, max = 10, message = "name长度需要在2~10之间")
private String name;
@Min(value = 1, message = "adminId不能小于1")
private Long adminId;
private List<Long> userIdList;
}
前端传入post表单,

这个要验证的userIdList不是直接出现在controller方法中,而是在GroupAddRequest这个请求模型中,而且List泛型是Long,如果用自定义类做泛型,那么前端传入的参数名就可能不是userIdList。
我希望是要验证的userIdList放在GroupAddRequest模型中,而controller方法传入只有GroupAddRequest这一个参数,然后在这个基础上,对GroupAddRequest中的userIdList进行校验。
同学你好,1、如果只是添加@Valid注解并不适用于List ,原因是@Valid是JSR-303批注,JSR-303适用于JavaBean上的验证。而根据JavaBean的官方描述,java.util.List不是JavaBean,因此不能使用兼容JSR-303的验证器直接对其进行验证。
2、如上所述,@Valid不能校验List ,此时其实可以自定义一个类,用来接收对应的数据,这样它就是一个JavaBean了。比如:
自定义的类CompanyTag
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
public class CompanyTag {
@NotNull(message = "用户id不能为null")
@Min(1)
Long userId;
String name;
}List改成自定义的ValidList<CompanyTag>
public class ValidList<E> implements List<E> {
@Valid
private List<E> list;
public ValidList() {
this.list = new ArrayList<E>();
}
public ValidList(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();
}在调用时
@PostMapping("add")
public Integer addBatch(@RequestBody @Valid ValidList<CompanyTag> companyTagList){
return 执行调用方法得到返回值;
}3、当然同学也可以不用@Valid,直接在方法里手动书写校验内容。
其实@Valid只能校验JavaBean,而List不是JavaBean所以校验会失败,具体的方法你可以参考这个方法来实现对应List集合的验证
- 参与学习 人
- 提交作业 9410 份
- 解答问题 16556 个
综合就业常年第一,编程排行常年霸榜,无需脱产即可学习,北上广深月薪过万 无论你是未就业的学生还是想转行的在职人员,不需要基础,只要你有梦想,想高薪
了解课程

恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星