springboot中使用Hibernate-Validation

1、說(shuō)明

后端接口設(shè)計(jì)時(shí)候胸囱,需要對(duì)前端請(qǐng)求參數(shù)進(jìn)行'先校驗(yàn)后處理業(yè)務(wù)'情況妹卿,如果在業(yè)務(wù)代碼中通過(guò)類(lèi)似if這里逐個(gè)校驗(yàn)蔑鹦,會(huì)使得代碼變得繁瑣嚎朽,開(kāi)發(fā)工作者都是愛(ài)偷懶的柬帕。java中,Bean ValidationJavaBean的驗(yàn)證定義了相關(guān)的元數(shù)據(jù)模型和API陷寝》锱埽基于Bean-Validation封裝,提供了更加豐富的Hibernate-Validation的校驗(yàn)包仔引。也有開(kāi)發(fā)會(huì)把這類(lèi)校驗(yàn)交給前端來(lái)處理咖耘,但是接口暴露外網(wǎng)會(huì)存在直接調(diào)用情況(黃牛)。畢竟:前端校驗(yàn)是為了提高用戶的體驗(yàn)度版保,后端校驗(yàn)則是為了保證數(shù)據(jù)的安全性

優(yōu)點(diǎn)
1.驗(yàn)證邏輯與業(yè)務(wù)邏輯之間進(jìn)行了分離夫否,降低了程序耦合度
2.統(tǒng)一且規(guī)范的驗(yàn)證方式,無(wú)需你再次編寫(xiě)重復(fù)的驗(yàn)證代碼
3.你將更專(zhuān)注于你的業(yè)務(wù)凰慈,將這些繁瑣的事情統(tǒng)統(tǒng)丟在一邊

2溉瓶、Bean Validation與Hibernate Validation

2.1 Bean Validation中內(nèi)置的constraint

包位置路徑:javax.validation.constraints

image.png

注解 說(shuō)明
@AssertFalse 注釋的元素必須為False
@AssertTrue 注釋的元素必須為T(mén)rue
@Email 注釋的元素必須郵箱
@NotBlank 注釋的元素不能為空堰酿,张足!null && size>0
@NotEmpty 注釋的元素不能為空,數(shù)組哼绑,集合等
@NotNull 注釋的元素必須為空,但可以為""字符串
@DecimalMin 注釋的元素?cái)?shù)字抖韩,最小不得小于Min
@DecimalMax 注釋的元素為數(shù)字茂浮,最大不超過(guò)Max值

其中NotNull、NotEmpty席揽、NotBlank區(qū)別

  • @NotNull
    適用于基本數(shù)據(jù)類(lèi)型(Integer幌羞,Long,Double等等)属桦,當(dāng) @NotNull 注解被使用在 String 類(lèi)型的數(shù)據(jù)上地啰,則表示該數(shù)據(jù)不能為 Null(但是可以為 Empty)
  • @NotBlank
    適用于 String 類(lèi)型的數(shù)據(jù)上,加了@NotBlank 注解的參數(shù)不能為 Null 且 trim() 之后 size > 0
  • @NotEmpty
    適用于 String亏吝、Collection集合蔚鸥、Map、數(shù)組等等止喷,加了@NotEmpty 注解的參數(shù)不能為 Null 或者 長(zhǎng)度為 0
2.1 Hibernate Validation中添加的constraint
image.png
注解 說(shuō)明
@Length 注釋的元素字符串長(zhǎng)度必須為制定返回內(nèi)
@Range 注釋的元素必須在指定范圍內(nèi)
@URL 注釋的元素必須為鏈接

3弹谁、基于Hibernate Validation的實(shí)現(xiàn)

(1)pom包引用
查看spring-boot-start-web中已經(jīng)集成了Hibernate Validation,所以可以不用額外引用包沟于。同時(shí)spring-boot-start-validation也完成了Hibernate Validationstart封裝(校驗(yàn)機(jī)制更加全面)植康。

 <dependency>
        <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-validation</artifactId>
       <version>2.2.6.RELEASE</version>
</dependency>

(2)Bean對(duì)象中使用注解注釋

     ...
    @ApiModelProperty(value = "收貨人所在省",required = true)
    @NotNull(message = "省不能為空")
    private String recipientProvince;

    @ApiModelProperty(value = "收貨人所在市")
    @NotNull(message = "市不能為空")
    private String recipientCity;

    @ApiModelProperty(value = "收貨人所在區(qū)")
    @NotNull(message = "區(qū)不能為空")
    private String recipientDistrict;
    ...

