数据验证 Validator

# 数据验证 Validator

Jboot 从 V3.7.5 开始,增强 Jboot 的验证方式,在 Jboot 之前的 @EmptyValidate、@RegexValidate 等基础上,进一步基于 JSR 303 – Bean Validation 简化了验证方式,相比 Spring 更加优雅简单。

# @NotNull

在 Controller (或 Service 等)中,我们可以直接通过 @NotNull 注解给 Controller 添加,例如:

@RequestMapping("/")
public class MyController extends JbootController {

    public void test(@NotNull String para) {
        renderText("test6");
    }
}

当我们访问 /test 的时候,会出现如下的错误:

para is null at method: io.jboot.test.MyController.test(java.lang.String) : /test
io.jboot.components.valid.ValidException : 不能为null
        at io.jboot.components.valid.ValidUtil.throwValidException(ValidUtil.java:59)
        at io.jboot.components.valid.ValidUtil.throwValidException(ValidUtil.java:50)
        at io.jboot.components.valid.interceptor.NotNullInterceptor.intercept(NotNullInterceptor.java:36)

如果是 ajax (或者 content-type 为 "application/json") 访问 /test 的时候,会返回如下的 json 信息:

{
    "throwable": "io.jboot.components.valid.ValidException: 不能为null",
    "errorMessage": "para is null at method: io.jboot.test.MyController.test(java.lang.String)",
    "errorCode": 400,
    "state": "fail",
    "message": "不能为null"
}

如果我们访问 /test?para=123,则可以正常访问,不会出错,此时 test 方法里的 para 的值为 123(不为 null)。

# @Size 验证

@Size 验证,不仅仅可以验证 String 数据的长度,也可以验证 int long 等数据类型的值的大小范围。比如:

public void test(@Size(min=2,max=10) int value) {
    renderText("test6");
}

这个要求 value 的值必须在 2 ~ 10 之间。

当然,我们还可以使用 @Size 来验证 MapList数组 的长度,比如配合 @JsonBody 来接收前端传入的值:

public void list(@Size(min=2,max=10) @JsonBody() List<MyBean> list) {        
    System.out.println("list--->" + list);        
    renderText("ok");
}

要求前度传入的 MyBean Json 数组的数量必须是在 2~10 之间。

更多关于 @JsonBody 请参考:这个链接

# @NotEmpty 验证

@NotEmpty 不仅仅可以验证 String 类型不能为 null 和 空字符串,也可以验证 Map、List、数组等不能为空,比如:

public void list(@NotEmpty() @JsonBody() List<MyBean> list) {        
    System.out.println("list--->" + list);        
    renderText("ok");
}

要求前端掺入的 MyBean Json 数组必须有值。

# @Valid 验证

@Valid 是针对整个 Java Bean 验证,也可以对 JFinal 的 Model 进行验证。的 MyBean Json 数

比如 MyBean 定义如下:

public class MyBean {
    private String id;

    @NotBlank(message = "密码不能为空")
    private String password;

    @Size(min=0,max=2,message = "性别的值只能是 0 1 2")
    private int sex;

    @Min(value = 18,message = "未成年禁止入内")  
    private Integer age; 
}

在 Controller 或者 Service 中,如下代码可以直接对 MyBean 进行验证:

public void test(@Valid() MyBean bean) {
    renderText("test6");
}

如果 MyBean 是一个 JFinal 的 Model,我们只需要在 getter 方法添加注解即可。

# 更多的验证

除了以上的基本示例以外,Jboot 的验证还支持了更多的验证:

注解 说明
@NotNull 限制必须不为null
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

# @EmptyValidate 和 @RegexValidate

当如果我们的 Controller 的方法没有参数的时候,就无法使用如上的注解进行验证了。因为,以上的注解 是给方法里的参数进行添加。在这个时候,我们可以使用 @EmptyValidate@RegexValidate 进行验证。

比如:

@RequestMapping("/")
public class MyController extends JbootController {

    @EmptyValidate(@Form(name = "mobile", message = "手机号不能为空"))
    public void action1() {
        renderText("ok");
    }


    @RegexValidate(@RegexForm(name = "mobile", regex = Regex.MOBILE, message= "您输入的不是手机号"))
    public void action2() {
        renderText("ok");
    }

}
  • 当我们访问 /action1 的时候,会出现手机号不能为空的错误提示。访问 /action1?mobile=123 的时候,正常访问。
  • 当我们访问 /action2 或者 /action2?mobile=123 的时候,会出现手机号不正确的错误提示。 访问 /action2?mobile=18611223344 的时候,正常访问。因为 18611223344 是一个正确的手机号 。

# 自定义渲染器

我们可以写一个 RenderFactory 继承自 JbootRenderFactory ,并复写其 getValidErrorRender() 方法。

例如:

public MyRenderFactory extends JbootRenderFactory(){

    @Override
    public ValidErrorRender getValidErrorRender(ValidException validException){
        //return 返回自己写渲染器
    }
}

然后在项目启动的时候,通过在 onConstantConfig(Constants constants) 里配置上自己的 MyRenderFactory:

@Override
public void onConstantConfig(Constants constants) {
    constants.setRenderFactory(new MyRenderFactory());
}