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

前言

javax.validation 是基于JSR-303標(biāo)準(zhǔn)提供的參數(shù)校驗(yàn)規(guī)范舆声,使用注解方式實(shí)現(xiàn)對參數(shù)的校驗(yàn)臼朗,極其方便豹缀。
比較常用的參數(shù)校驗(yàn)注解有:

  • @Null 被注解的元素必須為null
  • @NotNull 被注解的元素必須不為null
  • @AssertTrue 被注解的元素必須為true
  • @AssertFalse 被注解的元素必須為false
  • @Min(value) 被注解的元素必須為數(shù)字藤巢,其值必須大于等于最小值
  • @Max(value) 被注解的元素必須為數(shù)字竟纳,其值必須小于等于最小值
  • @Size(max,min) 被注解的元素的大小必須在指定范圍內(nèi)
  • @Past 被注解的元素必須為過去的一個時間
  • @Future 被注解的元素必須為未來的一個時間
  • @Pattern 被注解的元素必須符合指定的正則表達(dá)式

hibernate里對validation又做了一些拓展撵溃,常用的有以下幾個:

  • @Length 校驗(yàn)字符串的長度是否在指定范圍內(nèi)
  • @Range 校驗(yàn)數(shù)字的范圍
  • @URL 校驗(yàn)url是否合法
實(shí)現(xiàn)自定義拓展注解校驗(yàn)手機(jī)號碼

代碼部分如下:

具有required屬性的基礎(chǔ)校驗(yàn)器

package com.cube.share.base.constraints.validator;

/**
 * @author litb
 * @date 2022/3/21 17:55
 */
public class BaseRequiredValidator {

    protected boolean required;

    public boolean isRequired() {
        return required;
    }

    public void setRequired(boolean required) {
        this.required = required;
    }
}

基于正則校驗(yàn)的基礎(chǔ)校驗(yàn)器

package com.cube.share.base.constraints.validator;

import java.util.regex.Pattern;

/**
 * @author litb
 * @date 2022/3/21 17:56
 */
public class BasePatternValidator extends BaseRequiredValidator {

    protected Pattern pattern;

    public Pattern getPattern() {
        return pattern;
    }

    public void setPattern(Pattern pattern) {
        this.pattern = pattern;
    }
}

提供抽象的具有 required 和 pattern兩個屬性的 校驗(yàn)器

package com.cube.share.base.constraints.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.annotation.Annotation;
import java.util.regex.Matcher;

/**
 * @author litb
 * @date 2022/3/21 18:50
 * <p>
 * 提供抽象的具有 required 和 pattern兩個屬性的 校驗(yàn)器,
 * 子類需要實(shí)現(xiàn){@link AbstractPatternValidator#initialize(Annotation)}
 */
public abstract class AbstractPatternValidator<A extends Annotation> extends BasePatternValidator implements ConstraintValidator<A, String> {

    /**
     * Initializes the validator in preparation for
     * {@link #isValid(String, ConstraintValidatorContext)} calls.
     * The constraint annotation for a given constraint declaration
     * is passed.
     * <p>
     * This method is guaranteed to be called before any use of this instance for
     * validation.
     * <p>
     * The default implementation is a no-op.
     *
     * @param constraintAnnotation annotation instance for a given constraint declaration
     */
    @Override
    public abstract void initialize(A constraintAnnotation);

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (!required && value == null) {
            return true;
        }
        if (value == null) {
            return false;
        }
        Matcher matcher = pattern.matcher(value);
        return matcher.matches();
    }
}

自定義手機(jī)號碼校驗(yàn)注解

package com.cube.share.base.constraints;

import com.cube.share.base.constraints.validator.MobileValidator;

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

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

/**
 * @author litb
 * @date 2022/3/16 10:06
 * <p>
 * 校驗(yàn)手機(jī)號是否合法
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Repeatable(Mobile.List.class)
@Documented
@Constraint(validatedBy = {MobileValidator.class})
public @interface Mobile {

    String message() default "手機(jī)號碼不合法";

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

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

    /**
     * 是否必須有值
     */
    boolean required() default true;

    /**
     * 號碼所在區(qū)域
     */
    Region region() default Region.MAINLAND;

    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RUNTIME)
    @Documented
    @interface List {
        Mobile[] value();
    }

    /**
     * 區(qū)域
     */
    enum Region {
        /**
         * 大陸 (?:0|86|\+86)?1[3-9]\d{9}
         */
        MAINLAND,
        /**
         * 臺灣 (?:0|886|\+886)?(?:|-)09\d{8}
         */
        TW,
        /**
         * 香港 (?:0|852|\+852)?\d{8}
         */
        HK,
        /**
         * 澳門 (?:0|853|\+853)?(?:|-)6\d{7}
         */
        MO
    }
}

自定義注解@Mobile的校驗(yàn)器

package com.cube.share.base.constraints.validator;

import com.cube.share.base.constraints.ConstraintConstants;
import com.cube.share.base.constraints.Mobile;

/**
 * @author litb
 * @date 2022/3/21 17:50
 * <p>
 * 為{@link Mobile}實(shí)現(xiàn)的Validator
 */
public class MobileValidator extends AbstractPatternValidator<Mobile> {

    @Override
    public void initialize(Mobile annotation) {
        required = annotation.required();
        Mobile.Region region = annotation.region();
        switch (region) {
            case MAINLAND:
                pattern = ConstraintConstants.MOBILE_MAINLAND_PATTERN;
                break;
            case HK:
                pattern = ConstraintConstants.MOBILE_HK_PATTERN;
                break;
            case MO:
                pattern = ConstraintConstants.MOBILE_MO_PATTERN;
                break;
            case TW:
                pattern = ConstraintConstants.MOBILE_TW_PATTERN;
                break;
            default:
                throw new IllegalArgumentException("unmatched region");
        }
    }

}

自定義注解@Mobile的用法與validation實(shí)現(xiàn)的其他注解完全相同,在指定參數(shù)加上即可

 /**
     * 手機(jī)號,非必填
     */
    @Mobile(required = false)
    private String mobile;

示例代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锥累,一起剝皮案震驚了整個濱河市缘挑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桶略,老刑警劉巖语淘,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異际歼,居然都是意外死亡惶翻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門鹅心,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吕粗,“玉大人,你說我怎么就攤上這事旭愧∷萜” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵榕茧,是天一觀的道長垃沦。 經(jīng)常有香客問我,道長用押,這世上最難降的妖魔是什么肢簿? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上池充,老公的妹妹穿的比我還像新娘桩引。我一直安慰自己,他們只是感情好收夸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布坑匠。 她就那樣靜靜地躺著,像睡著了一般卧惜。 火紅的嫁衣襯著肌膚如雪厘灼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天咽瓷,我揣著相機(jī)與錄音设凹,去河邊找鬼。 笑死茅姜,一個胖子當(dāng)著我的面吹牛闪朱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钻洒,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼奋姿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了素标?” 一聲冷哼從身側(cè)響起称诗,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糯钙,沒想到半個月后粪狼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡任岸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年再榄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片享潜。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡困鸥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出剑按,到底是詐尸還是另有隱情疾就,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布艺蝴,位于F島的核電站猬腰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏猜敢。R本人自食惡果不足惜姑荷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一盒延、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鼠冕,春花似錦添寺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至憎乙,卻和暖如春票罐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寨闹。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工胶坠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留君账,地道東北人繁堡。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像乡数,于是被迫代替她去往敵國和親椭蹄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容