欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring 校验(validator,JSR-303)简单实现方式

程序员文章站 2022-06-15 11:48:56
目录spring 校验(validator,jsr-303)实现什么是jsr-303规范与spring mvc结合java hibernate validator jsr-303验证spring 校验...

spring 校验(validator,jsr-303)实现

什么是jsr-303规范

jsr 303是java ee 6中的一项子规范,叫做bean validation,官方参考实现是hibernate validator,此实现与hibernate orm没有任何关系。jsr 303用于对java bean中的字段的值进行验证。

与spring mvc结合

spring-mvc.xml配置:

    <!--jsr-303-->
    <mvc:annotation-driven validator="validator"/>
    <bean id="validator" class="org.springframework.validation.beanvalidation.localvalidatorfactorybean">
        <property name="providerclass" value="org.hibernate.validator.hibernatevalidator"/>
        <property name="validationmessagesource" ref="messagesource"/>
    </bean>
    <bean id="messagesource" class="org.springframework.context.support.reloadableresourcebundlemessagesource">
        <property name="basename" value="validatemessage"/>
        <property name="usecodeasdefaultmessage" value="false"/>
        <property name="defaultencoding" value="utf-8"/>
        <property name="cacheseconds" value="60"/>
    </bean>
    <bean  id="webbindinginitializer" class="org.springframework.web.bind.support.configurablewebbindinginitializer">
        <property name="conversionservice">
            <bean class="org.springframework.format.support.formattingconversionservicefactorybean"></bean>
        </property>
        <property name="validator" ref="validator"/>
    </bean>

实体类添加验证注解

这里贴出部分代码,知道如何加注解即可:

import com.lemontree.common.utils.ajaxresult;
import com.lemontree.common.utils.stringutil;
import com.lemontree.common.utils.email.emailutils;
import org.hibernate.validator.constraints.notempty;
import java.util.date;
public class user {
    /**
     * this field was generated by mybatis generator.
     * this field corresponds to the database column user.id
     *
     * @mbg.generated thu mar 16 13:27:38 cst 2017
     */
    private integer id;
    /**
     * this field was generated by mybatis generator.
     * this field corresponds to the database column user.user_name
     *
     * @mbg.generated thu mar 16 13:27:38 cst 2017
     */
    @notempty(message = "用户名不能为空")
    private string username;
    /**
     * this field was generated by mybatis generator.
     * this field corresponds to the database column user.password
     *
     * @mbg.generated thu mar 16 13:27:38 cst 2017
     */
    @notempty(message = "密码不能为空")
    private string password;
    }

控制器验证注解添加

将@validated 注解跟在实体类前面,bindingresult紧跟其后:

    @requestmapping(value = "/login.htm", method = requestmethod.post)
    public @responsebody ajaxresult login(@validated user user, bindingresult bindingresult,
                                          httpservletrequest request, httpservletresponse response) {
        if (bindingresult.haserrors()){
            list<fielderror> errorses = bindingresult.getfielderrors();
            if (collectionutils.isnotempty(errorses)){
                errorses.foreach(item->{
                    system.out.println(item.getdefaultmessage());
                });
            }
        }
      }

java hibernate validator jsr-303验证

jsr-303是java ee 6中的一项子规范,叫做 bean validation,hibernate validator是bean validation 的参考实现。

实际使用就是通过注解来给字段添加约束,然后校验字段是否符合规范,如果不符合就会抛出异常,以此来减少校验数据的代码,并保证拿到的数据都是符合规范的,也可以和spring框架配合使用

集成

官方文档

        <dependency>
            <groupid>org.hibernate</groupid>
            <artifactid>hibernate-validator</artifactid>
            <version>6.0.10.final</version>
        </dependency>
        <dependency>
            <groupid>org.glassfish</groupid>
            <artifactid>javax.el</artifactid>
            <version>3.0.1-b09</version>
        </dependency>
        <dependency>
            <groupid>javax.validation</groupid>
            <artifactid>validation-api</artifactid>
            <version>2.0.1.final</version>
        </dependency>

使用

校验对象

public class jsrtest {
    @notnull(message = "id不能为空!")
    @min(value = 1, message = "id只能大于等于1")
    integer id;
    @notnull(message = "姓名不能为空!")
    string name;
    public void validateparams() {
        validator validator = validation.builddefaultvalidatorfactory().getvalidator();//获取一个验证器
        set<constraintviolation<jsrtest>> violationset = validator.validate(this);//验证数据,获取到错误集合
        iterator<constraintviolation<jsrtest>> iterator = violationset.iterator();
        if (iterator.hasnext()) {
            string errormessage = iterator.next().getmessage();//获取到错误信息
            throw new validationexception(errormessage);
        }
    }
    public static void main(string args[]) {
        jsrtest req = new jsrtest();
        req.id = 1;
        req.validateparams();
    }
}

像上面那样将在属性上添加注解即可声明约束

校验属性

上面是校验整个对象,也可以单独校验某个字段:

validator.validateproperty(object, "name");

分组校验

