Spring 中@Validated 分组校验使用

说白了:分组的作用就是精准验证,解耦

Spring 中@Validated 分组校验使用

转载:Spring 中@Validated 分组校验使用_wangxuelei036的博客-CSDN博客_spring valid 分组

通过本文你能学习到@Validated 的基本使用,以及如何再spring-boot 中进行数据异常的统一处理

Spring Validation验证框架对参数的验证机制提供了@Validated(Spring’s JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。

在检验入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同,总体来说@validated 相当于 @Valid 验证的升级版,功能更加强大。

接下来我们直接看下如何使用

引入POM依赖
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.4.Final</version>
        </dependency>
定义公共分组class(用于标记分组,可以像后面定义在Vo里面,但是建议一些常用的定义在外部),如下:

public interface Add {
}
public interface Edit {
}
 

定义接收数据的Vo
注意注解中分组的的使用,为了演示,同时在内部定义了一个特殊分组类

 
import com.example.jsr.commmon.Add;
import com.example.jsr.commmon.Edit;
import org.hibernate.validator.constraints.NotBlank;
 
import javax.validation.constraints.Pattern;
 
public class ParamsVo {
 
    //特殊用于修改年龄 标记使用 灵活放置位置
    public interface ModifyAge {
    }
 
    //年龄是1-120之间有效
    public static final String AGE_REG = "/^(?:[1-9][0-9]?|1[01][0-9]|120)$/";
 
    @NotBlank(
            groups = {Edit.class, ParamsVo.ModifyAge.class},
            message = "失败,id不能为空"
    )
    private String id;
 
    @NotBlank(groups = {Edit.class, Add.class}, message = "失败,名字不能为空")
    private String name;
 
    //自定义一个正则
    @NotBlank(groups = {Add.class, ParamsVo.ModifyAge.class},
            message = "失败,请填写age"
    )
    @Pattern(regexp = AGE_REG,groups = {Add.class, ParamsVo.ModifyAge.class},
            message = "失败,请填写正确age"
    )
    private String age;
 
    ...省略setter getter 方法....
}
统一异常处理类
 
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
 
/**
 * 全局异常处理
 */
@ControllerAdvice
public class GlobalExceptionHandler {
 
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public String handlerUnexpectedTypeException(BindException ex){
        BindingResult result = ex.getBindingResult();
        if (result.hasErrors()) {
            FieldError fieldError = result.getFieldError();
            if (fieldError != null) {
                return fieldError.getDefaultMessage();
            }
        }
        return "失败,请刷新重试";
    }
 
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handlerException(Exception ex){
        ex.printStackTrace();
        return "失败,请刷新重试";
    }
}
测试类 
import com.example.jsr.Vo.ParamsVo;
import com.example.jsr.commmon.Add;
import com.example.jsr.commmon.Edit;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
@Controller
@RequestMapping("/validated/test")
public class ValidatedTestController {
 
    @RequestMapping("/add")
    @ResponseBody
    public String add(
            @Validated(Add.class)ParamsVo paramsVo){
        System.out.println(String.format("add obj = {%s}",paramsVo.toString()));
        return "success";
    }
 
    @RequestMapping("/edit")
    @ResponseBody
    public String editAll(
            @Validated({Edit.class,ParamsVo.ModifyAge.class})ParamsVo paramsVo){
        System.out.println(String.format("edit obj = {%s}",paramsVo.toString()));
        return "success";
 
    }
}
 页面效果测试
不填age 

填入一个错误age

到此为止,基本的使用相信也是没有问题了
————————————————
版权声明:本文为CSDN博主「妖四灵.Shuen」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wangxuelei036/article/details/107099859

@Validated的分组特性

介绍一下这样的场景:在对用户的帐号密码进行编辑保存以及新增是两种不一样的情况。

编辑修改->保存:只需要验证username与password是否符合条件即可,不需要验证id(因为在数据库中id已经存在)。

新增->保存:新增需要验证username与password是否符合条件,还要验证id。

这时候就用到groups分组分情况对Bean属性变量进行验证,也可以满足多验证。具体的需要一下两个步骤

第一步:创建分组接口类


分组接口类只是普通的接口类并没有多大意义,只是用来标识这个属性哪种情况下被验证,这类似于java.io.Serializable  

public interface addUser{ 

public interface editUser{

}

第二步:Controller方法参数中增加xxx.class接口

在对新增的用户进行ID验证,增加@Validated({addUser.class})接口类用来表示新增的User.getId()需要验证。

@Controller  

public class UserController {  

  

    @RequestMapping("/saveAdd")  

    public String saveAddUser(@Validated({addUser.class}) User user, BindingResult result) {  

        if(result.hasErrors()) {  

            return "error";  

        }  

        return "success";  

    }

第三步:Bean中添加groups分组

在User实体类中添加groups分组@NotEmpty(groups={addUser.class})与UserController中@Validated({addUser.class})对应,说明在执行saveAddUser新增用户的情况下,才对新增的用户id进行验证。

public class User {   

    //在分组addUser时,验证id不能为空,其他情况下不做验证

    @NotEmpty(groups={addUser.class})

    private String id;

    @NotEmpty(message = "用户名不能为空")

    private String username;

    @Size(min=6 ,max= 20 ,message = "密码最少6位,最高20位")

    private String password;

   ......

}

以上三步就可以简单地完成分组验证,但是对分组验证补充一下三点:

第一是:不分配groups分组时,默认每次都需要验证。

第二是:通过groups分组可以对同一个变量进行多个验证,如下代码

//对用户名进行两次不同情况的验证。

@NotEmpty(groups={First.class})

@Size(min=1,max=10,groups={Second.class})

public String username; 


第三是:默认的情况下,不同的分组约束验证是无序的,但是在有些情况下验证的相互约束很重要(比如前一个组验证失败,后面的将不再验证等情况),所以groups分组的验证也有前后验证顺序。使用@GroupSequence注解进行排序。

/*

 * 分组顺序接口类

 */

import javax.validation.GroupSequence;

//分组序列先Frist再Second

@GroupSequence({First.class,Second.class})

public interface Group{

}

@Controller  

public class UserController {  

  

    @RequestMapping("/saveAdd")  

    public String saveAddUser(@Validated({Group.class}) User user, BindingResult result) {  

        if(result.hasErrors()) {  

            return "error";  

        }  

        return "success";  

    }


 

转载于:https://blog.51cto.com/xiaok007/2286720