Java實(shí)現(xiàn)優(yōu)雅的參數(shù)校驗(yàn)方法詳解
一、引子
要對(duì)方法的參數(shù)進(jìn)行校驗(yàn),最簡(jiǎn)單暴力的寫法是這個(gè)樣子:
public static void utilA(String a,BigDecimal b){ if (StringUtils.isEmpty(a)){ System.out.println("a不可為空"); return; } if (b == null){ System.out.println("b不可為空"); return; } if (b.compareTo(BigDecimal.ZERO) != 1){ System.out.println("b的取值范圍不正確"); return; } System.out.println("do something"); }
這樣做從功能角度來(lái)說(shuō)一點(diǎn)問(wèn)題也沒(méi)有。
但是從代碼的長(zhǎng)期維護(hù)性上來(lái)說(shuō),代碼復(fù)用率低,校驗(yàn)規(guī)則一旦多起來(lái)很難維護(hù),而且怎么看怎么顯得笨拙,對(duì)于有一點(diǎn)追求的工程師來(lái)說(shuō),這么一大坨還是挺難接受的。
雖然有一些諸如 Preconditions(com.google) 的解決方案,但很難適應(yīng)所有的場(chǎng)景,用起來(lái)也沒(méi)到非常得心應(yīng)有的地步。
二、如何優(yōu)雅地校驗(yàn)參數(shù)
Spring官方推薦的,語(yǔ)義清晰的優(yōu)雅的方法級(jí)別校驗(yàn)(入?yún)⑿r?yàn)、返回值校驗(yàn))
2.1 官方指導(dǎo)意見(jiàn)
Spring官方在SpringBoot文檔中,關(guān)于參數(shù)校驗(yàn)(Validation)給出的解決方案是這樣的:
@Service @Validated public class MyBean { public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code, Author author) { ... } }
Spring Boot 官網(wǎng)文檔 《37. Validation》
也就是說(shuō),使用 JSR-303 規(guī)范,直接利用注解進(jìn)行參數(shù)校驗(yàn)。
(JSR-303 是 JAVA EE 6 中的一項(xiàng)子規(guī)范,叫做 Bean Validation,官方參考實(shí)現(xiàn)是 Hibernate Validator)
2.2 注解用法說(shuō)明
2.2.1.注解簡(jiǎn)介
對(duì)于簡(jiǎn)單類型參數(shù)(非Bean),直接在參數(shù)前,使用注解添加約束規(guī)則。注解如下所示:
@AssertTrue / @AssertFalse
驗(yàn)證適用字段:boolean
注解說(shuō)明:驗(yàn)證值是否為true / false
@DecimalMax / @DecimalMin
驗(yàn)證適用字段:BigDecimal,BigInteger,String,byte,short,int,long
注解說(shuō)明:驗(yàn)證值是否小于或者等于指定的小數(shù)值,要注意小數(shù)存在精度問(wèn)題
@Digits
驗(yàn)證適用字段:BigDecimal,BigInteger,String,byte,short,int,long
注解說(shuō)明:驗(yàn)證值的數(shù)字構(gòu)成是否合法
屬性說(shuō)明:integer:指定整數(shù)部分的數(shù)字的位數(shù)。fraction: 指定小數(shù)部分的數(shù)字的位數(shù)。
@Future / @Past
驗(yàn)證適用字段:Date,Calendar
注解說(shuō)明:驗(yàn)證值是否在當(dāng)前時(shí)間之后 / 之前
屬性說(shuō)明:公共
@Max / @Min
驗(yàn)證適用字段:BigDecimal,BigInteger,String,byte,short,int,long
注解說(shuō)明:驗(yàn)證值是否小于或者等于指定的整數(shù)值
屬性說(shuō)明:公共
注意事項(xiàng):建議使用在Stirng,Integer類型,不建議使用在int類型上,因?yàn)楸韱翁峤坏闹禐?ldquo;”時(shí)無(wú)法轉(zhuǎn)換為int
@NotNull / @Null
驗(yàn)證適用字段:引用數(shù)據(jù)類型
注解說(shuō)明:驗(yàn)證值是否為非空 / 空
屬性說(shuō)明:公共
@NotBlank 檢查約束字符串是不是Null還有被Trim的長(zhǎng)度是否大于0,只對(duì)字符串,且會(huì)去掉前后空格.
@NotEmpty 檢查約束元素是否為Null或者是EMPTY.
@NotBlank 與 @NotEmpty 的區(qū)別:空格(" ")對(duì)于 NotEmpty 是合法的,而 NotBlank 會(huì)拋出校驗(yàn)異常
@Pattern
驗(yàn)證適用字段:String
注解說(shuō)明:驗(yàn)證值是否配備正則表達(dá)式
屬性說(shuō)明:regexp:正則表達(dá)式flags: 指定Pattern.Flag 的數(shù)組,表示正則表達(dá)式的相關(guān)選項(xiàng)。
@Size
驗(yàn)證適用字段:String,Collection,Map,數(shù)組
注解說(shuō)明:驗(yàn)證值是否滿足長(zhǎng)度要求
屬性說(shuō)明:max:指定最大長(zhǎng)度,min:指定最小長(zhǎng)度。
@Length(min=, max=):專門應(yīng)用于String類型
@Valid
驗(yàn)證適用字段:遞歸的對(duì)關(guān)聯(lián)對(duì)象進(jìn)行校驗(yàn)
注解說(shuō)明:如果關(guān)聯(lián)對(duì)象是個(gè)集合或者數(shù)組,那么對(duì)其中的元素進(jìn)行遞歸校驗(yàn),如果是一個(gè)map,則對(duì)其中的值部分進(jìn)行校驗(yàn)(是否進(jìn)行遞歸驗(yàn)證)
屬性說(shuō)明:無(wú)
@Range(min=, max=) 被指定的元素必須在合適的范圍內(nèi)
@CreditCardNumber信用卡驗(yàn)證
@Email 驗(yàn)證是否是郵件地址,如果為null,不進(jìn)行驗(yàn)證,算通過(guò)驗(yàn)證。
@URL(protocol=,host=, port=,regexp=, flags=)
2.2.2使用
1.引入依賴
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.5.Final</version> </dependency>
2.在對(duì)應(yīng)字段上添加注解,方法被調(diào)用時(shí),如果傳入的實(shí)際參數(shù)與約束規(guī)則不符,會(huì)直接拋出 ConstraintViolationException ,表明參數(shù)校驗(yàn)失敗。
import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotEmpty; /** * @Author: wangxia * @Date: 2021/10/20 16:30 */ public class TestPerson { @NotEmpty(message = "用戶名不能為空") private String username; @Min(value = 0,message = "年齡不能小于0歲") @Max(value =150,message = "年齡不能大于150歲") private int age; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
3..對(duì)于Bean類型的參數(shù),在Bean內(nèi)部的各個(gè)字段上面追加約束注解,然后在方法的參數(shù)前面添加 @Validated或@Valid注解即可。示例:
@RequestMapping("/") @RestController public class TestValidatController { @PostMapping("/testValid") public String testValid(@Validated @RequestBody TestPerson testPerson){ return "測(cè)試成功"; } }
4.優(yōu)雅捕獲異常,這一步可以省略,但是請(qǐng)求時(shí)會(huì)直接返回,400的異常提示,不太優(yōu)雅。
@ControllerAdvice @ResponseBody public class MethodArgumentNotValidHandel { @ExceptionHandler(value=MethodArgumentNotValidException.class) public JSONObject MethodArgumentNotValidHandler(HttpServletRequest request, MethodArgumentNotValidException exception) throws Exception { JSONObject result=new JSONObject(); result.put("code","fail"); JSONObject errorMsg=new JSONObject(); for (FieldError error : exception.getBindingResult().getFieldErrors()) { errorMsg.put(error.getField(),error.getDefaultMessage()); } result.put("msg",errorMsg); return result; } }
添加優(yōu)雅捕獲的異常提示:
未添加優(yōu)雅捕獲的異常提示:
到此這篇關(guān)于Java實(shí)現(xiàn)優(yōu)雅的參數(shù)校驗(yàn)方法詳解的文章就介紹到這了,更多相關(guān)Java參數(shù)校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于ThreadPoolTaskExecutor的使用說(shuō)明
這篇文章主要介紹了基于ThreadPoolTaskExecutor的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11spring+springmvc+mybatis+maven入門實(shí)戰(zhàn)(超詳細(xì)教程)
這篇文章主要介紹了spring+springmvc+mybatis+maven入門實(shí)戰(zhàn)(超詳細(xì)教程),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05IDEA2019.2.2配置Maven3.6.2打開(kāi)出現(xiàn)Unable to import Maven project
這篇文章主要介紹了IDEA2019.2.2配置Maven3.6.2打開(kāi)出現(xiàn)Unable to import Maven project,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12IDEA中Directory創(chuàng)建多級(jí)目錄的實(shí)現(xiàn)
本文主要介紹了IDEA中Directory創(chuàng)建多級(jí)目錄的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06JAVA JDK8 List分組的實(shí)現(xiàn)和用法
今天小編就為大家分享一篇關(guān)于JAVA JDK8 List分組的實(shí)現(xiàn)和用法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12SpringBoot自定義轉(zhuǎn)換器應(yīng)用實(shí)例講解
SpringBoot在響應(yīng)客戶端請(qǐng)求時(shí),將提交的數(shù)據(jù)封裝成對(duì)象時(shí),使用了內(nèi)置的轉(zhuǎn)換器,SpringBoot 也支持自定義轉(zhuǎn)換器,這個(gè)內(nèi)置轉(zhuǎn)換器在 debug的時(shí)候,可以看到,提供了124個(gè)內(nèi)置轉(zhuǎn)換器2022-08-08