在Java EE 6中將Bean驗證與JAX-RS集成

JavaBeans驗證(Bean驗證)是一種新的驗證模型,可作為Java EE 6平臺的一部分使用。 約束條件支持Bean驗證模型,該約束以注釋的形式出現在JavaBeans組件(例如托管Bean)的字段,方法或類上。

javax.validation.constraints包中提供了一些內置約束。 Java EE 6教程列出了所有內置約束。

Bean驗證中的約束通過Java注釋表示:

public class Person {@NotNull@Size(min = 2, max = 50)private String name;// ...
}

Bean驗證和RESTful Web服務

JAX-RS 1.0為提取請求值并將其綁定到Java字段,屬性和參數(使用@HeaderParam@QueryParam等注釋)提供了強大的支持。它還支持通過非注釋參數將請求實體主體綁定到Java對象中(也就是說,未使用任何JAX-RS注釋進行注釋的參數)。 當前,必須以編程方式對資源類中的這些值進行任何其他驗證。

下一個發行版JAX-RS 2.0包含一項建議,以使驗證批注可以與JAX-RS批注結合使用。 例如,給定驗證批注@Pattern ,以下示例顯示如何驗證表單參數。

@GET
@Path('{id}')
public Person getPerson(@PathParam('id')@Pattern(regexp = '[0-9]+', message = 'The id must be a valid number')String id) {return persons.get(id);
}

但是,目前,唯一的解決方案是使用專有實現。 接下來介紹的是基于JBoss的RESTEasy框架的解決方案,該解決方案符合JAX-RS規范,并通過注釋@ValidateRequest添加了RESTful驗證接口。

導出的接口允許我們創建自己的實現。 但是,已經有一種廣泛使用的方法,RESTEasy還向其提供了無縫集成。 這個實現是Hibernate Validator 。 可以通過以下Maven依賴項將此提供程序添加到項目中:

<dependency><groupId>org.jboss.resteasy</groupId><artifactId>resteasy-jaxrs</artifactId><version>2.3.2.Final</version><scope>provided</scope>
</dependency>
<dependency><groupId>org.jboss.resteasy</groupId><artifactId>resteasy-hibernatevalidator-provider</artifactId><version>2.3.2.Final</version>
</dependency>

注意:在類或方法級別不聲明@ValidateRequest@ValidateRequest在方法上應用了約束注釋,也不會進行驗證,例如上面的示例。

@GET
@Path('{id}')
@ValidateRequest
public Person getPerson(@PathParam('id')@Pattern(regexp = '[0-9]+', message = 'The id must be a valid number')String id) {return persons.get(id);
}

應用注釋后,發出請求時將自動驗證參數id
您當然可以通過使用注釋@Valid來驗證整個實體,而不是單個字段。 例如,我們可以有一個接受Person對象并對其進行驗證的方法。

@POST
@Path('/validate')
@ValidateRequest
public Response validate(@Valid Person person) {// ...
}

注意:

默認情況下,當驗證失敗時,容器將引發異常,并將HTTP 500狀態返回給客戶端。 可以/應該重寫此默認行為,使我們能夠自定義通過異常映射器返回給客戶端的Response。

國際化

到目前為止,我們一直在使用默認的或硬編碼的錯誤消息,但這既是一種不好的做法,又一點也不靈活。 I18n是Bean驗證規范的一部分,它使我們能夠使用資源屬性文件來指定自定義錯誤消息。 默認資源文件名稱為ValidationMessages.properties并且必須包含屬性/值對,例如:

person.id.pattern=The person id must be a valid number
person.name.size=The person name must be between {min} and {max} chars long

注意:

{min}{max}是指與消息相關聯的約束的屬性。

然后可以將這些已定義的消息注入驗證約束中,如下所示:

@POST
@Path('create')
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response createPerson(@FormParam('id')@Pattern(regexp = '[0-9]+', message = '{person.id.pattern}')String id,@FormParam('name')@Size(min = 2, max = 50, message = '{person.name.size}')String name) {Person person = new Person();person.setId(Integer.valueOf(id));person.setName(name);persons.put(Integer.valueOf(id), person);return Response.status(Response.Status.CREATED).entity(person).build();
}

要提供其他語言的翻譯,必須使用翻譯后的消息創建一個新的ValidationMessages_XX.properties文件,其中XX是所提供語言的代碼。

不幸的是,Hibernate Validator提供程序不基于特定的HTTP請求支持i18n。 它不考慮Accept-Language HTTP標頭,并且始終使用Locale.getDefault()提供的默認Locale 。 為了能夠改變Locale使用Accept-Language HTTP標頭(例如,改變語言在瀏覽器選項),必須提供自定義實現。

定制驗證器提供商

