spring参数校验@Validated及嵌套校验

这篇具有很好参考价值的文章主要介绍了spring参数校验@Validated及嵌套校验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文介绍项目中校验@Validated的使用,主要分参数对象属性校验,嵌套校验,集合在对象属性中校验,集合作为参数校验。

对象属性校验

controller层

@RestController
@Slf4j
@RequestMapping("/api/test")
public class TestController {
    
    @PostMapping(value = "/h9")
    public ApplyInfoDTO2 test9(@Validated @RequestBody ApplyInfoDTO2 applyInfoDTO) {

        System.out.println("kaidsd");
        return applyInfoDTO;
    }
}
package com.dto;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;

@Data
@EqualsAndHashCode(callSuper = false)
public class ApplyInfoDTO2 implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键")
    private Long id;

    @ApiModelProperty(value = "标题", required = true)
    @NotBlank(message = "标题不能为空")
    private String title;

    @Valid
    @NotEmpty(message = "集合1不能为空")
    private List<FileInfoVO2> fileInfoList;

// @NotEmpty会判断这个集合是不是空的,如果前端没传fileInfo这个参数,就不会校验里面的对象属性
// 只有加了这个注解,才能保证这个对象不能为空。
    @Valid
    @NotEmpty(message = "集合2不能为空")
    private List<FileInfoVO> fileInfo;


}
package com.common.vo;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotNull;
import java.io.Serializable;


@Data
public class FileInfoVO implements Serializable {

    @NotNull(message = "文件名称不能为空")
    @ApiModelProperty("原文件名")
    private String name;

}

测试输入

{
    "titles": "44",
    "fileInfoList": [
        {
            "name": "sss"
        }
    ],
    "fileInfo": [
        {
            "names": "sss"
        }
    ]
}

输出

{
    "code": 400,
    "message": "标题不能为空,文件名称不能为空",
    "data": null,
    "timestamp": 1679912555257
}

集合作为参数校验

 @PostMapping(value = "/h10")
    public String test10(@Validated @RequestBody ValidList<FileInfoVO> fileInfo) {

        System.out.println("kaidsd");
        System.out.println(fileInfo);

        return "applyInfoDTO";
    }

这里作为参数,如果使用List接收是不起作用的,必须用ValidList,这个类中有标记@Valid

@Valid

private List<E> list = new ArrayList<>();

如果在对象参数中使用ValidList,就会出现2次错误提示消息。

对象改为

package com.dto;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;

@Data
@EqualsAndHashCode(callSuper = false)
public class ApplyInfoDTO2 implements Serializable {

// @NotEmpty会判断这个集合是不是空的,如果前端没传fileInfo这个参数,就不会校验里面的对象属性
// 只有加了这个注解,才能保证这个对象不能为空。
    @Valid
    @NotEmpty(message = "集合2不能为空")
    private ValidList<FileInfoVO> fileInfo;


}

输入

还是上边输入

输出

{
    "code": 400,
    "message": "文件名称不能为空,文件名称不能为空",
    "data": null,
    "timestamp": 1679913439751
}

Get请求参数校验

需要在controller层上边加@Validated校验注解

正确形式

@RestController
@Slf4j
@RequestMapping("/api/test")
@Validated
public class TestController {
    @GetMapping(value = "/h11")
    public String test11( @NotEmpty(message = "姓名不能为空") String name) {

        System.out.println("kaidsd");
        System.out.println(name);

        return "applyInfoDTO";
    }
}

输入路径

http://localhost:9004/api/test/h11

后台报错

javax.validation.ConstraintViolationException: test11.name: 姓名不能为空
    at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:116)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

错误写法,不生效

@RestController
@Slf4j
@RequestMapping("/api/test")
// 这里没有校验注解,在参数前面加不生效
public class TestController {
    @GetMapping(value = "/h11")

    public String test11(// 这里校验不生效   @Validated @NotEmpty(message = "姓名不能为空") String name) {

        System.out.println("kaidsd");
        System.out.println(name);

        return "applyInfoDTO";
    }
}

报错信息捕捉

之所以上面的请求,校验不通过能返回错误信息,是因为设置了全局异常信息捕捉

