SpringMVC整合Hibernate Validator進行註解式的參數校正——讓代碼更少、更加專註於商務邏輯

來源:互聯網
上載者:User
SpringMVC整合Hibernate Validator進行註解式的參數校正
                                                        ——讓代碼更少、更加專註於商務邏輯
1 問題背景:

參數驗證是一個常見的問題,例如驗證使用者輸入的密碼是否為空白、郵箱是否合法等。但是無論是前端還是後台,都需對使用者輸入進行驗證,以此來保證系統資料的正確性。對於web來說,有些人可能理所當然的想在前端驗證就行了,但這樣是非常錯誤的做法,前台的驗證一般是通過Javascript,js代碼是可以被禁用和篡改的,所以相對後台檢驗而言,安全性會低一些。前端代碼對於使用者來說是透明的,稍微有點技術的人就可以繞過這個驗證,直接提交資料到後台。無論是前端網頁提交的介面,還是提供給外部的介面,參數驗證隨處可見,也是必不可少的。總之,一切使用者的輸入都是不可信的。

基於這樣的常識,在後端的代碼開發中,參數校正是一個永遠也繞不開的話題。然而編寫參數校正代碼的過程是一個技術含量不高,及其耗時,繁瑣的過程。比如極大多數的參數校正代碼就是:判斷一下使用者名稱是否已經存在、使用者名稱長度是否滿足要求、使用者填寫的郵箱是否合法。年齡參數是不是一個整數等等。為了減少重複代碼的開發,許多有技術積澱的公司,一般都會提供一套或多套特有的參數校正工具類。以此減少代碼量。這種做法在項目中非常普遍,有了這些工具類庫,程式員在編寫業務代碼的過程中,工作效率可以大大提升。

然而,即便聰明如上述做法,我們的商務邏輯中依然還是可以見到大量的參數校正邏輯,倘若項目架構的不夠合理,這些與參數校正邏輯有關的代碼量會更多,真是XXX的裹腳布,又臭又長。大量繁雜的參數校正代碼混雜在商務邏輯中,一來降低了代碼的可讀性;二是讓人對業務本身的理解難度加大,很多剛加入公司的人往往是通過讀碼來理解業務的,公司的一些業務培訓一般只能講個大概,然而在閱讀代碼的過程中稍有不慎便會被這些“額外”的代碼擾亂思路,對於新手,那更是異常噩夢,倘若老員工辭職了,撒手拋給新來的,這樣的項目能不能維護下去都是個問題了。 2 Hibernate Validator介紹:

不過對於java開發人員來說,解決上述難題越來越容易了。隨著大量的Bean Validation 架構的問世,和主流架構對這些校正架構的整合和支援。 我們是非常容易的能將商務邏輯和參數校正代碼相分離的,其實說是分離還不夠恰當,這裡即將要介紹的hibernate Validator可以以註解的方式對參數進行校正,商務邏輯中的極大多數參數校正代碼都可以省去,可以使代碼更簡潔,更加專註於商務邏輯。hibernate Validator是 Bean Validation 的參考實現,Hibernate Validator 提供了 JSR 303 規範中所有內建 constraint 的實現,除此之外還有一些附加的 constraint。為了滿足特定的需求,使用者還可以自實現更多的constraint以便滿足特定的需求。 3 整合 Hibernate Validator前後代碼對比:

為了能一目瞭然的看到整合Hibernate Validator的好處,我們來比較一下下述代碼。假設我們有這樣一個方法, 該方法是從某個SSM(Spring MVC + Spring + Mybatis)項目的controller層摘錄下來的。該方法的目的是查詢所有名字叫某某的男性或女性同胞。名字參數name不可為空值,性別參數gender必須為“F”或“M”,分別代表女性或男性。注意,這裡的範例程式碼將參數校正邏輯放在了controller層,校正通過後再進入service層。可能有的項目會將參數校正挪到service層,當然這不是重點。這個查詢方法的代碼如下:

@RequestMapping(value = "/all", method = RequestMethod.GET)@ResponseBodypublic List<String> getAllPeople(String name, String gender) {        if (StringUtils.isEmpty(name)) {            throw new BusinessException(FALL, "使用者名稱不可為空");        }        if (gender == null || (!gender.equals("F") && !gender.equals("M"))) {            throw new BusinessException(FALL, "性別不合法");        }        return cityService.getAllCitys(name, gender);}

上述查詢方法是在沒有整合Hibernate Validator的項目中,參數校正的一般方式,為了輔助完成參數校正,我們還不得不封裝了一個工具類StringUtils用於判斷字串是否為空白。如果參數異常,則拋出業務異常,該異常會交給架構的異常處理機制進行處理。我們可以看到,僅僅兩個簡單的參數就不得不寫上多行代碼來完成要求。然而,當我們將上述SSM項目與Hibernate Validator整合之後,參數校正可以在方法簽名中完成,方法體內無需寫任何與參數校正相關的代碼邏輯。如果參數校正不通過,同樣也會拋出異常,該異常同樣會交給架構的異常處理機制進行處理。

@RequestMapping(value = "/all", method = RequestMethod.GET)@ResponseBodypublic List<String> getAllPeople(            @NotBlank(message = "使用者名稱不可為空" ) String name,            @Gender(message = "性別不合法") String gender) {        return cityService.getAllCitys(name, gender);}

通過上述代碼的比較,可以很明顯的看到,後者代碼簡潔了很多,在參數數量很多,業務複雜的的方法中,代碼量的差異會更加明顯,同樣的,代碼的可讀性也會有了天壤之別。 4. Spring MVC整合Hibernate Validator步驟:

4.1 如果項目中使用Maven,就需要在pom.xml中添加如下一段,Hibernate需要Java EL運算式,因此需要添加EL的依賴項。

