使用@Validated校验List集合中数据失效

使用场景:

1,再做批量修改,或者单独修改数据时候,我们要对前端传递的值做一些校验,比如如下图
在这里插入图片描述

前端传递的实际值或者ip地址为空或者xxx字段为空,导致了之前正确的数据,变成了 非法数据,给后期运维添加工作量。。。效果不好

于是代码就写成如下:

    @PostMapping("/batchUpdateIndicatorDeviceCategorys")
    @ApiOperation("根据参数dto-批量修改告警设备或异常设备的数据值")
    public ResponseVo batchUpdateIndicatorDeviceCategorys(@RequestBody @Validated List<IndicatorDeviceScheduleDto> scheduleDtoList){
        return indicatorDeviceCategoryDetailsService.batchUpdateIndicatorDeviceCategorys(scheduleDtoList);
    }

在测试时候,发现明明在参数校验时候做了判断,但是集合里面比如id,或者currentUserNumber没有传递值,在调试时候还是提示更新成功,数据库里面比如之前修改人工号是有数据的,变成了null,这你要是上线了,运维不得炸。。。。。


@Data
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IndicatorDeviceScheduleDto {

    /**
     * id
     */
    @TableId
    @NotNull(message = "id不能为空")
    private Long id;

    /**
     * 当前登录人工号或者唯一标识
     */
    @NotNull(message = "当前登录人工号或者唯一标识不能为空")
    private String currentUserNumber;

    /**
     * 实际指标值 保留2位小数
     */
    @NotNull(message = "实际指标值,不能为空请重新输入")
    private Double actualValue;

}

原因分析:

1,个人理解 可能有误:@Validated只能对单个起到作用,对list集合起不到,list是java.util包下面的,你这里加个注解肯定不行的了,java.utils包不能自己对参数进行校验,没有这么智能。

解决方案:

方案一:

传统方式,对list集合进行遍历,然后对每个值进行校验,如果有异常 抛出异常,这个方法可行但是代码量臃肿。

方案二:

在controller类上面添加注解 @Validated ,在controller 传参列表里面添加 @Valid

    @Api(tags = "xxxx 管理")
    @Validated
    @RestController
    @RequestMapping("aaa/indicatorDeviceCategoryDetailsController")
    public class IndicatorDeviceCategoryDetailsController {
    
    @PostMapping("/batchUpdateIndicatorDeviceCategorys")
    @ApiOperation("根据参数dto-批量修改告警设备或异常设备的数据值")
    public ResponseVo batchUpdateIndicatorDeviceCategorys( @RequestBody @Valid List<IndicatorDeviceScheduleDto> scheduleDtoList){
        return indicatorDeviceCategoryDetailsService.batchUpdateIndicatorDeviceCategoryDetails(scheduleDtoList);
  }

}

再次调试,scheduleDtoList集合里面的Dto的currentUserNumber设置为空,抛异常了,异常是xxx异常,但是异常过于繁多,消息提示不够友好,可以满足校验参数情况,错误信息详情如下
在这里插入图片描述

方案三:

我们可以写一个集合实现list,代码如下,在controller类上面不用加@Validated注解,在controller使用自定义ValidableList集合,对list进行封装,就可以对scheduleDtoList做参数校验处理。

个人推荐方案三: 优点,异常清晰明了
代码如下:

    @Api(tags = "xxxx 管理")
    @RestController
    @RequestMapping("aaa/indicatorDeviceCategoryDetailsController")
    public class IndicatorDeviceCategoryDetailsController {
    
    @PostMapping("/batchUpdateIndicatorDeviceCategorys")
    @ApiOperation("根据参数dto-批量修改告警设备或异常设备的数据值")
     public ResponseVo batchUpdateIndicatorDeviceCategoryDetails(@RequestBody @Validated ValidableList<IndicatorDeviceScheduleDto> scheduleDtoList){
        return indicatorDeviceCategoryDetailsService.batchUpdateIndicatorDeviceCategoryDetails(scheduleDtoList);
  }
}

import lombok.Data;
import org.jetbrains.annotations.NotNull;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.*;
import java.util.function.UnaryOperator;

/**
 * @author psd 用于校验指定的List集合里面的数据
 */
@Data
public class ValidableList<E> implements List<E> {

    @Valid
    // 新增集合元素非空校验
    @NotEmpty
    private List<E> list = new ArrayList<>();

    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 list.contains(o);
    }

    @NotNull
    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }

    @NotNull
    @Override
    public Object[] toArray() {
        return list.toArray();
    }

    @NotNull
    @Override
    public <T> T[] toArray(@NotNull 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(@NotNull Collection<?> c) {
        return list.containsAll(c);
    }

    @Override
    public boolean addAll(@NotNull Collection<? extends E> c) {
        return list.addAll(c);
    }

    @Override
    public boolean addAll(int index, @NotNull Collection<? extends E> c) {
        return list.addAll(index, c);
    }

    @Override
    public boolean removeAll(@NotNull Collection<?> c) {
        return list.removeAll(c);
    }

    @Override
    public boolean retainAll(@NotNull Collection<?> c) {
        return list.retainAll(c);
    }

    @Override
    public void replaceAll(UnaryOperator<E> operator) {
        List.super.replaceAll(operator);
    }

    @Override
    public void sort(Comparator<? super E> c) {
        List.super.sort(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);
    }

    @NotNull
    @Override
    public ListIterator<E> listIterator() {
        return list.listIterator();
    }

    @NotNull
    @Override
    public ListIterator<E> listIterator(int index) {
        return list.listIterator(index);
    }

    @NotNull
    @Override
    public List<E> subList(int fromIndex, int toIndex) {
        return list.subList(fromIndex, toIndex);
    }

    @Override
    public Spliterator<E> spliterator() {
        return List.super.spliterator();
    }
}


**错误信息详情如下: **简单明了
在这里插入图片描述

温馨提示,无论使用方案二或者方案三,都要写下面统一异常处理,要不然拦截不了异常

import com.dx.major.common.bean.ResponseVo;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import lombok.extern.slf4j.Slf4j;

/**
 * @author psd 统一参数校验异常处理类
 */
@Slf4j
@ControllerAdvice
public class ValidatedExceptionHandler {

    /**
     * 处理@Validated 参数校验异常
     *
     * @param exception
     *            异常类型
     * @return 异常信息
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R exceptionHandler(MethodArgumentNotValidException exception) {
        BindingResult result = exception.getBindingResult();
        // 增强嵌套路径输出
        String errorMsg = result.getFieldErrors().stream()
                .map(fieldError ->
                        String.format("[%s] %s",
                                fieldError.getField(),
                                fieldError.getDefaultMessage())
                )
                .collect(Collectors.joining("; "));
        log.warn("参数校验失败: {}", errorMsg);
        return R.fail(ResultCodeEnum.PARAM_ERROR.getCode(),ResultCodeEnum.PARAM_ERROR.getMessage() + ":" + errorMsg);
    }
}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