public class jsrtest {
    @notnull(message = "id不能为空!", groups = {validationgroup.class})
    @min(value = 1, message = "id只能大于等于1")
    integer id;
    @notnull(message = "姓名不能为空!", groups = {validationgroup.class})
    string name;
    @decimalmin(value = "1.1")
    double price;
    int date;
    public static void validateparams(jsrtest jsrtest) {
        validator validator = validation.builddefaultvalidatorfactory().getvalidator();
        set<constraintviolation<jsrtest>> violationset = validator.validate(jsrtest, validationgroup.class);
        iterator<constraintviolation<jsrtest>> iterator = violationset.iterator();
        if (iterator.hasnext()) {
            string errormessage = iterator.next().getmessage();
            throw new validationexception(errormessage);
        }
    }
    public static void main(string args[]) {
        jsrtest req = new jsrtest();
        validateparams(req);
    }    
    public interface validationgroup {
    }
}

分组校验所指定的calss必须是一个接口,可以指定多个

自定义约束

通常情况下,框架提供的注解已经可以满足正常的验证需求,但是我们也可以自定义注解来满足我们的需求

我们这里的例子是所注释的字符串中不能包含指定字符

@target(field)      //元注解,定义该注解使用在字段上
@retention(runtime) //定义注解的生命周期
@constraint(validatedby = customvalidator.class)//指明该注解的校验器
@documented         //表示该注解会被添加到javadoc中
public @interface customconstraints {
    string message() default "默认异常message";
    class<?>[] groups() default {};
    class<? extends payload>[] payload() default {}; //这个属性可以用来标注错误的严重等级,但是并不被api自身所使用
    string value() default " ";
}
import javax.validation.constraintvalidator;
import javax.validation.constraintvalidatorcontext;
/**
 * 需要实现constraintvalidator接口
 * 泛型的第一个参数是自定义的注解,第二个参数注解所注释的字段的类型
 */
public class customvalidator implements constraintvalidator<customconstraints, string> {
    private string value;
    /**
     * 初始化调用,拿到注解所指定的value
     *
     * @param constraintannotation
     */
    @override
    public void initialize(customconstraints constraintannotation) {
        value = constraintannotation.value();
    }
    /**
     * @param value   注释的字段的值
     * @param context
     * @return true 通过验证,false 未通过验证
     */
    @override
    public boolean isvalid(string value, constraintvalidatorcontext context) {
        if (value != null && value.contains(this.value)) {
            context.disabledefaultconstraintviolation();//禁用默认的消息
            context.buildconstraintviolationwithtemplate("新添加的错误消息").addconstraintviolation();
            return false;
        }
        return true;
    }
}

然后就可以和其他注解一样使用它了

封装

或者是将验证参数的代码提取去出来,单独写一个方法

    public static void validateparams(object object) {
        validator validator = validation.builddefaultvalidatorfactory().getvalidator();//获取一个验证器
        set<constraintviolation<object>> violationset = validator.validate(object);//验证数据,获取到错误集合
        iterator<constraintviolation<object>> iterator = violationset.iterator();
        if (iterator.hasnext()) {
            string errormessage = iterator.next().getmessage();//获取到错误信息
            throw new validationexception(errormessage);
        }
    }

当然这里也可以不抛出异常,而返回一个boolean值,如何封装看实际需求

配合spring使用

    @getmapping("/test")
    public integer lookcanbuygoods(@valid jsrtest req, bindingresult result) throws exception {
        if (result.haserrors()) {
            throw new validationexception(result.getallerrors().get(0).getdefaultmessage());
        }
        //do something...
        return 1;
    }

@valid添加这个注解之后就会对参数进行验证,如果在其后没有跟bindingresult,验证不通过就会直接抛出异常,如果添加了bindingresult参数,就不会直接抛出异常,而会把异常信息存储在bindingresult中,供开发者自行处理

如果想要使用分组可以这样

    @getmapping("/test")
    public integer test(@validated (jsrtest.validationgroup.class) jsrtest req, bindingresult result) throws exception {
        if (result.haserrors()) {
            throw new validationexception(result.getallerrors().get(0).getdefaultmessage());
        }
        //do something...
        return 1;
    }

@validated如果不使用分组其作用和@valid一致

注解使用说明

constraint 详细信息
@null 被注释的元素必须为 null
@notnull 被注释的元素必须不为 null
@asserttrue 被注释的元素必须为 true
@assertfalse 被注释的元素必须为 false
@min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@decimalmin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@decimalmax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@size(max, min) 被注释的元素的大小必须在指定的范围内
@digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@past 被注释的元素必须是一个过去的日期
@pastorpresent 被注释的元素必须是过去或现在的日期
@future 被注释的元素必须是一个将来的日期
@futureorpresent 被注释的元素必须是将来或现在的日期
@pattern(value) 被注释的元素必须符合指定的正则表达式
@digits(integer =, fraction =) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度
@email 验证是否是邮件地址,如果为null,不进行验证,算通过验证
@notblank 字符串不能是null还有被trim的长度要大于0
@notempty 不能为null,且长度大于0
@negative 被注释的元素必须是负数
@negativeorzero 被注释的元素必须是负数或0
@positive 必须是正数
@positiveorzero 必须是正数或0

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。