以下代碼旨在解決此問題,并已通過JBoss AS 7.1進行了測試。

首先要做的是刪除Maven resteasy-hibernatevalidator-provider依賴性,因為我們提供了自己的提供程序,并添加了Hibernate Validator依賴性:

<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>4.2.0.Final</version>
</dependency>

接下來,創建一個自定義消息插值器以調整使用的默認Locale

public class LocaleAwareMessageInterpolator extendsResourceBundleMessageInterpolator {private Locale defaultLocale = Locale.getDefault();public void setDefaultLocale(Locale defaultLocale) {this.defaultLocale = defaultLocale;}@Overridepublic String interpolate(final String messageTemplate,final Context context) {return interpolate(messageTemplate, context, defaultLocale);}@Overridepublic String interpolate(final String messageTemplate,final Context context, final Locale locale) {return super.interpolate(messageTemplate, context, locale);}
}

下一步是提供ValidatorAdapter 。 引入此接口是為了將RESTEasy與實際的驗證API分離。

public class RESTValidatorAdapter implements ValidatorAdapter {private final Validator validator;private final MethodValidator methodValidator;private final LocaleAwareMessageInterpolator interpolator = new LocaleAwareMessageInterpolator();public RESTValidatorAdapter() {Configuration<?> configuration = Validation.byDefaultProvider().configure();this.validator = configuration.messageInterpolator(interpolator).buildValidatorFactory().getValidator();this.methodValidator = validator.unwrap(MethodValidator.class);}@Overridepublic void applyValidation(Object resource, Method invokedMethod,Object[] args) {// For the i8n to work, the first parameter of the method being validated must be a HttpHeadersif ((args != null) && (args[0] instanceof HttpHeaders)) {HttpHeaders headers = (HttpHeaders) args[0];List<Locale> acceptedLanguages = headers.getAcceptableLanguages();if ((acceptedLanguages != null) && (!acceptedLanguages.isEmpty())) {interpolator.setDefaultLocale(acceptedLanguages.get(0));}}ValidateRequest resourceValidateRequest = FindAnnotation.findAnnotation(invokedMethod.getDeclaringClass().getAnnotations(), ValidateRequest.class);if (resourceValidateRequest != null) {Set<ConstraintViolation<?>> constraintViolations = new HashSet<ConstraintViolation<?>>(validator.validate(resource,resourceValidateRequest.groups()));if (constraintViolations.size() > 0) {throw new ConstraintViolationException(constraintViolations);}}ValidateRequest methodValidateRequest = FindAnnotation.findAnnotation(invokedMethod.getAnnotations(), ValidateRequest.class);DoNotValidateRequest doNotValidateRequest = FindAnnotation.findAnnotation(invokedMethod.getAnnotations(),DoNotValidateRequest.class);if ((resourceValidateRequest != null || methodValidateRequest != null)&& doNotValidateRequest == null) {Set<Class<?>> set = new HashSet<Class<?>>();if (resourceValidateRequest != null) {for (Class<?> group : resourceValidateRequest.groups()) {set.add(group);}}if (methodValidateRequest != null) {for (Class<?> group : methodValidateRequest.groups()) {set.add(group);}}Set<MethodConstraintViolation<?>> constraintViolations = new HashSet<MethodConstraintViolation<?>>(methodValidator.validateAllParameters(resource,invokedMethod, args,set.toArray(new Class<?>[set.size()])));if (constraintViolations.size() > 0) {throw new MethodConstraintViolationException(constraintViolations);}}}
}

警告:

需要將@HttpHeaders作為要驗證的方法的第一個參數注入:

@POST
@Path('create')
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response createPerson(@Context HttpHeaders headers,@FormParam('id')@Pattern(regexp = '[0-9]+', message = '{person.id.pattern}')String id,@FormParam('name')@Size(min = 2, max = 50, message = '{person.name.size}')String name) {Person person = new Person();person.setId(Integer.valueOf(id));person.setName(name);persons.put(id, person);return Response.status(Response.Status.CREATED).entity(person).build();
}

最后,創建將選擇以上用于驗證Bean驗證約束的類的提供程序:

@Provider
public class RESTValidatorContextResolver implementsContextResolver<ValidatorAdapter> {private static final RESTValidatorAdapter adapter = new RESTValidatorAdapter();@Overridepublic ValidatorAdapter getContext(Class<?> type) {return adapter;}
}

映射異常

Bean Validation API使用類型為javax.validation.ValidationException或其任何子類的異常報告錯誤情況。 應用程序可以為任何異常提供自定義異常映射提供程序。 JAX-RS實現必須始終使用其泛型類型是異常的最接近超類的提供程序,應用程序定義的提供程序優先于內置提供程序。

異常映射器可能看起來像:

@Provider
public class ValidationExceptionMapper implementsExceptionMapper<MethodConstraintViolationException> {@Overridepublic Response toResponse(MethodConstraintViolationException ex) {Map<String, String> errors = new HashMap<String, String>();for (MethodConstraintViolation<?> methodConstraintViolation : ex.getConstraintViolations()) {errors.put(methodConstraintViolation.getParameterName(),methodConstraintViolation.getMessage());}return Response.status(Status.PRECONDITION_FAILED).entity(errors).build();}
}

上面的示例顯示了ExceptionMapper的實現,該映射映射了MethodConstraintViolationException類型的MethodConstraintViolationException 。 當用@ValidateRequest注釋的方法的一個或多個參數的驗證失敗時,Hibernate Validator實現將引發此異常。 這樣可以確保客戶端收到格式化的響應,而不僅僅是從資源傳播的異常。

源代碼

這篇文章使用的源代碼可以在GitHub上找到 。

警告:

重命名資源屬性文件,以使文件ValidationMessages.properties (即沒有任何后綴)可以映射到Locale.getDefault()返回的Locale

相關文章

