O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

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

14.055 visualizações

Publicada em

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

Publicada em: Tecnologia
  • Seja o primeiro a comentar

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 !!

×