告別 if-else 校驗代碼參數(shù)校驗這么寫才足夠優(yōu)雅_第1頁
告別 if-else 校驗代碼參數(shù)校驗這么寫才足夠優(yōu)雅_第2頁
告別 if-else 校驗代碼參數(shù)校驗這么寫才足夠優(yōu)雅_第3頁
告別 if-else 校驗代碼參數(shù)校驗這么寫才足夠優(yōu)雅_第4頁
告別 if-else 校驗代碼參數(shù)校驗這么寫才足夠優(yōu)雅_第5頁
已閱讀5頁,還剩14頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

告別if-else校驗代碼,參數(shù)校驗這么寫才足夠優(yōu)雅很痛苦遇到大量的參數(shù)進(jìn)行校驗,在業(yè)務(wù)中還要拋出異?;蛘卟粩嗟姆祷禺惓r的校驗信息,在代碼中相當(dāng)冗長,充滿了if-else這種校驗代碼,今天我們就來學(xué)習(xí)spring的javax.validation注解式參數(shù)校驗.為什么要用validatorjavax.validation的一系列注解可以幫我們完成參數(shù)校驗,免去繁瑣的串行校驗不然我們的代碼就像下面這樣:

//

http://localhost:8080/api/user/save/serial

/**

*

走串行校驗

*

*

@param

userVO

*

@return

*/

@PostMapping("/save/serial")

public

Object

save(@RequestBody

UserVO

userVO)

{

String

mobile

=

userVO.getMobile();

//手動逐個

參數(shù)校驗~

寫法

if

(StringUtils.isBlank(mobile))

{

return

RspDTO.paramFail("mobile:手機號碼不能為空");

}

else

if

(!Pattern.matches("^[1][3,4,5,6,7,8,9][0-9]{9}$",

mobile))

{

return

RspDTO.paramFail("mobile:手機號碼格式不對");

}

//拋出自定義異常等~寫法

if

(StringUtils.isBlank(userVO.getUsername()))

{

throw

new

BizException(Constant.PARAM_FAIL_CODE,

"用戶名不能為空");

}

//

比如寫一個map返回

if

(StringUtils.isBlank(userVO.getSex()))

{

Map

result

=

new

HashMap<>(5);

result.put("code",

Constant.PARAM_FAIL_CODE);

result.put("msg",

"性別不能為空");

return

result;

}

//.........各種寫法

...

userService.save(userVO);

return

RspDTO.success();

}

這被大佬看見,一定說,都9102了還這么寫,然后被勸退了.....什么是javax.validationJSR303是一套JavaBean參數(shù)校驗的標(biāo)準(zhǔn),它定義了很多常用的校驗注解,我們可以直接將這些注解加在我們JavaBean的屬性上面(面向注解編程的時代),就可以在需要校驗的時候進(jìn)行校驗了,在SpringBoot中已經(jīng)包含在starter-web中,再其他項目中可以引用依賴,并自行調(diào)整版本:

javax.validation

validation-api

1.1.0.Final

org.hibernate

hibernate-validator

5.2.0.Final

注解說明

