SpringMVCを使っていて、バリューオブジェクトにアノテーションでバリデーションの定義入れて、
@Validだけ仕掛けておけばイイってのは楽チンではイイわーとか思ってたのですが、
FormとJSONとで、ちょっとばかし挙動が違くて困っています。
#ちゃんと解決してから書けばいいのですが、明日になると自分自身、内容を覚えてられるか
#微妙なのでブログに書いてしまおうかな、と…w
■ HTMLのFormを受取る時
– Controller
@RequestMapping(value = "/post", method = RequestMethod.POST) public String hogePost( @Valid Hoge hoge, // Integer:id, String:nameって感じのバリューオブジェクト BindingResult result, Locale locale, Model model) { ~略~ if (result.hasErrors()) { List<FieldError> errors = result.getFieldErrors(); for (FieldError error : errors) { logger.info(messageSource.getMessage(error, locale)); } }
– Hoge
@NotNull @Max(100) private Integer id; @NotNull private String name;
– Bean定義
<beans:bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> </beans:bean> <beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <beans:property name="basename"><beans:value>classpath:messages</beans:value></beans:property> </beans:bean>
– エラーメッセージファイル(messages.properties と messages_ja_JP.properties 同内容…)
typeMismatch=Type Mismatch!! Max=MaxMaxMax!!
みたいな感じの実装と設定にして↓のように
Integerのidの項目に”a”とか入れて叩いてやると、
↓のようにタイプが違いますから~ってエラーメッセージを返してくれます。
INFO : com.shinodogg.hoge.HomeController - Type Mismatch!!
■ JSON文字列を受取る時
今回のプロジェクトはクライアントからjQueryとか使って$.ajax的な感じで、
JSONがリクエストされてきます。
Controllerの中であーだこーだするのではなく、HTMLのFormと同じように
@Validってチョロっと書いてドヤ顔したいわけです。
ちょこちょこハマったりしつつも、Twitterでたまに絡ませていただいてる
@keisuke69さんのブログにお世話になったりしながら、
以下のような実装にしてみました。
– Controller
@RequestMapping(value="/jsonpost", method=RequestMethod.POST, headers="Accept=application/json") public String hogeJsonPost( @RequestBody @Valid Hoge hoge, //JSONのバリデート後にバリューオブジェクトに値詰めてくれる Locale locale, Model model) { ~略~ @ExceptionHandler @ResponseStatus(value = HttpStatus.BAD_REQUEST) @ResponseBody public String handleMethodArgumentNotValidException( MethodArgumentNotValidException error) { logger.info("JSON Validate: " + error.getMessage());
バリデーションエラーが起こった場合は、BindResultがホゲホゲではなくて、
バリデーションエラーExceptionをハンドリングするメソッドを作ってやるのが特徴です。
って事で↓のようなクライアントからJSONをリクエストしてみます。
– jQuery
<html> <head><script type="text/javascript"> $(function(){ $('#hoge').click( function(){ $.ajax({ type: "POST", url: "http://localhost:8080/Hoge/jsonpost", dataType: "json", data: '{"id": "123", "name": "hoge"}', success: function(data){ alert(data); }, contentType: "application/json" }); }); }); </script> </head> <body> <a href="javascript: void(0)" id="hoge">hoge</a><br /> </body> </html>http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js
結果は上記のMax(100)が効いて↓のようなのが取得できましたよ、と。
INFO : com.shinodogg.hoge.HomeController - JSON Validate: Validation failed for argument at index 0 in method: public java.lang.String com.shinodogg.hoge.HomeController.hogeJsonPost(com.shinodogg.hoge.Hoge,java.util.Locale,org.springframework.ui.Model), with 1 error(s): [Field error in object 'hoge' on field 'id': rejected value [123]; codes [Max.hoge.id,Max.id,Max.java.lang.Integer,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [hoge.id,id]; arguments []; default message [id],100]; default message [must be less than or equal to 100]]
いやー、ご丁寧にありがとうございます、素敵なメッセージ、、、なんですが、
上記のmessage.propertiesでは Max=MaxMaxMax!! って定義してるんすよね、、と。
まぁ、イイっす。こいつはもうちょい調べればエラーメッセージをプロパティファイルの内容から
食う事が出来そうな気がしないでもないです。
が、、↓のようにidの項目に数値ではなく文字列を突っ込んでみると、、、
data: '{"id": "a", "name": "hoge"}',
typeMismatch=Type Mismatch!! が出ないのは、まぁ予想通りですが、、
↓イヤイヤ、、ちょっとコレはキツくないすかね、、と。
org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not construct instance of java.lang.Integer from String value 'a': not a valid Integer value at [Source: org.apache.catalina.connector.CoyoteInputStream@3008af78; line: 1, column: 2] (through reference chain: com.shinodogg.hoge.Hoge["id"]); nested exception is org.codehaus.jackson.map.JsonMappingException: Can not construct instance of java.lang.Integer from String value 'a': not a valid Integer value at [Source: org.apache.catalina.connector.CoyoteInputStream@3008af78; line: 1, column: 2] (through reference chain: com.shinodogg.hoge.Hoge["id"]) at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:127)
確かにJSONのコンバートで失敗するのは分かるのですが、そこをちゃんと拾って、
エラーメッセージを返して欲しかったな、と。MethodArgumentNotValidExceptionで。
まぁ、コレもなんとかなるのかもですが、StackOverFlowを見ながら
トライアンドエラーしていくのは、日本人の私にはなかなかシンドイす。
(ま、英語の勉強になってるのでイイかってポジティブに考えてますが…)
ここまでたどり着く間にも、
HttpMediaTypeNotSupportedExceptionとか、
Spring Modules Validation使ったら動かなかったとか、
Jackson(JSONパーサー)の設定がpom.xmlに無かったとか、
知らんがな、、ってのにイロイロぶつかりましたが、
それもまた経験、、、、と。。
明日も継続してコレ調べるので、解決したら追記するなり、別エントリ書くなりいたしやす。
ソフトバンククリエイティブ
売り上げランキング: 41068
コメント
[…] « SpringMVCでJSONを受付けた時のvalidationで困っている件 […]