使用@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 java.util.*;
import java.util.function.UnaryOperator;
/**
* @author psd 用于校验指定的List集合里面的数据
*/
@Data
public class ValidableList<E> implements List<E> {
@Valid
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() {
}
@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 psc 统一参数校验异常处理类
*/
@Slf4j
@ControllerAdvice
public class ValidatedExceptionHandler {
/**
* 处理@Validated 参数校验异常
*
* @param exception
* 异常类型
* @return 异常信息
*/
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseVo exceptionHandler(MethodArgumentNotValidException exception) {
BindingResult result = exception.getBindingResult();
StringBuilder builder = new StringBuilder();
if (result.hasErrors()) {
result.getAllErrors().forEach(p -> {
FieldError fieldError = (FieldError) p;
log.warn("Bad Request Parameters: dto entity [{}],field [{}],message [{}]", fieldError.getObjectName(), fieldError.getField(),
fieldError.getDefaultMessage());
builder.append(fieldError.getDefaultMessage());
});
}
return ResponseVo.paramError(builder.toString());
}
}