使用Bean Validation實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)

Bean Validation

簡介

Bean Validation是Java定義的一套基于注解的數(shù)據(jù)校驗(yàn)規(guī)范,目前已經(jīng)從JSR 303的1.0版本升級到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),已經(jīng)經(jīng)歷了三個版本

"數(shù)據(jù)校驗(yàn)"是這個比較常見的工作,在日常的開發(fā)中貫穿于代碼的各個層次,從上層的View層到下底層的數(shù)據(jù)層,為了保證程序的正確運(yùn)行以及數(shù)據(jù)的正確性歧寺,開發(fā)者通常會在不同層次間做數(shù)據(jù)校驗(yàn)而且這些校驗(yàn)通常是重復(fù)的燥狰,為了實(shí)現(xiàn)代碼的復(fù)用性,通常會把校驗(yàn)的邏輯寫在被校驗(yàn)對象上斜筐。

Bean Validation就是為了解決這樣的問題龙致,它定義了一套元數(shù)據(jù)模型和API對JavaBean實(shí)現(xiàn)校驗(yàn),默認(rèn)是以注解作為元數(shù)據(jù)顷链,可以通過XML重寫或者拓展元數(shù)據(jù)目代,通常來說注解的方式可以實(shí)現(xiàn)比較簡單邏輯的校驗(yàn),而復(fù)雜校驗(yàn)就需要通過XML來描述嗤练¢涣耍可以說Bean Validation是JavaBean的一個拓展,也就是說它布局于哪一層的代碼煞抬,不局限于Web應(yīng)用還是端應(yīng)用霜大。

Bean Validation 2.0 關(guān)注點(diǎn)

  • 使用Bean Validation的最低Java版本為Java 8
  • 支持容器的校驗(yàn),通過TYPE_USE類型的注解實(shí)現(xiàn)對容器內(nèi)容的約束:List<@Email String>
  • 支持日期/時間的校驗(yàn)革答,@Past和@Future
  • 拓展元素?cái)?shù)據(jù):@Email战坤,@NotEmpty,@NotBlank残拐,@Positive途茫, @PositiveOrZero,@Negative溪食,@NegativeOrZero囊卜,@PastOrPresent和@FutureOrPresent

Bean Validation的實(shí)現(xiàn)

Bean Validation在2.0之前有兩個官方認(rèn)可的實(shí)現(xiàn):Hibernate ValidatorApache BVal,但如果你想用2.0版本的話错沃,基本上只有Hibernate Validator栅组,而這里我使用的是Hibernate Validator,其他實(shí)現(xiàn)不做展開枢析。

使用

安裝依賴

<!--版本自行控制笑窜,這里只是簡單舉例-->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.0.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.1.Final</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.el</artifactId>
    <version>3.0.1-b09</version>
</dependency>

Demo-直接使用

  • 一個簡單的JavaBean
public class User {
    private String name;
    private String gender;
    @Positive
    private int age;
    private List<@Email String> emails;

    // getter and setter 
    // ...
}
  • 使用Validator校驗(yàn)
User user = new User();

user.setName("seven");
user.setGender("man");
user.setAge(-1);
user.setEmails(Arrays.asList("sevenlin@gmail.com", "sevenlin.com"));

Set<ConstraintViolation<User>> result = Validation.buildDefaultValidatorFactory().getValidator().validate(user);

List<String> message
    = result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())
        .collect(Collectors.toList());

message.forEach(System.out::println);
  • 校驗(yàn)結(jié)果
emails[1].<list element> must be a well-formed email address: sevenlin.com
age must be greater than 0: -1

集成到Spring MVC

  • 配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public Validator getValidator(); {
        // ...
    }
}

注意,使用Spring MVC 的時候登疗,Spring會默認(rèn)注冊從classpath下找到的可用Bean Validation,所以如果不需要自定義Validation

  • 在Controller中校驗(yàn)請求參數(shù)
    使用注解@Valid@Validated實(shí)現(xiàn)對請求參數(shù)的校驗(yàn)