1.@NotNull:不能為null,但可以為empty("","

","

")

2.@NotEmpty:不能為null,而且長度必須大于0

("

","

")

3.@NotBlank:只能作用在String上,不能為null,而且調(diào)用trim()后,長度必須大于0("test")

即:必須有實際字符

驗證注解驗證的數(shù)據(jù)類型說明@AssertFalseBoolean,boolean驗證注解的元素值是false@AssertTrueBoolean,boolean驗證注解的元素值是true@NotNull任意類型驗證注解的元素值不是null@Null任意類型驗證注解的元素值是null@Min(value=值)BigDecimal,BigInteger,byte,short,int,long,等任何Number或CharSequence(存儲的是數(shù)字)子類型驗證注解的元素值大于等于@Min指定的value值@Max(value=值)和@Min要求一樣驗證注解的元素值小于等于@Max指定的value值@DecimalMin(value=值)和@Min要求一樣驗證注解的元素值大于等于@DecimalMin指定的value值@DecimalMax(value=值)和@Min要求一樣驗證注解的元素值小于等于@DecimalMax指定的value值@Digits(integer=整數(shù)位數(shù),fraction=小數(shù)位數(shù))和@Min要求一樣驗證注解的元素值的整數(shù)位數(shù)和小數(shù)位數(shù)上限@Size(min=下限,max=上限)字符串、Collection、Map、數(shù)組等驗證注解的元素值的在min和max(包含)指定區(qū)間之內(nèi),如字符長度、集合大小@Pastjava.util.Date,java.util.Calendar;JodaTime類庫的日期類型驗證注解的元素值(日期類型)比當(dāng)前時間早@Future與@Past要求一樣驗證注解的元素值(日期類型)比當(dāng)前時間晚@NotBlankCharSequence子類型驗證注解的元素值不為空(不為null、去除首位空格后長度為0),不同于@NotEmpty,@NotBlank只應(yīng)用于字符串且在比較時會去除字符串的首位空格@Length(min=下限,max=上限)CharSequence子類型驗證注解的元素值長度在min和max區(qū)間內(nèi)@NotEmptyCharSequence子類型、Collection、Map、數(shù)組驗證注解的元素值不為null且不為空(字符串長度不為0、集合大小不為0)@Range(min=最小值,max=最大值)BigDecimal,BigInteger,CharSequence,byte,short,int,long等原子類型和包裝類型驗證注解的元素值在最小值和最大值之間@Email(regexp=正則表達(dá)式,flag=標(biāo)志的模式)CharSequence子類型(如String)驗證注解的元素值是Email,也可以通過regexp和flag指定自定義的email格式@Pattern(regexp=正則表達(dá)式,flag=標(biāo)志的模式)String,任何CharSequence的子類型驗證注解的元素值與指定的正則表達(dá)式匹配@Valid任何非原子類型指定遞歸驗證關(guān)聯(lián)的對象如用戶對象中有個地址對象屬性,如果想在驗證用戶對象時一起驗證地址對象的話,在地址對象上加@Valid注解即可級聯(lián)驗證此處只列出HibernateValidator提供的大部分驗證約束注解,請參考hibernatevalidator官方文檔了解其他驗證約束注解和進(jìn)行自定義的驗證約束注解定義。實戰(zhàn)演練話不多說,直接走實踐路線,同樣使用的是SpringBoot的快速框架,詳細(xì)代碼見:/leaJone/myb…在公眾號后端架構(gòu)師后臺回復(fù)“架構(gòu)整潔”,獲取一份驚喜禮包。1.@Validated聲明要檢查的參數(shù)這里我們在控制器層進(jìn)行注解聲明

/**

*

走參數(shù)校驗注解

*

*

@param

userDTO

*

@return

*/

@PostMapping("/save/valid")

public

RspDTO

save(@RequestBody

@Validated

UserDTO

userDTO)

{

userService.save(userDTO);

return

RspDTO.success();

}

2.對參數(shù)的字段進(jìn)行注解標(biāo)注import

lombok.Data;

import

org.hibernate.validator.constraints.Length;

import

javax.validation.constraints.*;

import

java.io.Serializable;

import

java.util.Date;

/**

*

@author

LiJing

*

@ClassName:

UserDTO

*

@Description:

用戶傳輸對象

*

@date

2019/7/30

13:55

*/

@Data

public

class

UserDTO

implements

Serializable

{

private

static

final

long

serialVersionUID

=

1L;

/***

用戶ID*/

@NotNull(message

=

"用戶id不能為空")

private

Long

userId;

/**

用戶名*/

@NotBlank(message

=

"用戶名不能為空")

@Length(max

=

20,

message

=

"用戶名不能超過20個字符")

@Pattern(regexp

=

"^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$",

message

=

"用戶昵稱限制:最多20字符,包含文字、字母和數(shù)字")

private

String

username;

/**

手機號*/

@NotBlank(message

=

"手機號不能為空")

@Pattern(regexp

=

"^[1][3,4,5,6,7,8,9][0-9]{9}$",

message

=

"手機號格式有誤")

private

String

mobile;

/**性別*/

private

String

sex;

/**

郵箱*/

@NotBlank(message

=

"聯(lián)系郵箱不能為空")

@Email(message

=

"郵箱格式不對")

private

String

email;

/**

密碼*/

private

String

password;

/***

創(chuàng)建時間

*/

@Future(message

=

"時間必須是將來時間")

private

Date

createTime;

}

3.在全局校驗中增加校驗異常MethodArgumentNotValidException是springBoot中進(jìn)行綁定參數(shù)校驗時的異常,需要在springBoot中處理,其他需要處理ConstraintViolationException異常進(jìn)行處理.為了優(yōu)雅一點,我們將參數(shù)異常,業(yè)務(wù)異常,統(tǒng)一做了一個全局異常,將控制層的異常包裝到我們自定義的異常中為了優(yōu)雅一點,我們還做了一個統(tǒng)一的結(jié)構(gòu)體,將請求的code,和msg,data一起統(tǒng)一封裝到結(jié)構(gòu)體中,增加了代碼的復(fù)用性import

com.boot.lea.mybot.dto.RspDTO;

import

org.slf4j.Logger;

import

org.slf4j.LoggerFactory;

import

org.springframework.dao.DuplicateKeyException;

import

org.springframework.web.bind.MethodArgumentNotValidException;

import

org.springframework.web.bind.annotation.ExceptionHandler;

import

org.springframework.web.bind.annotation.RestControllerAdvice;

import

org.springframework.web.servlet.NoHandlerFoundException;

import

javax.validation.ConstraintViolationException;

import

javax.validation.ValidationException;

/**

*

@author

LiJing

*

@ClassName:

GlobalExceptionHandler

*

@Description:

全局異常處理器

*

@date

2019/7/30

13:57

*/

@RestControllerAdvice

public

class

GlobalExceptionHandler

{

private

Logger

logger

=

LoggerFactory.getLogger(getClass());

private

static

int

DUPLICATE_KEY_CODE

=

1001;

private

static

int

PARAM_FAIL_CODE

=

1002;

private

static

int

VALIDATION_CODE

=

1003;

/**

*

處理自定義異常

*/

@ExceptionHandler(BizException.class)

public

RspDTO

handleRRException(BizException

e)

{

logger.error(e.getMessage(),

e);

return

new

RspDTO(e.getCode(),

e.getMessage());

}

/**

*

方法參數(shù)校驗

*/

@ExceptionHandler(MethodArgumentNotValidException.class)

public

RspDTO

handleMethodArgumentNotValidException(MethodArgumentNotValidException

e)

{

logger.error(e.getMessage(),

e);

return

new

RspDTO(PARAM_FAIL_CODE,

e.getBindingResult().getFieldError().getDefaultMessage());

}

/**

*

ValidationException

*/

@ExceptionHandler(ValidationException.class)

public

RspDTO

handleValidationException(ValidationException

e)

{

logger.error(e.getMessage(),

e);

return

new

RspDTO(VALIDATION_CODE,

e.getCause().getMessage());

}

/**

*

ConstraintViolationException

*/

@ExceptionHandler(ConstraintViolationException.class)

public

RspDTO

handleConstraintViolationException(ConstraintViolationException

e)

{

logger.error(e.getMessage(),

e);

return

new

RspDTO(PARAM_FAIL_CODE,

e.getMessage());

}

@ExceptionHandler(NoHandlerFoundException.class)

public

RspDTO

handlerNoFoundException(Exception

e)

{

logger.error(e.getMessage(),

e);

return

new

RspDTO(404,

"路徑不存在,請檢查路徑是否正確");

}

@ExceptionHandler(DuplicateKeyException.class)

public

RspDTO

handleDuplicateKeyException(DuplicateKeyException

e)

{

logger.error(e.getMessage(),

e);

return

new

RspDTO(DUPLICATE_KEY_CODE,

"數(shù)據(jù)重復(fù),請檢查后提交");

}

@ExceptionHandler(Exception.class)

public

RspDTO

handleException(Exception

e)

{

logger.error(e.getMessage(),

e);

return

new

RspDTO(500,

"系統(tǒng)繁忙,請稍后再試");

}

}

4.測試如下確實做到了參數(shù)校驗時返回異常信息和對應(yīng)的code,方便了我們不再繁瑣的處理參數(shù)校驗在ValidationMperties就是校驗的message,有著已經(jīng)寫好的默認(rèn)的message,且是支持i18n的,大家可以閱讀源碼賞析自定義參數(shù)注解1.比如我們來個自定義身份證校驗注解@Documented

@Target({ElementType.PARAMETER,

ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME)

@Constraint(validatedBy

=

IdentityCardNumberValidator.class)

public

@interface

IdentityCardNumber

{

String

message()

default

"身份證號碼不合法";

Class[]

groups()

default

{};

Class[]

payload()

default

{};

}

這個注解是作用在Field字段上,運行時生效,觸發(fā)的是IdentityCardNumber這個驗證類。message定制化的提示信息,主要是從ValidationMperties里提取,也可以依據(jù)實際情況進(jìn)行定制groups這里主要進(jìn)行將validator進(jìn)行分類,不同的類group中會執(zhí)行不同的validator操作payload主要是針對bean的,使用不多。2.然后自定義Validator這個是真正進(jìn)行驗證的邏輯代碼:public

class

IdentityCardNumberValidator

implements

ConstraintValidator<IdentityCardNumber,

Object>

{

@Override

public

void

initialize(IdentityCardNumber

identityCardNumber)

{

}

@Override

public

boolean

isValid(Object

o,

ConstraintValidatorContext

constraintValidatorContext)

{

return

IdCardValidatorUtils.isValidate18Idcard(o.toString());

}

}

IdCardValidatorUtils在項目源碼中,可自行查看3.使用自定義的注解

@NotBlank(message

=

"身份證號不能為空")

@IdentityCardNumber(message

=

"身份證信息有誤,請核對后提交")

private

String

clientCardNo;

4.使用groups的校驗有的寶寶說同一個對象要復(fù)用,比如UserDTO在更新時候要校驗userId,在保存的時候不需要校驗userId,在兩種情況下都要校驗username,那就用上groups了:在公眾號頂級架構(gòu)師后臺回復(fù)“架構(gòu)”,獲取一份驚喜禮包。先定義groups的分組接口Create和Updateimport

javax.validation.groups.Default;

public

interface

Create

extends

Default

{

}

import

javax.validation.groups.Default;

public

interface

Update

extends

Default{

}

再在需要校驗的地方@Validated聲明校驗組

/**

*

走參數(shù)校驗注解的

groups

組合校驗

*

*

@param

userDTO

*

@return

*/

@PostMapping("/update/groups")

public

RspDTO

update(@RequestBody

@Validated(Update.class)

UserDTO

userDTO)

{

userService.updateById(userDTO);

return

RspDTO.success();

}

在DTO中的字段上定義好groups={}的分組類型@Data

public

class

UserDTO

implements

Serializable

{

private

static

final

long

serialVersionUID

=

1L;

/***

用戶ID*/

@NotNull(message

=

"用戶id不能為空",

groups

=

Update.class)

private

Long

userId;

/**

*

用戶名

*/

@NotBlank(message

=

"用戶名不能為空")

@Length(max

=

20,

message

=

"用戶名不能超過20個字符",

groups

=

{Create.class,

Update.class})

@Pattern(regexp

=

"^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$",

message

=

"用戶昵稱限制:最多20字符,包含文字、字母和數(shù)字")

private

String

username;

/**

*

手機號

*/

@NotBlank(message

=

"手機號不能為空")

@Pattern(regexp

=

"^[1][3,4,5,6,7,8,9][0-9]{9}$",

message

=

"手機號格式有誤",

groups

=

{Create.class,

Update.class})

private

String

mobile;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論