<dependency>   <groupId>org.hibernate</groupId>   <artifactId>hibernate-validator</artifactId>   <version>5.3.4.Final</version></dependency><dependency>   <groupId>javax.el</groupId>   <artifactId>javax.el-api</artifactId>   <version>2.2.4</version></dependency><dependency>   <groupId>org.glassfish.web</groupId>   <artifactId>javax.el</artifactId>   <version>2.2.4</version></dependency>

4.2 在springmvc的設定檔(此處使用預設名:spring-mvc.xml)中添加如下配置開啟校正功能

    <mvc:annotation-driven validator="validator" /><!--    bean層級的校正 方法中的參數bean必須添加@Valid註解,後面緊跟著BindingResult result參數-->    <bean id="validator"        class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">        <property name="providerClass" value="org.hibernate.validator.HibernateValidator" />    </bean><!--    方法層級的校正  要校正的方法所在類必須添加@Validated註解-->    <bean        class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">        <!-- 可以引用自己的 validator 配置,在本文中(下面)可以找到 validator 的參考配置,如果不指定則系統使用預設的 -->        <property name="validator" ref="validator" />    </bean>

4.3 在校正的方法所在類上添加@Validated註解可以開啟方法層級的校正,第3節代碼對比的列子中,參數校正註解直接添加在方法簽名上的方法參數前面,這就是所謂的方法層級的校正。所謂bean層級的校正,就是方法的參數是一個Java Bean,校正的註解則添加到Java Bean的相應屬性上。目前,在使用Spring MVC的項目中,bean層級的校正必須給bean參數添加@Valid註解。但在使用Jersey(一個REST FULL的標準實現架構)替代Spring MVC的項目中,則沒有此要求。所以代碼還會更方便。 5 Hibernate Validator 中內建的 constraint簡介

       註解                作用

@Valid 被注釋的元素是一個對象,需要檢查此對象的所有欄位值
@Null 被注釋的元素必須為 null
@NotNull 被注釋的元素必須不為 null
@AssertTrue 被注釋的元素必須為 true
@AssertFalse 被注釋的元素必須為 false
@Min(value) 被注釋的元素必須是一個數字,其值必須大於等於指定的最小值
@Max(value) 被注釋的元素必須是一個數字,其值必須小於等於指定的最大值
@DecimalMin(value) 被注釋的元素必須是一個數字,其值必須大於等於指定的最小值
@DecimalMax(value) 被注釋的元素必須是一個數字,其值必須小於等於指定的最大值
@Size(max, min) 被注釋的元素的大小必須在指定的範圍內
@Digits (integer, fraction) 被注釋的元素必須是一個數字,其值必須在可接受的範圍內
@Past 被注釋的元素必須是一個過去的日期
@Future 被注釋的元素必須是一個將來的日期
@Pattern(value) 被注釋的元素必須符合指定的Regex 6 自訂校正註解樣本

6.1 在第3節中,我們使用到了@Gender註解表示男女的性別,這其實不是Hibernate Validator內建的,而是一個自訂的註解。由於HV中的標準註解可能滿足不了某些校正情境,因此自訂校正註解是有必要的。之所以寫本文,目的是推薦公司的項目也也可以嘗試使用這個優秀的bean validation架構,所以自訂註解的實現細節此處不進一步講述,只是給出兩個已經實現的列子,一個是之前使用到的註解@Gender,用於校正使用者的性別。另一個註解是@PhoneNumber, 用於限制上傳的參數必須是手機號。

6.2 @Gender註解類代碼如下:

@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = Gender.Validator.class)@SuppressWarnings("javadoc")public @interface Gender{    String message() default "invalid gender";    boolean allowBlank() default false;    Class<?>[] groups() default {};    Class<? extends Payload>[] payload() default{};    public class Validator implements ConstraintValidator<Gender, String>    {        boolean allowBlank;        @Override        public void initialize(Gender gender)        {            allowBlank = gender.allowBlank();        }        @Override        public boolean isValid(String arg0, ConstraintValidatorContext arg1)        {            if (arg0 == null)            {                return allowBlank;            }            return arg0.equalsIgnoreCase("M") || arg0.equalsIgnoreCase("F");        }    }}

6.2 @PhoneNumber註解如下:

@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = PhoneNumber.Validator.class)@SuppressWarnings("javadoc")public @interface PhoneNumber {    String message() default "invalid phone number";    Class<?>[] groups() default {};    Class<? extends Payload>[] payload() default {};    public class Validator implements ConstraintValidator<PhoneNumber, String> {        @Override        public void initialize(PhoneNumber arg0)        {        }        @Override        public boolean isValid(String arg0, ConstraintValidatorContext arg1)        {            return StringUtil.isPhoneNumber(arg0);        }}}

@PhoneNumber註解中用到的工具類StringUtil的isPhoneNumber方法如下:

public final String PHONE ="^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,5-8])|(18[0-9]))\\d{8}$";public static boolean isPhoneNumber(String phone)    {        if (StringUtil.isNullOrEmpty(phone))        {            return false;        }        return match(RegExp.PHONE, phone);    }
7 簡單總結

本文主要介紹了hibernate Validator這一優秀的Bean Validation架構。並介紹了Spring MVC中整合這個參數校正框如何將商務邏輯與參數校正邏輯相分離,從而保持代碼的精簡和優雅。易讀和易維護。本人之前所在公司的多重專案採用了這種方式,使得項目代碼無比清爽。本人也願意分享自己積累的一點微薄知識,如果將本文涉及的技術與上一篇篇經驗案列講到的內容聯合使用,更會使項目增色不少,但願在後續的項目中,本人能見證這一成熟技術的應用。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.