Spring参数校验

如何使用

Spring提供了简便的参数校验注解,不需要像以前一样if else去判断了,下面记录一下如何使用注解实现参数的校验

导入坐标

要使用各种注解完成参数的校验,需要导入hibernate-validator坐标以实现

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.1.Final</version>
        </dependency>

常用注解如下(本人并没有都使用过,粘贴的)
@Null 检查该字段为空
@NotNull 不能为null
@NotBlank 不能为空,常用于检查空字符串
@NotEmpty 不能为空,多用于检测list是否size是0
@Max 该字段的值只能小于或等于该值
@Min 该字段的值只能大于或等于该值
@Past 检查该字段的日期是在过去
@Future 检查该字段的日期是否是属于将来的日期
@Email 检查是否是一个有效的email地址
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
@Size(min=, max=) 检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等
@Length(min=,max=) 检查所属的字段的长度是否在min和max之间,只能用于字符串
@AssertTrue 用于boolean字段,该字段只能为true
@AssertFalse 该字段的值只能为false

注解说明

我们使用到的验证参数注解共有两个@Valid与@Validated。
@Validated:可以用在类型、方法和方法参数上,支持分组校验。但是不能用在成员属性上,不支持嵌套检测;
@Valid:可以用在方法、构造方法、方法参数和成员属性上,支持嵌套检测。

验证注解时可能抛出的异常说明

在使用注解校验参数的过程中,可能由于参数不合法会抛出各种异常,但是大体就只有下面三种
BindException:表单提交时,如果参数未通过注解校验抛出该异常,对于以json格式提交将不会抛出该异常
MethodArgumentNotValidException:前端以JSON格式提交参数,后端使用requestBody接收时,如果参数未通过注解校验则抛出该异常。需要说明的是,该异常是BindException的子类
ConstraintViolationException :1. 接口参数上加@RequestParam、@PathVariable或者没加任何注解(按形参名赋值)
2. 接口参数加@NotBlank、@NotNull、@Length等校验注解
当1和2都成立时,也就是说当直接在接口的参数中对基本类型进行校验时,若校验未通过则抛出该异常

简单的使用
1. 创建接收参数的对象
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    @NotNull(groups = Group1.g12.class,message = "学号不能为空")
    @Length(min = 2,max = 3, groups = Group1.g12.class,message = "学号长度错误,需要在2~3位之间")
    private String no;

    @NotNull(groups = Group1.g11.class,message = "姓名不存在!")
    private String name;

    @Max(12)
    private Integer age;

    private String address;

}
2.创建实现分组校验的接口
public interface Group1 {
	//命名比较随意,看看就行
    public interface g11{};
    public interface g12{};
    public interface g13{};
    public interface g14{};
    
}
3.写几个接口测试测试
    @PostMapping("v1")
    public void v1(@Validated(Group1.g12.class) Student student){  //bindException
        System.out.println(student.toString());
    }

    @GetMapping("v2/{name}")
    public void v2(@PathVariable @Length(min = 2,max = 5,message = "name长度需要在2~5之间") String name){ //ConstraintViolationException
        System.out.println(name);
    }

    @PostMapping("v3")
    public void v3(@RequestBody @Validated Student student){ //MethodArgumentNotValidException
        System.out.println("业务执行了...");
        System.out.println(student.toString());
    }

可以看到,我写了三个接口,v1是验证Student(加入了分组校验),v2是直接在接口参数中对基本类型String进行校验,v3是接收JSON参数进行校验
接下来我们一个一个测试:
v1
v1接口很明显,需要对Student进行校验,并且指定了分组Group1.g12.class,而通过观察Student对象可以看到,只有学号no携带了该分组,所以只要学号字段验证通过就没问题。但是当学号为空时则控制台打印Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors<EOL>Field error in object 'student' on field 'no': rejected value [null]; codes [NotNull.student.no,NotNull.no,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [student.no,no]; arguments []; default message [no]]; default message [学号不能为空]<EOL>Field error in object 'student' on field 'no': rejected value [null]; codes [NotNull.student.no,NotNull.no,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [student.no,no]; arguments []; default message [no]]; default message [学号不能为空]]
当学号超过3位长度时则控制台打印:Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'student' on field 'no': rejected value [1200]; codes [Length.student.no,Length.no,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [student.no,no]; arguments []; default message [no],3,2]; default message [学号长度错误,需要在2~3位之间]]

