返回顶部
首页 > 资讯 > 后端开发 > Python >@Valid 无法校验List<E>的问题
  • 573
分享到

@Valid 无法校验List<E>的问题

2024-04-02 19:04:59 573人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录@Valid 无法校验List<E>原因方法@validated 验证List反面例子解决方法@Valid 无法校验List<E> 原因 @Valid只能

@Valid 无法校验List<E>

原因

@Valid只能校验JavaBean,而List<E>不是JavaBean所以校验会失败,尝试了三种解决办法,比较推荐方法3,其他两种大家也可以学习一下。

方法

方法1:对List进行Wrapper

既然List不是JavaBean,那我们就把它封装成JavaBean,我们定义一个ListWrapper类如下:


package com.wyq.firstdemo.util; 
import lombok.Getter;
import lombok.Setter; 
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List; 
@Setter
@Getter
public class ListWrapper<E> {
    @Valid
    private List<E> list; 
    public ListWrapper() {
        list = new ArrayList<>();
    } 
    public  ListWrapper(List<E> list) {
        this.list = list;
    } 
}

同时修改一下controller对应的方法:


    // 使用包装类对list进行验证
    @PostMapping("/insert/all")
    public ServerResponse<String> insertList(@Valid @RequestBody ListWrapper<UserEntity> listWrapper, BindingResult bindingResult) {
        if(bindingResult.hasErrors()) {
            log.error(bindingResult.getFieldError().toString());
            return ServerResponse.createByErrORMessage(bindingResult.getFieldError().getDefaultMessage());
        }
 
        userService.insertList(listWrapper.getList());
        return ServerResponse.createBySuccess();
    }

这样就可以对list进行校验了

注意:

由于对list进行了包装,如果我们传参的时候

[{},{}..]要改为{“list”: [{},{}..]}

方法2:使用@Validated+@Valid

在controller类上面增加@Validated注解,并且删除方法参数中的BindingResult bindingResult(因为这个参数已经没有用了,异常统一有controller返回了)

然后我们运行一下测试一下

可以看到可以对参数进行校验了,但还还有一个问题,那就是这个不是我们想要的返回格式,它controller自己返回的格式,所以我们需要做一个统一异常处理,代码如下:


package com.wyq.firstdemo.handler;
import com.wyq.firstdemo.common.ServerResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.WEB.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice; 
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;
 
@Slf4j
@RestControllerAdvice
public class ControllerExceptionHandler {
 
    @ExceptionHandler
    @ResponseBody
    public ServerResponse<String> handle(ConstraintViolationException exception) {
        log.error(String.valueOf(exception));
        Set<ConstraintViolation<?>> violations = exception.getConstraintViolations();
        StringBuilder builder = new StringBuilder();
        for (ConstraintViolation violation : violations) {
            builder.append(violation.getMessage());
            break;
        }
        return ServerResponse.createByErrorMessage(builder.toString());
    } 
}

经过统一异常处理,我们这边的返回结果就是我们想要的格式了

方法3:自定义一个List

先上代码后说明,先定义一个ValidList


package com.wyq.firstdemo.util;  
import javax.validation.Valid;
import java.util.*; 
public class ValidList<E> implements List<E> { 
    @Valid
    private List<E> list;
 
    public ValidList() {
        this.list = new ArrayList<>();
    }
 
    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();
    } 
    ... 
}

对比方法3和方法1,有没有觉得代码有点相似,新建一个类,并且让他实现List接口,使这个类即具有了JavaBean的特性,又具有了List的特性,比方法1简单优雅很多。

只需要把List换成ValidList就可以了,还不需要多统一异常处理。

参考:https://stackoverflow.com/questions/28150405/validation-of-a-list-of-objects-in-spring/36313615#36313615

@validated 验证List

经常遇到一些参数需要验证,用@validated 的分组验证方式很棒,可以解决大量的冗余代码,提升美观性。

但是我们平时会遇到入参为list的校验,@validated 的分组验证就无法使用了,非常麻烦,各大搜索引擎一查,总结一下比较推荐的方法:

反面例子


