Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新

13,328 views

Published on

2015-09-16 GlassFish勉強会(https://glassfish.doorkeeper.jp/events/27471)での資料です。Java EE 8で導入される予定の、アクションベースWebフレームワーク「MVC 1.0」の最新情報を紹介しています。
2015-10-10 EDR2リリースに従い、資料を修正しました

Published in: Technology
  • Be the first to comment

Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新

  1. 1. Java EE 8先取り! MVC 1.0入門 2015-09-16 GlassFish勉強会 多田真敏(@suke_masa) #glassfish_jp 1 2015/10/10修正 EDR2 対応版
  2. 2. 自己紹介 • 多田真敏(ただまさとし) - (株)カサレアル所属 • Java EEを中心とした研修トレーナー - 日本には数人程度? - NetBeans愛好家 • JJUG CCCスピーカー - 2014春、2014秋、2015春 2
  3. 3. 本セッションの内容 • Java EE 8で仕様に含まれる予定の
 「MVC 1.0」とその参照実装「Ozark」について、 現時点のJSR・ソースコードを基に解説します。 3
  4. 4. 注意点 4 • MVC 1.0およびJava EE 8は仕様策定が進行中であり、本資 料の情報は2015年10月10日時点のものに過ぎません。今 後、仕様が変更される可能性があることを十分にご注意 ください。 • 本資料のサンプルプログラムは、MVC 1.0+Ozarkのソース コードやJavadocを参考にして作成していますが、まだ公 式情報も少なく、正しい実装とは限りません。あくま でMVC 1.0の概要を知るための「参考」と捉えてください。
  5. 5. 目次 1)MVC 1.0登場の背景とコンセプト 2)MVC 1.0の機能とサンプルプログラム 3)実装されない機能と今後への期待 5
  6. 6. 1) MVC 1.0登場の背景と コンセプト 6
  7. 7. MVC 1.0登場の背景 • Struts 1のEnd Of Life宣言 • Java EE標準への回帰 • しかし、JSFは「アクションベース」ではなく
 「コンポーネントベース」で作り方が異なる 7 「Java EE標準」で「アクションベース」な フレームワークが求められている
  8. 8. Java EE 8に関する調査結果 • 1位:JSON-B • 2位:セキュリティの簡素化 • 3位:キャッシュ(JCache) • 4位:セキュリティ
    インターセプター • 5位:MVC 8 https://blogs.oracle.com/ldemichiel/entry/results_from_the_java_ee より アクションベースへの 期待感が大きい
  9. 9. と、言うことで • Java EE 8でMVC 1.0 (JSR 371)の登場! • 2015年3月にEDR1、10月にEDR2がリリース • EDR3は2016年3月31日にリリース予定 9
  10. 10. 注:JSFを否定するものではない! • JSR 371には、
 「MVCはJSFを置き換えるものではない」
 と書かれている • MVCとJSFの共存も可能(後述) • UI開発の効率性を重視するならJSF、
 画面遷移の分かりやすさを重視するならMVC 10
  11. 11. MVC 1.0のコンセプト 1.既存のJava EE技術を活用する。 2.CDIおよびBean Validationと統合する。 3.MVCアプリケーションのコアを提供し、
 すべての機能は必ずしも提供しない。 4.JAX-RS上で動かす。 5.JSPおよびFaceletsをサポートする。 11 サーブレット上と議論が分かれたが JAX-RS上に決定
  12. 12. コンセプトとしないもの 1.新しいビュー言語などは定義しない。 2.Java EE外のスタンドアロンなMVCはサポートし ない。 3.JAX-RSでないRESTはサポートしない。 4.Java EEでないビュー言語は組み込みサポートし ない。 12
  13. 13. 言い換えると・・・ • JAX-RSを中心に、既存のJava EEテクノロジーを
 最大限に活用する • URLマッチング、例外処理、バリデーション、DIなど • 新たに策定する仕様は最小限に留める • 例えば、新たなJSPカスタムタグを作ったりはしない 13
  14. 14. MVC 1.0を利用したWebアプリの構成 14 ビュー コントローラー モデル JSP または Facelets JAX-RS リソース クラス JPA CDI ビーン CDIで 依存性注入 Bean Validation で入力検証 例外処理も JAX-RS の機能を活用
  15. 15. 2) MVC 1.0の機能と サンプルプログラム 15
  16. 16. 参照実装Ozark • MVC 1.0は仕様 - ≒インタフェース・例外・ アノテーションの集合 • 参照実装はOzark - 上記のインタフェース実 装クラスや、その他の必 要なクラスの集合 - 参照実装=公式の実装 16
  17. 17. 今回の開発・実行環境 • GlassFish web 4.1.1 • Oracle JDK 8u60 • NetBeans 8.0.2 • Maven 3.3.3 • Jersey 2.21.1 17
  18. 18. 下準備:JAX-RSの有効化 • Applicationのサブクラスを作成する • 作成したクラスに@ApplicationPathを付加 • ※設定ファイルは不要 18 @ApplicationPath(“api”) public class MyApplication extends Application { } http://<host>/<context>/api/… が、 クライアントがアクセスするURLになる ※下線付きはJAX-RSの機能です
  19. 19. ①基本的な入力・画面遷移・出力 19 @Path(“hello”) @RequestScoped public class HelloController { @Inject private Models models; @GET @Path(“input") @Controller public String input() { return "hello/input.jsp"; } @GET @Path("result") @Controller public String result(@QueryParam("name") String name) { models.put("name", name); return "hello/result.jsp"; } } JAX-RSリソースメソッドを コントローラーにする フォワード先のパスを返す ビューに渡す値はModelsに (実体はjava.util.Map) クエリパラメータは 引数で受け取る ※下線付きはJAX-RSの機能です
  20. 20. ①基本的な入力・画面遷移・出力 20 <form action="./result" method="get"> 名前:<input type="text" name="name"><br> <input type="submit" value="送信"> </form> 両方とも至って普通のJSP こんにちは、${name}さん! 入力画面 出力画面
  21. 21. ①基本的な入力・画面遷移・出力 • ビューは/WEB-INF/views/配下に保存(変更も可能) 21 src +-main +-java | +-ozarksample | +-controller | +-HelloController.java +-webapp +-WEB-INF +-views +-hello +-input.jsp +-result.jsp @GET @Path(“input”) @Controller public String input() { return "hello/input.jsp"; } @GET @Path(“result") @Controller public String result(...) { return "hello/result.jsp"; }
  22. 22. ①基本的な入力・画面遷移・出力 22
  23. 23. [発展] 何故このような処理が可能か? • MVC 1.0仕様 • @Controllerには@NameBindingメタアノテーションが付加さ れている • Ozark実装 • ViewResponseFilterにも@Controllerが付加されているため、 コントローラーメソッド実行時のみこのフィルターが実行される • ViewResponseFilterは、コントローラーメソッドの戻り値また はレスポンスエンティティをViewableに変換する • Viewable型に対応したViewableWriter(MessageBodyWriter 実装クラス)が実行され、ビューが処理される 23※下線付きはJAX-RSの機能です
  24. 24. ②CDI Beanによる値の受け渡し 24 @Path(“cdi”) @RequestScoped public class CdiController { @Inject private RequestScopeDto dto; … @GET @Path("result") @Controller public String result(@QueryParam("name") String name) { dto.setName(name); return "hello/result.jsp"; } }
  25. 25. ②CDI Beanによる値の受け渡し 25 @Named(“dto”) @RequestScoped public class RequestScopeDto { private String name; // setter/getter } <body> こんにちは、${dto.name}さん!<br> </body> @Namedで指定した名前 ※@Named、@RequestScopedはDI/CDIの機能です
  26. 26. ③リダイレクト • コントローラーの戻り値のパスの先頭に、
 「redirect:」を付加 • @RedirectScopedというスコープアノテーション も用意されている 26 @Path(“hello”) @RequestScoped public class RedirectController { @GET @Controller @Path("result1") public String result1(@QueryParam("name") String name) { return “redirect:redirect/result2"; } }
  27. 27. ④コントローラーメソッド  の戻り値の型 1)String • パス文字列を戻り値とする • 条件分岐でパスを動的に変更した い時や、通常時に使う 2) Viewable • コンストラクタ引数でパス、 Models、ViewEngine(後述)を指 定可能 • 明示的にViewEngineを指定した い時に使う • 4つのどの型の戻り値も、最終的 には全てViewableに変換される 27 @GET @Controller @Path("hello") public String hello() { return “hello.jsp”; } @GET @Controller @Path("hello") public Viewable hello() { return new Viewable( “hello.jsp”, models, JspViewEngine.class); }
  28. 28. ④コントローラーメソッド  の戻り値の型 28 3) Response • パスとHTTPレスポンスコー ドを指定可能 • HTTPレスポンスコードを指 定したい時に使う 4) void • メソッド@Viewアノテーショ ンを付けてパスを指定 • 条件分岐はできないので、遷 移するビューが1つに決まっ ている時に使う @GET @Controller @Path("hello") public Response hello() { return Response .status(Response.Status.OK) .entity(“hello.jsp”) .build(); } @GET @Controller @Path(“hello") @View(“hello.jsp”) public void hello() { } ※下線付きはJAX-RSの機能です
  29. 29. ⑤バリデーション • アクションフォーム 的クラスを作り、 Bean Validationの アノテーションを指 定 29 public class FormBean { @Size(min = 1, max = 10) @FormParam("name") private String name; @Size(min = 1, max = 3) @Pattern(regexp = "[0-9]+") @Min(0) @Max(200) @FormParam("age") private String age; // setter/getter… ※Bean Validationは既存のJava EEの機能です
  30. 30. ⑤バリデーション • コントローラーメソッドの引数には@Validおよび @BeanParamを指定 • メソッドには@ValidateOnExecutionを指定 30 @Path(“validation") @RequestScoped public class ValidationController { @Inject private BindingResult bindingResult; @POST @Path(“result") @Controller @ValidateOnExecution(type = ExecutableType.NONE) public String result(@Valid @BeanParam FormBean formBean) { if (bindingResult.isFailed()) { models.put("bindingResult", bindingResult); return "validation/input.jsp"; } … ※下線付きはJAX-RSの機能です
  31. 31. ⑤バリデーション • Bean Validationの検証結果が
 BindingResultに詰められる 31 @Path(“validation”) @RequestScoped public class ValidationController { @Inject private BindingResult bindingResult; @POST @Path("result") @Controller @ValidateOnExecution(type = ExecutableType.NONE) public String result(@Valid @BeanParam FormBean formBean) { if (bindingResult.isFailed()) { models.put("bindingResult", bindingResult); return "validation/input.jsp"; } …
  32. 32. ⑤バリデーション • 画面にエラーメッセージを表示するためには、 ModelsやCDI Beanを使って画面にエラー情報を 受け渡す必要がある 32 @POST @Path(“result") @Controller @ValidateOnExecution(type = ExecutableType.NONE) public String result(@Valid @BeanParam FormBean formBean) { if (bindingResult.isFailed()) { models.put("bindingResult", bindingResult); return "validation/input.jsp"; } …
  33. 33. ⑤バリデーション • コントローラーメソッドのから渡したエラー情報 を画面で表示 33 <c:if test="${not empty bindingResult}”> <h1>検証エラーですよ!</h1> <c:forEach items="${bindingResult.allMessages}" var="message"> <c:out value="${message}"/><br> </c:forEach> </c:if>
  34. 34. ⑥例外処理 • ExceptionMapper実装クラスを作成する - 例外クラスごとにExceptionMapperを作成可能 34 @Provider @ApplicationScoped public class MyExceptionMapper implements ExceptionMapper<MyException> { @Inject private Models models; @Override public Response toResponse(MyException exception) { models.put("error", exception.getMessage()); return Response.status(Response.Status.BAD_REQUEST) .entity("exception/error.jsp").build(); } } スローされた 例外インスタンス ※下線付きはJAX-RSの機能です
  35. 35. ⑥例外処理 • コントローラーメソッド内で例外が発生すると、 ExceptionMapperが呼ばれ、その中で指定したエ ラーページに遷移する 35 @GET @Path("result") @Controller public String result(…) throws Exception { … throw new MyException("MyExceptionが発生しました。"); }
  36. 36. ⑦サポートされるビュー技術 • MVC 1.0で公式にサポートされるのは下記の2つ 1)JSP 2)Facelets(JSFのビュー技術)
 #PrimeFacesなどのリッチコンポも利用可能。コン ポーネントベースとアクションベース両方のメリット が享受できるのでは? 36
  37. 37. ⑦サポートされるビュー技術 • 下記は参照実装のOzark独自で拡張サポート 1)Thymeleaf 2)AsciiDoc 3)FreeMarker 4)Handlebars 5)Jade 6)JSR-223 7)Mustache 8)Velocity 37 ※Pebbleはプルリク申請中 (正規の手順に従っていなかったため未マージ)
  38. 38. ⑦サポートされるビュー技術 • javax.mvc.engine.ViewEngineインタフェースを実装した クラスを作ればOK • お気に入りのビュー技術で自作ViewEngineをプルリクすれ ば、マージしてくれるかも?(正規の手順を踏む必要はある) 38 public interface ViewEngine { // このビューエンジンを適用できるパスならtrue // (拡張子で判断していることが多い) boolean supports(String view); // ビューを処理する void processView(ViewEngineContext context); }
  39. 39. ⑦サポートされるビュー技術 • JSP/Facelets以外のビュー技術を使う場合、 1)拡張機能のJARをクラスパスに追加 2)コントローラーメソッドの戻り値で、
 supports()がtrueとなるようなパスを返す 39 @GET @Path("input") @Controller public String input() { return "thymeleaf/input.html"; } 拡張子.htmlならば Thymeleafが適用 その他の 設定不要!
  40. 40. ⑧セキュリティ:CSRF対策 • Application#getProperties()に下記の設定が必要 - EXPLICIT:対策箇所を明示的に指定 - IMPLICIT:全てのコントローラーメソッドで対策が有効 - OFF:無効 40 @ApplicationPath("api") public class MyApplication extends Application { @Override public Map<String, Object> getProperties() { Map<String, Object> properties = new HashMap<>(); properties.put(Csrf.CSRF_PROTECTION, Csrf.CsrfOptions.EXPLICIT); return properties; } ※下線付きはJAX-RSの機能です
  41. 41. ⑧セキュリティ:CSRF対策 • 設定がEXPLICITの場合、対策したいコントローラーメ ソッドには@CsrfValidを付加する • POSTおよびapplication/x-www-form-urlencodedのみ が対象となる 41 @Path(“security”) @RequestScoped public class SecurityController { … @CsrfValid @POST @Path("result") @Controller public String result(@FormParam("name") String name) { …
  42. 42. ⑧セキュリティ:CSRF対策 • ビューにはCSRFトークンを埋め込んでおく • トークンが正しくない場合の仕様は策定中の模様 • 現在のOzarkの挙動ではForbiddenExceptionが発生 42 <form action="./result" method="post"> 名前:<input type="text" name="name"><br> <input type="submit" value="送信"> <input type=“hidden" name="${mvc.csrf.name}" value="${mvc.csrf.token}"/> </form>
  43. 43. ⑧セキュリティ:XSS対策 • Encodersインタフェースに2つのメソッド 1)HTMLエスケープ(html()メソッド) 2)JavaScriptエスケープ(js()メソッド) 43 <body> こんにちは、${mvc.encoders.html(name)}さん!<br> </body>
  44. 44. ⑨その他の機能 1)MvcContext • アプリケーションパスなどの情報がの取得などが可能 • ApplicationScopedなオブジェクトなので、 MvcContext自体は@Injectで取得可能 2)イベント処理 • コントローラー処理の前後、ビュー処理の前後、リダ イレクト時にイベントを発火している • オブザーバーは自分で実装する 44
  45. 45. ⑨その他の機能 3)ファイルアップロード • Jersey(JAX-RS参照実装)の独自機能として存在 • http://yumix.hatenablog.jp/entry/2012/12/17/ 002515 4) ファイルダウンロード • JAX-RSで元々可能 • http://dev.worksap.co.jp/Members/t_tanaka/ 2011/05/31/jax-rs-file-download/ 45
  46. 46. ⑨その他の機能 5)ビューを保存するフォルダの変更 • デフォルトでは「/WEB-INF/views/」 • Application#getProperties()で指定 46 @ApplicationPath("api") public class MyApplication extends Application { @Override public Map<String, Object> getProperties() { Map<String, Object> properties = new HashMap<>(); properties.put(ViewEngine.VIEW_FOLDER, "/WEB-INF/my-views/"); return properties; } }
  47. 47. ⑨その他の機能 6)ハイブリッドクラス • コントローラーメソッドとJAX-RSリソースメソッドを
 1つのクラス内に混在させることができる 47 @Path("hybrid") public class HybridController { @Path(“view”) @GET @Controller // コントローラーメソッド public String getView() { return “view.jsp”; } @Path(“json”) @GET @Produces(“application/json”) public Response getJson() { return Response.ok().entity(someBean).build(); } }
  48. 48. 3) 実装されない機能と 今後への期待 48
  49. 49. 実装されない機能 • ボタン2度押し対策 - メーリングリスト上で
 「クライアントサイドで対応すべき」
 という意見で一致→実装しないことが決定 - 開発者がJavaScriptなどで対応する必要あり 49
  50. 50. 今後に期待する機能 • バリデーショングループのサポート - JAX-RS 2.0では ”Not Required”、
 Jersey 2.xでは ”Does Not Support”
 # JAX-RS 2.1に期待 • コントローラーで返すパス文字列 - 現状はフォルダ名まで書かなければならない 50 @GET @Path(“input") @Controller public String input() { return “hello/input.jsp”; }
  51. 51. 今後に期待する機能 • Modelsなどをメソッド引数としてDIする
 → CDI 2.0に期待 51 // これはOK @Inject private Models models; @GET @Path("result") @Controller public String result(…) { models.put("name", name); return "hello/result.jsp"; } // 現時点ではNG @GET @Path("result") @Controller public String result( @Inject Models models) { models.put("name", name); return "hello/result.jsp"; }
  52. 52. 今後に期待する機能 • 認証・認可などのセキュリティ機能
 → Java EE Security API(JSR 375)に期待 52
  53. 53. 今後に期待する機能 • FaceletsまたはThymeleafを使用している画面 で、POST送信時にIOExceptionが発生する - Jerseyによってリクエストボディが消費済みになって いることが要因 - Jersey MVC + Thymeleafでも同様の問題が発生 - JerseyのJIRAにコメントしましたが未返答
 https://java.net/jira/browse/JERSEY-766 53
  54. 54. 4) FAQ 54
  55. 55. よくある(と思われる)疑問 • Q1: Jersey MVCに似ていないか? • A1: 共に、JAX-RSとJerseyという同じ技術をベースとしているので、必然的に似てき ます。 • Q2: なぜ、Jersey MVCがあるにも関わらず、MVC 1.0が作られているのか? • A2: Jersey MVCは、あくまでJerseyの独自機能であり、Java EE標準ではありませ ん。Java EE標準のアクションベースフレームワークとして、MVC 1.0が作られていま す。 • Q3: MVC 1.0が完成したら、Jersey MVCはどうなるのか? • A3: 個人の予想ですが、しばらくは共存して、徐々にMVCへの移行が推奨されるのでは ないかと思います。Jerseyの中の人ではないので、確定的なことは申し上げられませ ん。 55
  56. 56. 5) まとめ 56
  57. 57. まとめ • MVC 1.0は、 • Java EE 8標準で導入されるアクション ベースフレームワーク • JAX-RSを中心に、既存のJava EEの技術を最大 限に活用している • URLマッチング・バリデーション・例外処理・セ キュリティなどの基本的な機能がそろっている 57
  58. 58. 参考資料 • JSR 371 Early Draft
 http://download.oracle.com/otndocs/jcp/mvc-1-edr- spec/index.html • MVC-SPECのソースコード
 https://github.com/spericas/mvc-spec • Ozarkのソースコードおよびテストコード
 https://github.com/spericas/ozark • MVC 1.0のメーリングリスト
 https://java.net/projects/mvc-spec/lists
 58
  59. 59. 本日のソースコード • GitHubにアップしています
 https://github.com/MasatoshiTada/ OzarkSample - 上記のプロジェクトをビルド・実行するには、MVC- SPECおよびOzarkが必要です。この2つをgit clone 後、Ozarkのpom.xmlの<jersey.version>を「2.19」 に変更して、MVC-SPEC#Ozark#OzarkSampleの順に Mavenでビルドしてください。 59
  60. 60. 60 GlassFish/Payaraで Java EEの未来を 覗いてみませんか?
  61. 61. 61 ご清聴ありがとうございました! Enjoy Java EE !!

×