狠狠撸
Submit Search
Spring bootでweb バリデート编
?
10 likes
?
28,262 views
なべ
Follow
厂辫谤颈苍驳でのバリデートの仕方を解説
Read less
Read more
1 of 41
Download now
Downloaded 40 times
More Related Content
Spring bootでweb バリデート编
1.
バリデート编
2.
アジェンダ ? はじめに ? サンプルページ ?
サンプルページの準備 ? バリデート ? メッセージを変更 ? カスタムバリデータ ? データベースを参照するバリデート ? ローカライズ ? まとめ
3.
はじめに ? Spring Bootを使って、 Webの入力妥当性チェック(バリデート)の 実装方法を試してみる。
4.
サンプルページ ? サンプルページの画面フローは下記の通り 商品入力画面 確認画面 完了画面 【確認】クリック 【登録】クリック 入力エラー時 【戻る】クリック 【戻る】クリック
5.
サンプルページ ? サンプルページの画面フローは下記の通り 商品入力画面 確認画面 完了画面 【確認】クリック 【登録】クリック 入力エラー時 【戻る】クリック 【戻る】クリック ここの話 どのように入力チェックをするか?
6.
サンプルページ ? Controller /** 商品関連のページを制御するController
*/ @Controller @RequestMapping("product") public class ProductController { } http://someserver/someapp/product/ に 関連付けたController
7.
サンプルページの準備 ? まずサンプルページの下記画面フローを作成する 商品入力画面 確認画面 完了画面 【確認】クリック 【登録】クリック 入力エラー時 【戻る】クリック 【戻る】クリック
8.
サンプルページの準備 ? Controller /** 商品関連のページを制御するController
*/ @Controller @RequestMapping("product") public class ProductController { /** 商品入力の開始 */ @RequestMapping(value = "/input", method= RequestMethod.GET) public String input(Model model) { return "product/input"; } } http://someserver/someapp/product/input の GETリクエストを処理するメソッド テンプレート product/input.html が レンダリングされる
9.
サンプルページの準備 ? Template (input.html) <body> <h3>商品入力</h3> <form
action="confirm.html" method="post"> Code: <input type="text" name="productCode" size="20"/> <br/> 商品名: <input type="text" name="productName" size="20"/> <br/> 金額: <input type="text" name="price" size="20"/> <br/> <input type="submit" name="naviButton" value="確認"/> </form> </body> 素のHTML
10.
サンプルページの準備 ? Template (input.html) <form
action="confirm.html" th:action="@{/product/confirm}" method="post"> Code: <input type="text" name="productCode" size="20" /> <br/> 商品名: <input type="text" name="productName" size="20"/> <br/> 金額: <input type="text" name="price" size="20" /> <br/> <input type="submit" name="naviButton" value="確認"/> </form> Thymeleaf の記述を追加
11.
サンプルページの準備 ? Controller /** 商品関連のページを制御するController
*/ @Controller @RequestMapping("product") public class ProductController { /** 商品入力の確認 */ @RequestMapping(value = "/confirm", method=RequestMethod.POST) public String confirm(Model model,) { return "product/confirm"; } } http://someserver/someapp/product/input からの POSTリクエストを処理するメソッド テンプレート product/confirm.html が レンダリングされる
12.
サンプルページの準備 ? Template (confirm.html) <body> <h3>商品入力
- 確認</h3> <form action="finish.html" method="post"> Code: <br/> 商品名: <br/> 金額: <br/> <input type="submit" name="naviButton" value="登録"/> </form> </body>
13.
サンプルページの準備 ? 動作確認 http://someserver/someapp/product/input http://someserver/someapp/product/confirm
14.
サンプルページの準備 ? Template (input.html) <form
action="confirm.html" th:action="@{/product/confirm}" method="post"> Code: <input type="text" name="productCode" size="20" th:field="*{productForm.productCode}"/> <br/> 商品名: <input type="text" name="productName" size="20" th:field="*{productForm.productName}"/> <br/> 金額: <input type="text" name="price" size="20" th:field="*{productForm.price}"/> <br/> 入力画面を実装する
15.
サンプルページの準備 ? Form /** 画面の値を保持するForm
*/ public class ProductForm { private Integer productCode; private String productName; private Integer price; // getter/setteを省略 フォームクラスを実装する これが入力値の格納先となる
16.
サンプルページの準備 ? Controller /** 商品関連のページを制御するController
*/ @Controller @RequestMapping("product") public class ProductController { @ModelAttribute public ProductForm setupForm() { return new ProductForm(); } /** 商品入力の確認 */ @RequestMapping(value = "/confirm", method=RequestMethod.POST) public String confirm(Model model, ProductForm productForm) { return "product/confirm"; } } 画面用のFormクラスを初期化する 引数に入れた項目が 画面上の同名の項目にマップされる
17.
サンプルページの準備 ? Template (confirm.html) <form
action="finish.html" id="confirm" th:object="${productForm}" method="post"> Code: <span th:text="${productForm.productCode}"/> <br/> 商品名: <span th:text="${productForm.productName}"/> <br/> 金額: <span th:text="${productForm.price}"/> <br/> 確認画面を実装する
18.
サンプルページの準備 ? 動作確認 http://someserver/someapp/product/input http://someserver/someapp/product/confirm
19.
バリデート ? Formの修正 /** 画面の値を保持するForm
*/ public class ProductForm { @NotNull private Integer productCode; @NotNull @Length(max=10) private String productName; @NotNull @Max(1000) private Integer price; // getter/setteを省略 Bean Validationの仕様に従って アノテーションを記述する @NotNull → 必須入力 @Length → 長さ制限(10文字まで) @Max → 1,000までの入力
20.
バリデート ? Controllerの修正 /** 商品関連のページを制御するController
*/ @Controller @RequestMapping("product") public class ProductController { @RequestMapping(value = "/confirm", method=RequestMethod.POST) public String confirm(Model model, @Valid ProductForm productForm, Errors errors) { if (errors.hasErrors()) { return "product/input"; } return "product/confirm"; } } @Validを付けて、Formに対して バリデートをすることを明記 受け取ったバリデート結果を参照し、 エラーがあれば入力画面に遷移する
21.
バリデート ? Templateの修正(input.html) Code: <input type="text"
name="productCode" size="20" th:field="*{productForm.productCode}"/> <span th:if="${#fields.hasErrors('*{productForm.productCode}')}" th:errors="*{productForm.productCode}" style="color: red"/> <br/> 商品名: <input type="text" name="productName" size="20" th:field="*{productForm.productName}"/> <span th:if="${#fields.hasErrors('*{productForm.productName}')}" th:errors="*{productForm.productName}" style="color: red"/> <br/> 金額: <input type="text" name="price" size="20" th:field="*{productForm.price}"/> <span th:if="${#fields.hasErrors('*{productForm.price}')}" th:errors="*{productForm.price}" style="color: red"/><br/> エラーがあるか? エラーがあれば、内容を出力
22.
バリデート ? 動作確認 http://someserver/someapp/product/input 未入力、 10文字超え、 1000超え エラーメッセージを表示
23.
メッセージを変更 ? 初期状態ではメッセージが全て英語のため、 これを日本語にする
24.
メッセージを変更 ? 方法1:個別に指定する public class
ProductForm { @NotNull(message="入力してください(埋め込み)") private Integer productCode; 各バリデート用のアノテーションにある messageプロパティで指定する http://someserver/someapp/product/input
25.
メッセージを変更 ? 方法2:プロパティファイルで指定する javax.validation.constraints.NotNull.message=入力してください(プロパティ) プロパティファイルに対応するアノテーションの メッセージをプロパティファイルで指定する http://someserver/someapp/product/input ValidationMessages.properties
26.
メッセージを変更 ? 可変項目をメッセージに埋め込む org.hibernate.validator.constraints.Length.message=入力は{max}文字までです。 アノテーションのパラメータ名を プロパティファイルで指定する http://someserver/someapp/product/input @NotBlank @Length(min=1, max=10) private
String productName; {max}に 10が埋め込まれる
27.
カスタムバリデータ ? 自前のバリデート機能を実装する方法は次の通り (サンプルとして電話番号のバリデータを実装する)
28.
カスタムバリデータ ? アノテーションを宣言する (お約束の書き方) @Constraint(validatedBy
= TelNumberValidator.class) @Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface TelNumber { String message() default “TEL number is invalid"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } 実際にチェックを行う クラスを指定(後述) デフォルトメッセージ
29.
カスタムバリデータ ? チェック処理を実装する public class
TelNumberValidator implements ConstraintValidator<TelNumber, String> { @Override public void initialize(TelNumber constraintAnnotation) { } @Override public boolean isValid(final String value, final ConstraintValidatorContext context) { return true; } } チェック対象のアノテーションと チェック対象のデータ型 ここにチェック処理を 実装する 初期処理
30.
カスタムバリデータ ? チェック処理を実装する public class
TelNumberValidator implements ConstraintValidator<TelNumber, String> { private Pattern pattern; @Override public void initialize(TelNumber constraintAnnotation) { pattern = Pattern.compile("^0??d*-??d*-??d*"); } @Override public boolean isValid(final String value, final ConstraintValidatorContext context) { Matcher matcher = pattern.matcher(value); return matcher.find(); } } 正規表現チェック用の フィールド パターンに合ってたら true 違ったら false を返す 初期処理 0から始まって、数値の間に「-」が2つあること
31.
カスタムバリデータ ? カスタムバリデータを利用する @NotBlank @TelNumber private String
telNumber; http://someserver/someapp/product/input
32.
データベースを参照するバリデート ? 今までのBean Validationは Controllerの手前での出来事だったが、 データベースを参照するバリデートはControllerの先の動作となる Controller Service ブラウザ Bean
Validation データベースを参照する バリデート
33.
データベースを参照するバリデート ? Serviceにバリデート用メソッドを用意する /** Productをチェックする
*/ public void validate(ProductForm productForm) throws DuplicateProductException { if ( productForm.getProductCode() == 1 ) { throw new DuplicateProductException(); } } サンプルとして、商品コードに 「1」が入れられたら例外を投げる 異常時は例外を投げる
34.
データベースを参照するバリデート ? サービス固有の例外を作成する public class
DuplicateProductException extends Exception { } Exceptionを拡張して 必ずキャッチさせる
35.
データベースを参照するバリデート ? ControllerでServiceに追加したチェックを呼び出す /** 商品入力の確認
*/ @RequestMapping(value = "/confirm", method=RequestMethod.POST) public String confirm(Model model, @Valid ProductForm productForm, Errors errors) { if (errors.hasErrors()) { return "product/input"; } try { productService.validate(productForm); } catch(DuplicateProductException e) { errors.rejectValue("productCode", "duplicate", new String[]{"商品コード"}, "default message."); return "product/input"; } return "product/confirm"; } チェックを呼び出す エラーがあったら rejectValueでフィールド ごとのエラーを詰める
36.
データベースを参照するバリデート ? メッセージ用のプロパティファイルを用意する duplicate={0}が重複しています。 「キー =
メッセージ」の形式で記述 messages.properties errors.rejectValue("productCode", "duplicate", new String[]{"商品コード"}, "default message."); rejectValueしたときのerrorCodeを プロパティと同じキーにする 置換箇所「{0}」に 「商品コード」を当てる
37.
データベースを参照するバリデート ? アプリケーション設定を変更する spring: messages: basename: messages 先ほどのmessages.propertiesを 参照するよう設定する application.yml http://someserver/someapp/product/input
38.
データベースを参照するバリデート ? その他の方法 if (errors.hasErrors())
{ return "product/input"; } productService.validate(productForm); return "product/confirm"; } @ExceptionHandler( DuplicateProductException.class ) public ModelAndView handleException(RuntimeException e ) { return new ModelAndView(" product/input ") .addObject("error", e.getMessage()); } public class DuplicateProductException extends RuntimeException { } RuntimeExceptionに変更 try ~ catchを削除 コントローラの例外を 一手に引き受ける
39.
ローカライズ ? 言語ごとのプロパティファイルを配置し、多言語対応をする javax.validation.constraints.NotNull.message=Please input. ValidationMessages.properties デフォルト javax.validation.constraints.NotNull.message=入力してください。 ValidationMessages_ja.properties 日本語 javax.validation.constraints.NotNull.message=Please
input. ValidationMessages_en.properties 英語
40.
まとめ ? SpringというよりBean Validation(JSR-303,JSR-349)の仕様を 知る方が、学習の近道かもしれない???? ?
また、Springの採用している実装のHibernate Validatorも確認を
41.
まとめ ? 参考 ■JSR 303
Bean Validationで遊んでみるよ! - Yamkazu's Blog http://yamkazu.hatenablog.com/entry/20110206/1296985545 ■私のBeanValidationの使い方(Java EE Advent Calendar 2013) — 裏紙 http://backpaper0.github.io/2013/12/03/javaee_advent_calendar_2013. html ■Spring Boot Security Application - Bartosz Kielczewski http://kielczewski.eu/2014/12/spring-boot-security-application/ ■81.参考: 妥当性チェックのエラーメッセージ出力方法 - soracane https://sites.google.com/site/soracane/home/springnitsuite/spring- batch/81-can-kao-tuo-dang-xingchekkunoeramesseji-chu-li-fang-fa
Download