@PostMapping(value = "/create")
@ResponseBody
public ResponseEntity<User> create(@RequestBody @Validated UserForm form) {
    User user = userService.create(form);
    return ResponseEntity.ok().body(user);
}
  • 配置統(tǒng)一校驗(yàn)結(jié)果處理
@ControllerAdvice
public class ValidationResponseAdvice extends ResponseEntityExceptionHandler {
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        String message = ex.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(","));
        return ResponseEntity.badRequest().body(message);
    }
}

常見的元數(shù)據(jù)

meta-data comment version
@Null 對象嫌蚤,為空 Bean Validation 1.0
@NotNull 對象辐益,不為空 Bean Validation 1.0
@AssertTrue 布爾,為True Bean Validation 1.0
@AssertFalse 布爾脱吱,為False Bean Validation 1.0
@Min(value) 數(shù)字智政,最小為value Bean Validation 1.0
@Max(value) 數(shù)字,最大為value Bean Validation 1.0
@DecimalMin(value) 數(shù)字箱蝠,最小為value Bean Validation 1.0
@DecimalMax(value) 數(shù)字续捂,最大為value Bean Validation 1.0
@Size(max, min) min<=value<=max Bean Validation 1.0
@Digits (integer, fraction) 數(shù)字垦垂,某個范圍內(nèi) Bean Validation 1.0
@Past 日期,過去的日期 Bean Validation 1.0
@Future 日期牙瓢,將來的日期 Bean Validation 1.0
@Pattern(value) 字符串劫拗,正則校驗(yàn) Bean Validation 1.0
@Email 字符串,郵箱類型 Bean Validation 2.0
@NotEmpty 集合矾克,不為空 Bean Validation 2.0
@NotBlank 字符串页慷,不為空字符串 Bean Validation 2.0
@Positive 數(shù)字,正數(shù) Bean Validation 2.0
@PositiveOrZero 數(shù)字胁附,正數(shù)或0 Bean Validation 2.0
@Negative 數(shù)字酒繁,負(fù)數(shù) Bean Validation 2.0
@NegativeOrZero 數(shù)字,負(fù)數(shù)或0 Bean Validation 2.0
@PastOrPresent 過去或者現(xiàn)在 Bean Validation 2.0
@FutureOrPresent 將來或者現(xiàn)在 Bean Validation 2.0

其他

相關(guān)鏈接

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末控妻,一起剝皮案震驚了整個濱河市州袒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弓候,老刑警劉巖郎哭,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弓叛,居然都是意外死亡彰居,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進(jìn)店門撰筷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陈惰,“玉大人,你說我怎么就攤上這事毕籽√Т常” “怎么了?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵关筒,是天一觀的道長溶握。 經(jīng)常有香客問我,道長蒸播,這世上最難降的妖魔是什么睡榆? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮袍榆,結(jié)果婚禮上胀屿,老公的妹妹穿的比我還像新娘。我一直安慰自己包雀,他們只是感情好宿崭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著才写,像睡著了一般葡兑。 火紅的嫁衣襯著肌膚如雪奖蔓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天讹堤,我揣著相機(jī)與錄音吆鹤,去河邊找鬼。 笑死蜕劝,一個胖子當(dāng)著我的面吹牛檀头,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播岖沛,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼暑始,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了婴削?” 一聲冷哼從身側(cè)響起廊镜,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唉俗,沒想到半個月后嗤朴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虫溜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年雹姊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衡楞。...
    茶點(diǎn)故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡吱雏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瘾境,到底是詐尸還是另有隱情歧杏,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布迷守,位于F島的核電站犬绒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏兑凿。R本人自食惡果不足惜凯力,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望礼华。 院中可真熱鬧沮协,春花似錦、人聲如沸卓嫂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晨雳。三九已至行瑞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間餐禁,已是汗流浹背血久。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帮非,地道東北人氧吐。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像末盔,于是被迫代替她去往敵國和親筑舅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評論 2 349

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