参数校验框架 Hibernate Validator

一、场景:

一般我们的参数校验是这样的
在这里插入图片描述
概括一下如下图:
​​​​​​​在这里插入图片描述

通过上图有没有发现,数据校验可谓是贯穿所有的应用程序层,一个 API 接口或方法不简单只有两个输入参数,多则几十个参数,都在进行参数校验,这样既耗时又容易出错。

有没有办法简化这个流程呢?

大家都知道 Optional 类。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException),它也能对参数校验起到一定作用,但是用着用着发现并不太好用,这不是我想要的,还有其他办法吗?

话不多说看图,我想要的是这个样子:
​​​​​​​​​​在这里插入图片描述
能不能做到呢?请往下看

今天我们就尝试打造一款款轮子,不再纠结参数校验,通过简单的配置就可以完成校验;可以腾出更多时间,去完成业务代码的编写;充分达到验证与业务剥离。

接下来我们的参数校验框架 Hibernate Validator就隆重登场了,那 Hibernate Validator 到底是啥?Hibernate Validator 是 JSR 380 数据校验规范的一种实现。

二、实现

第一步:引入依赖包
compile ‘org.hibernate:hibernate-validator:6.0.17.Final’
compile ‘org.glassfish:javax.el:3.0.1-b09’

校验常用注解如下图:
在这里插入图片描述
第二步:定义请求对象,添加校验规则。

public class UserModel1 {


    @NotNull(message = "[接口版本号]不能为空!")
    @Pattern(regexp = "^(\\d+)(\\.\\d+)?$", message = "[接口版本号]格式错误!")
    @Size(min = 0, max = 4, message = "[接口版本号]长度错误,最大长度为[{max}]!")
    private String versionNo;

    @NotNull(message = "[手机号]不能为空!")
    @Size(min = 0, max = 11, message = "[用户手机号码]长度错误,最大长度为[{max}]!")
    private String mobile;

    @NotNull(message = "[订单号]不能为空!")
    @Size(min = 0, max = 32, message = "[订单号]长度错误,最大长度为[{max}]!")
    private String orderId;

    @NotNull(message = "[验证码]不能为空!")
    @Size(min = 0, max = 6, message = "[验证码]长度错误,最大长度为[{max}]!")
    private String smsCode;

    @Email
    private String email;

    public String getVersionNo() {
        return versionNo;
    }

    public void setVersionNo(String versionNo) {
        this.versionNo = versionNo;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public String getSmsCode() {
        return smsCode;
    }

    public void setSmsCode(String smsCode) {
        this.smsCode = smsCode;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

第三步:直接封装工具类。

public class ValidateUtil {

    public static <T> void validate(T t) {
        if (null == t) {
            throw new ValidateException("001", "参数为空");
        }

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        //把对象放到验证器的验证方法中,用Set存储违背约束的对象
        Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
        List<String> errorList = new ArrayList<>();
        for (ConstraintViolation<T> constraintViolation : constraintViolations) {
            errorList.add(constraintViolation.getMessage());
        }
        if (!errorList.isEmpty()) {
            throw new ValidateException("001", errorList.toString());
        }
    }
}

第四步:自定义异常,这个根据实际情况而定,非必须

public class ValidateException extends RuntimeException {
    private String code;
    private String msg;

    /**
     * @param code 异常码
     * @param msg  异常消息
     */
    public ValidateException(String code, String msg) {
        super(msg);
        this.setCode(code);
        this.setMsg(msg);
    }

    public ValidateException() {
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

第五步:测试。

public class ValidateTest {
    public static void main(String[] args) {
        UserModel1 request = new UserModel1();
//        @CreditCardNumber信用卡验证
//        @Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
        request.setVersionNo("123");
        request.setMobile("138013800000");
        request.setEmail("130@qq.com");
        try {
            ValidateUtil.validate(request);
        } catch (ValidateException e) {
            //TODO 在实际业务中直接获取异常码、异常信息进行包装返回给前端即可
            System.out.println(String.format("code: %s, msg:%s", e.getCode(), e.getMsg()));
        }

    }
}

结果:
在这里插入图片描述
三、自定义校验实现

package annotation;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Constraint(validatedBy = MyCheckImpl.class)
public @interface MyCheck {

    String message() default "未知错误";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };


}
package annotation;


import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class MyCheckImpl implements ConstraintValidator<MyCheck, String>{

    @Override
    public void initialize(MyCheck constraintAnnotation) {

    }

    @Override
    public boolean isValid(String arg0, ConstraintValidatorContext arg1) {

        // 具体校验方法
        if("男".equals(arg0)||"女".equals(arg0)){
            return true;
        }

        return false;

    }

}

在之前的实体类中使用我们的自定义校验
在这里插入图片描述
在这里插入图片描述

有没有激起大家兴趣呢?赶快尝试一下吧!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值