v2(提示下,直接在接口中对类型进行注解校验需要在controller上打@Validated注解)
v2就是在接口参数中直接对对基本类型进行校验,长度需要在2~5之间,所以我们直接发送一个不符合条件的请求,http://localhost:8080/v2/HelloWorld,控制台打印:
在这里插入图片描述
v3
v3就是接收参数的形式变成了JSON,并且进行了参数校验(不带任何分组),所以只是对age进行了校验,age不能超过12,我们试着发送一个不合法的请求,JSON参数为{“name”:“zhangsan”,“age”:15},结果控制台打印:Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void com.example.validation.controller.VController.v3(com.example.validation.entity.Student): [Field error in object 'student' on field 'age': rejected value [15]; codes [Max.student.age,Max.age,Max.java.lang.Integer,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [student.age,age]; arguments []; default message [age],12]; default message [最大不能超过12]] ]

4.关于分组校验

分组校验的情况下,对于没有添加分组校验的注解将不会生效
没有分组校验情况下,只会校验不带分组校验的校验注解

5.分组校验的全局异常处理

在第三步中,我们测试完接口发现报出了不同的异常信息,那么全局异常处理是必不可少的,需要将不合法的提示正确的返回给用户。
经过测试,对于报出的异常共有三类

  1. 对于直接在接口中进行校验的基本类型参数(包含String),抛出ConstraintViolationException
  2. 对于JSON请求映射的参数,抛出MethodArgumentNotValidException
  3. 对于接口参数为对象时,抛出BindException

其中,MethodArgumentNotValidException是BindException的子类
那么,我们只需要拦截BindException和ConstraintViolationException进行处理即可,如下:

	//拦截BindException和MethodArgumentNotValidException
    @ExceptionHandler(BindException.class)
    public Map<String, String> MANVE(BindException e){
        Map<String, String> res = new LinkedHashMap();
        BindingResult bindingResult = e.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        for (ObjectError item:allErrors) {
            if (item instanceof FieldError){
                String field = ((FieldError) item).getField();
                String defaultMessage = ((FieldError) item).getDefaultMessage();
                res.put(field,defaultMessage);
            }
        }
        return res;
    }
	//拦截ConstraintViolationException
    @ExceptionHandler(ConstraintViolationException.class)
    public Map<String,String> CVE(ConstraintViolationException e){
        Map<String,String> res = new LinkedHashMap<>();
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        for (ConstraintViolation item: constraintViolations) {
            String messageTemplate = item.getMessageTemplate();
            PathImpl propertyPath = (PathImpl) item.getPropertyPath();
            NodeImpl leafNode = propertyPath.getLeafNode();
            res.put(leafNode.asString(),messageTemplate);
        }
        return res;
    }

可以把代码中的返回报错信息改为你所需要的形式

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot提供了参数校验的功能,可以在Controller层对前端传过来的数据进行统一检验。在Spring Boot中,可以使用注解@Valid或@Validated来进行参数校验。\[1\] @Validated注解可以用在类上,表示该类中的方法参数需要进行校验。在Controller类中,可以使用@Validated注解来标注类,然后在方法参数上使用校验注解,比如@NotNull、@Max等,来对参数进行校验。\[1\] 例如,在Controller类中的方法参数上使用@NotNull注解可以校验参数是否为空,使用@Max注解可以校验参数的最大值。如果参数校验不通过,会返回相应的错误信息。\[1\] 参数校验的目的是为了保证数据的安全性和完整性。在web开发中,前端的参数校验是为了提升用户体验,后端参数校验是为了防止恶意攻击和保护数据的安全。如果没有经过任何校验参数通过service层、dao层一路来到了数据库,可能会导致严重的后果。因此,参数校验是非常重要的一环。\[2\] 总结来说,Spring Boot提供了参数校验的功能,可以使用@Validated注解和校验注解来对Controller层的参数进行校验,以保证数据的安全性和完整性。\[1\]\[2\] #### 引用[.reference_title] - *1* *2* [springBoot参数校验](https://blog.csdn.net/weixin_43947894/article/details/105448716)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [springboot对参数进行校验](https://blog.csdn.net/weixin_44153131/article/details/129011498)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值