import com.common.exception.BusinessException;
import com.common.exception.E;
import com.common.exception.SystemExceptionEnum;
import com.common.response.R;
import java.util.Iterator;
import java.util.Objects;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Order(0)
@RestControllerAdvice
public class SystemExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(SystemExceptionHandler.class);
    private static final String ENUM_TYPE_ERROR_KEYWORD = "枚举类型错误";

    public SystemExceptionHandler() {
    }

    @ResponseBody
    @ExceptionHandler({E.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<Void> handle(E e) {
        log.error("全局异常信息 -> {}", e.getMessage(), e);
        return e.isHideMessage() ? R.fail(e.getCode(), SystemExceptionEnum.UNKNOWN.getMessage()) : R.fail(e);
    }

    @ResponseBody
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> validationBodyException(MethodArgumentNotValidException e) {
        log.error("全局参数校验异常信息 -> {}", e.getMessage(), e);
        StringBuilder builder = new StringBuilder();
        Iterator var3 = e.getBindingResult().getAllErrors().iterator();

        while(var3.hasNext()) {
            ObjectError error = (ObjectError)var3.next();
            String defaultMessage = error.getDefaultMessage();
            if (!Strings.isBlank(defaultMessage)) {
                if (builder.length() > 0) {
                    builder.append(",");
                }

                builder.append(defaultMessage);
            }
        }

        String message = builder.toString();
        message = Strings.isBlank(message) ? SystemExceptionEnum.ARGUMENT_ERROR.getMessage() : message;
        return R.fail(SystemExceptionEnum.ARGUMENT_ERROR.getCode(), message);
    }

    @ResponseBody
    @ExceptionHandler({HttpMessageNotReadableException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> httpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error("全局参数校验异常信息 -> {}", e.getMessage(), e);
        return ((String)Objects.requireNonNull(e.getMessage())).contains("枚举类型错误") ? R.fail(E.of(SystemExceptionEnum.ENUM_TYPE_ERROR)) : R.fail(E.of(SystemExceptionEnum.ARGUMENT_ERROR));
    }

    @ResponseBody
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public R<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        return R.fail(E.of(SystemExceptionEnum.METHOD_NOT_ALLOWED));
    }

    @ExceptionHandler({BusinessException.class})
    public R<Void> handleBusinessException(BusinessException e) {
        log.error("业务异常:{},{}", e.getMessage(), e);
        return R.fail(e.getCode(), e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler({Exception.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<Void> handleUnknown(Exception e) {
        log.error("全局未知异常信息 -> {}", e.getMessage(), e);
        return R.fail(E.of(SystemExceptionEnum.UNKNOWN));
    }
}

自定义的ValidList类

package com.utils;

import lombok.Data;

import javax.validation.Valid;
import java.util.*;

/**
 * 文件描述: 校验List中字段属性
 *
 * @date 2020年03月16日 11:22
 */
@Data
public class ValidList<E> implements List<E> {

    @Valid
    private List<E> list = new ArrayList<>();

    @Override
    public int size() {
        return list.size();
    }

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

    @Override
    public boolean contains(Object o) {
        return list.contains(o);
    }

    @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);
    }
}

post请求报错异常信息类是MethodArgumentNotValidException

org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.ccreate.cnpc.apply.controller.TestController.test10(com.ccreate.cnpc.apply.utils.ValidList<com.ccreate.cnpc.common.vo.FileInfoVO>): [Field error in object 'fileInfoVOList' on field 'list[0].name': rejected value [null]; codes [NotNull.fileInfoVOList.list[0].name,NotNull.fileInfoVOList.list.name,NotNull.list[0].name,NotNull.list.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [fileInfoVOList.list[0].name,list[0].name]; arguments []; default message [list[0].name]]; default message [文件名称不能为空]] 
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:139)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)

get请求报错的是ConstraintViolationException

在service层校验对象参数

错误写法,在service层方法参数上加@Validated是不生效的


import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

@Service
// 加这不生效校验
@Validated
public class ApplyTestService {
    public Boolean add(// 加这也不生效校验  @Validated ApplyInfoDTO2 applyInfoDTO) {
  
        System.out.println("applyTestService");

        return true;
    }
}

正确写法

自定义一个校验工具类


import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
import java.util.stream.Collectors;


public class ValidationUtils {

    private static final Validator validator;

    static {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    /**
     * 校验对象
     *
     * @param object 待校验对象
     * @param groups 待校验的组
     */
    public static void validateEntity(Object object, Class<?>... groups) throws IllegalArgumentException {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
        if (!constraintViolations.isEmpty()) {
            String msg = constraintViolations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("||"));
            throw new E(msg);
        }
    }
}

正确service写法

import com.dto.ApplyInfoDTO2;
import com.ValidationUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;


@Service
public class ApplyTestService {
    public Boolean add(@Validated ApplyInfoDTO2 applyInfoDTO) {
// 这里写自己的校验
        ValidationUtils.validateEntity(applyInfoDTO);
        System.out.println("applyTestService");

        return true;
    }
}

总结:

  1. 对象校验,用post传参,对象属性的校验注解导包使用正确

  1. 集合作为校验接收参数使用ValidList这个类接收

  1. 对象中集合校验使用List接收,不能使用ValidList,会出现2次错误信息

  1. get参数校验,需要在类上加@Validated

  1. service层校验需要自己写校验工具类。写校验方法。文章来源地址https://www.toymoban.com/news/detail-484729.html

到了这里,关于spring参数校验@Validated及嵌套校验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【优雅的参数验证@Validated】@Validated参数校验的使用及注解详解——你还在用if做条件验证?

    请先看看下面代码:(简单举个例子,代码并不规范) 以上代码主要是为了对用户user实体进行条件验证。 但是那么多的if, 写得纯纯得小白一个,也使得代码显得臃肿不美观不优雅! 接下来,让我们学习使用优雅的参数验证@Validated! @Valid和@Validated是Spring Validation框架提供

    2024年02月02日
    浏览(42)
  • Spring Boot中参数校验

    为了保证数据的正确性、完整性,前后端都需要进行数据检验。作为一名后端开发工程师,不能仅仅依靠前端来校验数据,我们还需要对接口请求的参数进行后端的校验。最常见的做法就是通过if/else语句来对请求的每一个参数一一校验,当很多参数需要校验的时候,if/else语

    2023年04月16日
    浏览(37)
  • Spring Boot 使用validation校验参数

    在看公司代码的时候,发现是用了 Spring Boot Validation 去检验参数的,但是后面又在代码里去检验参数去了,而且这个 Spring Boot Validation 校验好像并不生效。于是自己摸索研究了一下。 虽然项目使用的校验都是 javax.validation ,但是不引入这个依赖他是真的不生效。 gradle如下:

    2024年01月25日
    浏览(43)
  • 二,手机硬件参数介绍和校验算法

    第一章 安卓aosp源码编译环境搭建 第二章 手机硬件参数介绍和校验算法 第三章 修改安卓aosp代码更改硬件参数 第四章 编译定制rom并刷机实现硬改(一) 第五章 编译定制rom并刷机实现硬改(二) 第六章 不root不magisk不xposed lsposed frida原生修改定位 第七章 安卓手机环境检测软件分享

    2024年02月08日
    浏览(33)
  • spring boot3参数校验基本用法

    ⛰️个人主页:      蒾酒 🔥系列专栏: 《spring boot实战》 🌊山高路远,行路漫漫,终有归途。 目录 前置条件 前言 导入依赖 使用介绍 配置检验规则 开启校验 使用注意 全局异常捕获返回友好提示信息 常用的校验规则注解 使用技巧 已经初始化好一个spring boot项目且版本为

    2024年02月21日
    浏览(45)
  • Spring参数注解,支持数组入参(List)校验

    2、对返回的校验信息异常进行全局捕获,封装后返回。 参考 https://stackoverflow.com/questions/28150405/validation-of-a-list-of-objects-in-spring

    2024年02月11日
    浏览(56)
  • spring boot实现实体类参数自定义校验

    安装依赖项 1、新建实体类 2、新建验证类 3、在控制器中 3.1 首先写入方法 @InitBinder注解的作用是在控制器方法执行之前,先执行有 @InitBinder注解的方法,使用WebDataBinder 把新建的验证规则绑定 3.2 在控制器接口参数中

    2024年02月12日
    浏览(37)
  • springboot使用@Valid 和 @Validated 注解校验详解以及编写一个自定义全局异常类

    全局异常处理类 验证: ============================================== 导入所需要的包: 如果你是 springboot 项目,那么可以不用引入了,已经引入了,他就存在于最核心的 web 开发包里面。 如果你不是 springboot 项目,那么引入下面依赖即可: 新建三个实体类 实现一: 使用@Valid注解修

    2024年02月10日
    浏览(40)
  • Spring Boot使用 Hibernate-Validator校验参数时的长度校验

    今天在使用Validator框架数据验证的时候碰到了三个类似的注解,都是用来限制长度,但是用法上有区别:  @Size是一个Bean验证注释,用于验证关联的String具有的长度受最小值和最大值限制的值.  @Length是一个Hibernate特定的注释,与@Size具有相同的含义; 两者的区别: ​ 用@length限

    2024年02月14日
    浏览(41)
  • 参数校验: spring-boot-starter-validation

    2024年01月21日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包