使用Hibernate Validator進(jìn)行REST接口上的數(shù)據(jù)校驗(yàn)

本文部分內(nèi)容來自互聯(lián)網(wǎng)。

在進(jìn)行REST接口開發(fā)的時(shí)候,需要對(duì)POST/PUT等接口傳入的參數(shù)進(jìn)行一些校驗(yàn)的時(shí)候,可以通過Hibernate Validator提供的注解進(jìn)行校驗(yàn)。這些注解放在參數(shù)實(shí)體定義的屬性或者類上面,能夠進(jìn)行默認(rèn)的校驗(yàn)。
配合@Valid注解和BindingResult功能一起使用,則可以在Controller的具體實(shí)現(xiàn)邏輯中進(jìn)行校驗(yàn)后的處理。

1. 常用的校驗(yàn)注解

注解 功能
@NotNull 值不為空
@Null 值只能為空
@Pattern(regex=) 字符串必須匹配括號(hào)內(nèi)的正則表達(dá)式
@Size(max=,min=) 集合的元素?cái)?shù)量必須max和min之間的值
@CreditCardNumber(ignoreNonDigitCharacters=) 字符串必須是美國(guó)標(biāo)準(zhǔn)的信用卡卡號(hào)
@Email 字符串必須是email地址
@Length(min=,max=) 檢查字符串的長(zhǎng)度
@NotBlank 字符串必須有字符
@NotEmpty 字符串不為null,集合有元素
@Range(min=,max=) 數(shù)字必須大于min,小于max
@SafeHtml 字符串是安全的html代碼
@URL 字符串是合法的url
@AssertFalse 值必須是false
@AssertTrue 值必須是true
@DecimalMax(value=,inclusive=) 值必須小于等于(inclusive=true)/值必須小于(inclusive=false):可以注解在字符串類型上
@DecimalMin(value=,inclusive=) 值必須大于等于(inclusive=true)/值必須大于(inclusive=false):可以注解在字符串類型上
@Max(value=) 值必須小于等于value指定的值,不能注解在字符串類型上
@Min(value=) 值必須大于等于value執(zhí)行的值,不能注解在字符串類型上
@Digits(integer=,fraction=) 數(shù)字格式檢查,integer指定整數(shù)部分的長(zhǎng)度,fraction指定小數(shù)部分的長(zhǎng)度
@Futrue 值必須是未來的注解
@Past 值只能是過去的時(shí)間

2. 在服務(wù)中使用校驗(yàn)

例如,通過請(qǐng)求添加一個(gè)用戶信息,

  1. 那么首先需要在這個(gè)用戶的定義時(shí)確定好要滿足哪些信息。比如,用戶名不能為空,密碼不能為空等。
public class UserInfo {
    private int id;
    @NotBlank
    private String name;
    @NotNull
    private String passwd;
    @Range(min=10, message = "年齡不能小于10")
    private int age;
    private String mail;
    private String phoneNumber;
    private String address;
}
  1. 通過REST的post接口添加用戶,則用戶信息的body體必須滿足這些條件,否則的話controller的服務(wù)中,就要校驗(yàn),并捕獲這些異常。
/**
     * 添加一個(gè)新的用戶
     */
    @PostMapping(value = "/user")
    public UserInfo addOneSpecifiedUser(@Valid UserInfo userInfo, BindingResult errors) {
        if(errors.hasErrors()){
            errors.getAllErrors().stream().forEach(
                    error -> logger.error(error.toString())
            );
        }

        logger.info("進(jìn)入到用戶添加的頁面");
        return userInfo;
    }

@Valid注解的功能是檢查REST請(qǐng)求推送來的請(qǐng)求體是否滿足預(yù)定義的格式,如果不滿足,那么這些請(qǐng)求中的錯(cuò)誤信息將會(huì)被BindingResult綁定的變量errors所接收,并帶著這些異常進(jìn)入請(qǐng)求響應(yīng)代碼,由請(qǐng)求響應(yīng)部分去處理這些異常。

  1. 使用REST工具發(fā)送這樣的請(qǐng)求后,產(chǎn)生的效果如下:
2018-04-25 10:41:09.303 ERROR 3240 --- [nio-8080-exec-9] o.l.s.controller.UserController          : Field error in object 'userInfo' on field 'age': rejected value [1]; codes [Range.userInfo.age,Range.age,Range.int,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.age,age]; arguments []; default message [age],9223372036854775807,10]; default message [年齡不能小于10]
2018-04-25 10:41:09.303 ERROR 3240 --- [nio-8080-exec-9] o.l.s.controller.UserController          : Field error in object 'userInfo' on field 'passwd': rejected value [null]; codes [NotNull.userInfo.passwd,NotNull.passwd,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.passwd,passwd]; arguments []; default message [passwd]]; default message [不能為null]

3. 自定義校驗(yàn)

要實(shí)現(xiàn)類似于本文中提供那些常用校驗(yàn)方式同樣的便利,需要自定義我們自己的校驗(yàn)規(guī)則注解。