@***Mapping("
@Data
@NoArgsConstructor
public class ValidList<E> implements List<E> { 
    @Valid
    private List<E> list = new LinkedList<>(); 
    public ValidList(List<E> paramList) {
        this.list = paramList;
    }
 
    @Override
    public int size() {
        return list.size();
    }
 
    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }
 
    @Override
    public boolean contains(Object o) {
        return list.contains(0);
    }
 
    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }
 
    @Override
    public Object[] toArray() {
        return list.toArray();
    }
 
    @Override
    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }
 
    @Override
    public boolean add(E e) {
        return list.add(e);
    }
 
    @Override
    public boolean remove(Object o) {
        return list.remove(o);
    }
 
    @Override
    public boolean containsAll(Collection<?> c) {
        return list.containsAll(c);
    }
 
    @Override
    public boolean addAll(Collection<? extends E> c) {
        return list.addAll(c);
    }
 
    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        return list.addAll(index, c);
    }
 
    @Override
    public boolean removeAll(Collection<?> c) {
        return list.removeAll(c);
    }
 
    @Override
    public boolean retainAll(Collection<?> c) {
        return list.retainAll(c);
    }
 
    @Override
    public void clear() {
        list.clear();
    }
 
    @Override
    public E get(int index) {
        return list.get(index);
    }
 
    @Override
    public E set(int index, E element) {
        return list.set(index, element);
    }
 
    @Override
    public void add(int index, E element) {
        list.add(index, element);
    }
 
    @Override
    public E remove(int index) {
        return list.remove(index);
    }
 
    @Override
    public int indexOf(Object o) {
        return list.indexOf(o);
    }
 
    @Override
    public int lastIndexOf(Object o) {
        return list.lastIndexOf(o);
    }
 
    @Override
    public ListIterator<E> listIterator() {
        return list.listIterator();
    }
 
    @Override
    public ListIterator<E> listIterator(int index) {
        return list.listIterator(index);
    }
 
    @Override
    public List<E> subList(int fromIndex, int toIndex) {
        return list.subList(fromIndex, toIndex);
    }
}

这样前端的代码是不需要任何改动的!

这个时候有小伙伴说,需要捕获异常,是的,@Validated是通过抛出异常来进行返回的。

上代码,全局异常处理:



@RestControllerAdvice
public class GlobalException {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
 
    
    @ExceptionHandler({
            ParamNullException.class, MethodArgumentNotValidException.class,
            ConstraintViolationException.class, HttpMessageNotReadableException.class,
            MissingServletRequestParameterException.class
    })
    public ReturnResult<?> requestMissingServletRequest(Exception ex) {
        ReturnResult<?> returnResult = new ReturnResult<>();
        returnResult.setRetCode(2);
        if (ex instanceof MissingServletRequestParameterException) {
            returnResult.setRetMsg("参数非法:" + ((MissingServletRequestParameterException) ex).getParameterName());
        } else if (ex instanceof HttpMessageNotReadableException) {
            //排除入参问题
            returnResult.setRetMsg("参数非法:" + ex.getMessage());
        } else if (ex instanceof MethodArgumentNotValidException) {
            //排除入参问题
            FieldError error = (FieldError) ((MethodArgumentNotValidException) ex).getBindingResult().getAllErrors().get(0);
            returnResult.setRetMsg("参数非法:" + error.getField() + " " + error.getDefaultMessage());
        } else if (ex instanceof ConstraintViolationException) {
            //排除入参问题
            ConstraintViolation<?> violation = ((ConstraintViolationException) ex).getConstraintViolations().iterator().next();
            returnResult.setRetMsg("参数非法:" + violation.getPropertyPath().toString().split("[.]")[1]
                    + violation.getMessage());
        }
        return returnResult;
    }
 
    
    @ExceptionHandler(Exception.class)
    public ReturnResult<?> resolveException(HttpServletRequest request, Exception ex) {
        ReturnResult<?> returnResult = new ReturnResult<>();
 
        logger.error("==============异常开始=============");
        logger.error("url: " + request.getRequestURL() + " msg: " + ex.getMessage());
        ex.printStackTrace();
        logger.info("==============异常结束=============");
 
        returnResult.setRetCode(1);
        returnResult.setRetMsg("GlobalException!!!");
        returnResult.setRetData(ex.toString());
        return returnResult;
    }
}

ReturnResult是自己定一的方法返回封装类,根据自己的项目自己封装就行。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: @Valid 无法校验List<E>的问题

本文链接: https://lsjlt.com/news/154940.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作