(3)Controller層使用@Valid或者@Validated

 @PostMapping("/add")
 public UniformResultTemplate<Boolean> addAddress(@RequestBody @Validated AddressReqDto reqDto, HttpServletRequest request){
   return null;
 }

注意:Post請(qǐng)求方式區(qū)別,Get@Validated注解需要加在 所在方法類(lèi)前

@RestController
@RequestMapping("/api/address")
@Validated
public class AddressController extends BaseController{

  @ApiOperation("收獲地址詳情")
    @GetMapping("/detail")
    public UniformResultTemplate<AddressDetailRespDto> queryAddressList(@NotNull(message = "地址Id不能為空") 
@RequestParam(value = "addressId") Long addressId, HttpServletRequest request){
        return null;
    }
}

(4)使用@ControllerAdvice統(tǒng)一異常處理返回存崖。

@Component
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    // Post請(qǐng)求Bean中的校驗(yàn)拋出:MethodArgumentNotValidException
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public UniformResultTemplate handleBindException(MethodArgumentNotValidException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        log.warn("參數(shù)校驗(yàn)異常:{}({})", fieldError.getDefaultMessage(),fieldError.getField());
        return new UniformResultTemplate("10002",fieldError.getDefaultMessage());
    }

  // Get請(qǐng)求的參數(shù)校驗(yàn)睡毒,拋出的是ConstraintViolationException
  @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public UniformResultTemplate handleGetBindException(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>>  eSet = ex.getConstraintViolations();
        StringBuffer sb = new StringBuffer();
        if(!CollectionUtils.isEmpty(eSet)) {
            Iterator<ConstraintViolation<?>> iterator = eSet.iterator();
            while (iterator.hasNext()) {
                log.warn("參數(shù)校驗(yàn)異常:{}({})", iterator.next().getMessage());
                sb.append(iterator.next().getMessage()).append("::");
            }
        }
        return new UniformResultTemplate("10002",sb.toString());
    }

  // 方法簽名參數(shù)錯(cuò)誤
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public UniformResultTemplate handleGetBindException(MissingServletRequestParameterException ex) {
        log.warn("參數(shù)校驗(yàn)異常:{}", ex.getMessage());
        return new UniformResultTemplate("10002",ex.getMessage());
    }
}

(5)結(jié)果現(xiàn)象

{
    "code": "10002",
    "message": "市不能為空",
    "result": null,
    "totalTimes": null,
    "interfaceTimes": null
}

4吕嘀、編譯器校驗(yàn)工具

防止因使用錯(cuò)誤Hibernate-Validation注解而導(dǎo)致程序運(yùn)行時(shí)報(bào)錯(cuò)偶房,增加編譯器校驗(yàn)工具,進(jìn)行友好提示棕洋。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
    <version>6.1.5.Final</version>
</dependency>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掰盘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子愧捕,更是在濱河造成了極大的恐慌次绘,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件管跺,死亡現(xiàn)場(chǎng)離奇詭異禾进,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)泻云,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)宠纯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事湃累“郑” “怎么了蒙秒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵晕讲,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我弄息,道長(zhǎng)勤婚,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任缨称,我火速辦了婚禮祝迂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘型雳。我一直安慰自己四啰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布欧瘪。 她就那樣靜靜地躺著匙赞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪涌庭。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天拴魄,我揣著相機(jī)與錄音匹中,去河邊找鬼。 笑死顶捷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的葵蒂。 我是一名探鬼主播重虑,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荔仁!你這毒婦竟也來(lái)了芽死?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤遇骑,失蹤者是張志新(化名)和其女友劉穎揖曾,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體练链,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奴拦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年错妖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潮模。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡痴施,死狀恐怖究流,靈堂內(nèi)的尸體忽然破棺而出锉矢,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布绵估,位于F島的核電站卡骂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏全跨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一渺杉、第九天 我趴在偏房一處隱蔽的房頂上張望挪钓。 院中可真熱鬧,春花似錦倚评、人聲如沸馏予。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蚯妇。三九已至,卻和暖如春箩言,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饭豹。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留它褪,地道東北人翘悉。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像老赤,于是被迫代替她去往敵國(guó)和親制市。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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