  • Java和UTF-8編碼
  • 作為JBoss AS 7模塊運行Drools 5.4.0 Final
  • 比較設備描述存儲庫
  • Java EE 6測試第二部分– Arquillian和ShrinkWrap簡介
  • Java EE 6測試第I部分– EJB 3.1可嵌入API
  • 上一篇文章:將Drools 5.4.0 Final作為JBoss AS 7模塊運行

參考:來自Samaxes博客的JCG合作伙伴 Samuel Santos的Java EE 6中的Bean驗證與JAX-RS集成 。

翻譯自: https://www.javacodegeeks.com/2013/01/integrating-bean-validation-with-jax-rs-in-java-ee-6.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/370661.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370661.shtml
英文地址,請注明出處:http://en.pswp.cn/news/370661.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何讓浮動的元素換行??css

當你想要做成這種布局效果的時候 紫色框里面的內容那樣 它是一個列表 li元素是塊級元素 默認大小是父元素ul的寬 并且換行 如果li沒有背景的話那就不用管了 可是問題來了它不但有背景 而且是根據文字自適應的寬高 這就是inline-block類型的功能了 那么想讓li是inline-bl…

Python學習之類和實例

面向對象最重要的概念就是類&#xff08;Class&#xff09;和實例&#xff08;Instance&#xff09;&#xff0c;必須牢記類是抽象的模板&#xff0c;比如Student類&#xff0c;而實例是根據類創建出來的一個個具體的“對象”&#xff0c;每個對象都擁有相同的方法&#xff0c;…

解決sublime里面的vue高亮的問題

下載插件文件&#xff1a;https://github.com/vuejs/vue-syntax-highlight 直接在官網下載放在安裝時候的packages目錄下&#xff08;sublime text3\Sublime Text3\Data\Packages&#xff09; 在Packages文件夾下新建一個vue的文件&#xff0c;把第一步下載的文件復制進去 subl…

python矩形填充顏色_在Python中找到所有用0填充的矩形

假設我們有一個二進制2D矩陣&#xff0c;現在我們必須找到所有用0填充的矩形的起點和終點。我們必須牢記&#xff0c;矩形是分開的&#xff0c;彼此之間不接觸&#xff0c;但是它們可以接觸陣列邊界。僅包含單個元素的矩形也是可能的。所以&#xff0c;如果輸入像-101110111011…

python concat_python中merge、concat用法

轉載&#xff1a;https://blog.csdn.net/ly_ysys629/article/details/73849543 參考&#xff1a;https://blog.csdn.net/stevenkwong/article/details/52540605 數據規整化&#xff1a;合并、清理、過濾 pandas和python標準庫提供了一整套高級、靈活的、高效的核心函數和算法將…

Vue使用axios無法讀取data的解決辦法

今天發現Vue中使用了axios后&#xff0c;then方法中無法讀取到data中的數據了&#xff0c;總是提示 Cannot set property xxx of undefined 上網找了一圈后發現了一下解決方法。 解決辦法1&#xff1a; methods:{tap:function(){var selfthis;axios.get(xxxxxx).then(function(…

設置博客園標題樣式

1.向博客園申請js權限 我們需要進入博客園自定義博客模板的頁面&#xff0c;向博客園管理團隊申請頁面運行js的權限。【博客園】->【設置】->【博客設置】&#xff0c;點擊頁面上的js權限申請&#xff0c;然后填寫申請的理由&#xff0c;耐心等幾分鐘&#xff0c;再刷新一…

Spring 3.1 –從數據庫加載XML配置的屬性

Spring使通過其PropertyPlaceholderConfigurer和&#xff08;Spring 3.1之前&#xff09;PropertySourcesPlaceholderConfigurer&#xff08;Spring 3.1&#xff09;從屬性文件中獲取的值易于注入。 這些類實現了BeanFactoryPostProcessor接口&#xff0c;該接口使它們能夠在初…

如何判斷PHP 是線程安全還是非線程安全的

什么是線程安全與非線程安全&#xff1f; 線程安全就是在多線程環境下也不會出現數據不一致&#xff0c;而非線程安全就有可能出現數據不一致的情況。 線程安全由于要確保數據的一致性&#xff0c;所以對資源的讀寫進行了控制&#xff0c;換句話說增加了系統開銷。所以在單線程…

關聯查詢mysql_《MySQL數據庫》關聯查詢

原標題&#xff1a;《MySQL數據庫》關聯查詢一、關聯查詢1、概念在查詢數據時&#xff0c;所需要的數據不只在一張表中&#xff0c;可能在兩張或多張表中。這個時候&#xff0c;需要同時操作這些表來查詢數據&#xff0c;即關聯查詢。關聯查詢所涉及到的表與表之間都會存在有關…

python語言語塊句的標記_《自然語言處理理論與實戰》

編輯推薦 1.講解自然語言處理的理論 2.案例豐富&#xff0c;實戰性強 3.適合自然語言處理學習的入門者 內容提要 自然語言處理是什么&#xff1f;誰需要學習自然語言處理&#xff1f;自然語言處理在哪些地方應用&#xff1f;相關問題一直困擾著不少初學者。針對這一情況&#x…

NOIP2017年11月9日賽前模擬

最后一次NOIP模擬了 題目1&#xff1a;回文數字 Tom 最近在研究回文數字。  假設 s[i] 是長度為 i 的回文數個數&#xff08;不含前導0&#xff09;&#xff0c;則對于給定的正整數 n 有&#xff1a; 以上等式中最后面的括號是布爾表達式&#xff0c;Tom 想知道S[n] mod 2333…

height百分比失效

heigh:100%失效 解決方案&#xff1a; 第一種 html, body { height: 100%; } 第二種 div { height: 100%; position: absolute; } 非定位元素的寬高百分比計算不會將 padding 計算在內&#xff0c;而定位元素會計算在內。 利用這個特性可以實現圖片左右半區點擊分別上一張圖…

Java堆空間,本機堆和內存問題

最近&#xff0c;我在和一個朋友討論為什么Java進程使用的內存比啟動Java進程時設置的最大堆多。 代碼創建的所有Java對象都是在Java堆空間內創建的&#xff0c;其大小由-Xmx選項定義。 但是一個Java進程由很多空間組成&#xff0c;而不僅僅是Java堆空間。 以下是組成Java進程…

mysql視圖表怎么設置約束_MySQL一一sql的視圖、索引、約束

一、視圖本質上相當于一張**“虛擬表”**&#xff0c;可當作獨立的一張表進行操作(增、刪、改、查)** 作用&#xff1a;**** a)**可通過權限控制&#xff0c;只將“表中的少數列”暴露給數據庫用戶&#xff0c;而不讓該用戶直接操縱數據庫中“實際表”** b)**…

Software Development Life Cycle

轉載于:https://www.cnblogs.com/genezhao/p/6879848.html

python中 的用法_詳解python中@的用法

python中的用法 是一個裝飾器&#xff0c;針對函數&#xff0c;起調用傳參的作用。 有修飾和被修飾的區別&#xff0c;function作為一個裝飾器&#xff0c;用來修飾緊跟著的函數&#xff08;可以是另一個裝飾器&#xff0c;也可以是函數定義&#xff09;。 代碼1 結果1 Its fun…

ArrayAndString(數組和字符串)

1.實現一個算法&#xff0c;確定一個字符串的所有字符是否全都不同。假使不允許使用額外的數據結構&#xff0c;又該怎么處理&#xff1f; public class UniqueChars {public static void main(String[] args) {// TODO Auto-generated method stubString string "abcdef…

MyBatis教程– CRUD操作和映射關系–第2部分

為了說明這一點&#xff0c;我們正在考慮以下示例域模型&#xff1a; 會有用戶&#xff0c;每個用戶可能都有一個博客&#xff0c;每個博客可以包含零個或多個帖子。 這三個表的數據庫結構如下&#xff1a; CREATE TABLE user (user_id int(10) unsigned NOT NULL auto_incr…

position 的屬性值

理論上來說&#xff0c;全部 position 的取值有8個 包括&#xff1a;position&#xff1a;static | relative | absolute | fixed | sticky | initial | inherit | unset 其中最常用的是 static 、relative、absolute、fixed 和 sticky initial、inherit、unset 是css的關鍵…