自定義注解進(jìn)行校驗(yàn)的步驟

  1. 寫一個(gè)校驗(yàn)注解,在注解中指定校驗(yàn)器類,校驗(yàn)注解與校驗(yàn)器一般一一對(duì)應(yīng)。
  2. 寫一個(gè)校驗(yàn)器類并在校驗(yàn)器類中寫校驗(yàn)邏輯,校驗(yàn)器必須實(shí)現(xiàn)ConstraintValidator<?, ?>接口,第一個(gè)參數(shù)是對(duì)應(yīng)的注解,第二個(gè)參數(shù)是要校驗(yàn)的屬性的類型。

代碼實(shí)例

S1: 自定義校驗(yàn)注解

package com.kunlun.validation.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

import com.kunlun.validation.validator.KlPatternValidator;

/**
 * 自定義的校驗(yàn)注解
 * 規(guī)則:
 *  1.如果字符串為空串或者為null,則不進(jìn)行正則校驗(yàn)
 *  2.如果字符串不為空串,則必須進(jìn)行正則校驗(yàn)
 * @author xc
 * @date 2018年1月19日上午11:38:02
 */
@Documented
// 指定該注解可以使用的地方
@Target(value= {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
// 指定實(shí)際進(jìn)行校驗(yàn)的校驗(yàn)器,該校驗(yàn)器是自己寫的且必須實(shí)現(xiàn)ConstraintValidator接口
@Constraint(validatedBy=KlPatternValidator.class)
public @interface KlPattern {
    /*
     * 用于驗(yàn)證的注解下列這三個(gè)方法必須要,這是Hibernate Validation框架要求的,否則程序再在調(diào)用的時(shí)候會(huì)報(bào)錯(cuò)
     * default用于對(duì)屬性給定默認(rèn)值
     *  如果不給定默認(rèn)值,則在使用注解的時(shí)候必須給屬性指定屬性值,否則報(bào)錯(cuò)
     *  給定默認(rèn)值時(shí),在使用注解的時(shí)候可以不用指定屬性值
     */
    String message() default "不符合正則!";

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

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

    // 沒加default給定默認(rèn)值,使用注解的時(shí)候該屬性必須賦值,否則報(bào)錯(cuò)
    String regex();
    // value屬性,加上了default "mercy" 使得該屬性在使用注解的時(shí)候可以不用輸入也不會(huì)報(bào)錯(cuò)
    String value() default "mercy";
}

S2: 與上面校驗(yàn)注解對(duì)應(yīng)的校驗(yàn)器類

package com.kunlun.validation.validator;

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

import com.kunlun.validation.annotation.KlPattern;

/**
 * KlPatternValidator是KlPattern注解實(shí)際調(diào)用的驗(yàn)證器
 * 在KlPatternValidator中完成校驗(yàn)邏輯
 * 
 * @author xc
 * @date 2018年1月19日上午11:44:38
 */
public class KlPatternValidator implements ConstraintValidator<KlPattern, String> {

    private String regex;

    /**
     * 通過initialize()可以獲取注解里的屬性值
     */
    @Override
    public void initialize(KlPattern constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
        regex = constraintAnnotation.regex();
    }

    /**
     * 實(shí)際驗(yàn)證邏輯
     *  返回值為true表示驗(yàn)證通過,
     *  返回值為false表示驗(yàn)證未通過
     */
    @Override
    public boolean isValid(String s, ConstraintValidatorContext ctx) {

        // 當(dāng)前前端傳過來的請(qǐng)求參數(shù)是空串,或者沒傳的時(shí)候,不進(jìn)行后續(xù)正則校驗(yàn)
        if ("".equals(s) || s == null) {
            return true;
        }

        // 進(jìn)行正則校驗(yàn)
        if(s.matches(regex)) {
            return true;
        }

        return false;
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 摘要:MVC模式早在上個(gè)世紀(jì)70年代就誕生了,直到今天它依然存在,可見生命力相當(dāng)之強(qiáng)。MVC模式最早用于Small...
    在風(fēng)口閱讀 1,600評(píng)論 1 20
  • SpringMVC介紹之Validation 對(duì)于任何一個(gè)應(yīng)用而言在客戶端做的數(shù)據(jù)有效性驗(yàn)證都不是安全有效的,這時(shí)...
    yongguang423閱讀 1,230評(píng)論 0 16
  • 一、什么是REST REST是一種軟件架構(gòu)風(fēng)格,或者說是一種規(guī)范,其強(qiáng)調(diào)HTTP應(yīng)當(dāng)以資源為中心,并且規(guī)范了URI...
    Ferrari1001閱讀 44,527評(píng)論 3 32
  • 文/李曉 圖/網(wǎng)圖 每一件事情都有溝通成本。尤其是在教別人一件你已經(jīng)會(huì)的事情的時(shí)候。最最簡(jiǎn)單的例子,你需要做一張報(bào)...
    adaya閱讀 823評(píng)論 0 2
  • 放學(xué)歸來,和老媽一起到家門口的絲域養(yǎng)發(fā)館洗頭。 往日,老媽都帶我去朗斯洗頭,鬧哄哄的,而剛走進(jìn)這里,婉...
    阿莫靈閱讀 227評(píng)論 0 0

友情鏈接更多精彩內(nèi)容