ついにMVCがJakarta EEに。その歴史・機能・アーキテクチャを知ろう

113 Views

June 21, 26

スライド概要

日本 Jakarta EE & MicroProfile ユーザーグループのイベントでの資料です。

profile-image

Java、Spring、IntelliJ IDEA

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

ついにMVCがJakarta EEに。 その歴史・機能・アーキテクチャを知ろ う Jakarta EE & Microprofileセミナー 2026年6月22日 多田真敏 1

2.

このセッションについて ◆Jakarta MVCは、今までJakarta EEに無かった 「アクションベース」のWebフレームワークです。 ◆実はJakarta MVCの原型は、2015年にJava EE 8の計画が 始まったころから存在しました。そこから10年以上経ち、 今回ようやくJakarta EEに正式に含まれました。 ◆このセッションでは、その歴史的背景から、Jakarta MVCの 基本的機能、JAX-RSベースのアーキテクチャまでお話します。 2

3.

前提知識 ◆本セッションは以下の知識・経験があることを前提とします ◆Jakarta REST (旧JAX-RS) 3

4.

自己紹介 ◆多田真敏(@suke_masa) ◆JJUG・JSUGスタッフ ◆クレジットカード会社で 社内システムの内製化+AWS化 ◆OSSドキュメントの和訳 ◆Thymeleaf・Resilience4j ◆櫻坂46、北海道日本ハムファイターズ、 DB.スターマン、ゴジラ、英語学習 4

5.

多田とJava EE ◆前職・前々職ではJava研修講師 理由は後ほど説明 ◆前々職で2014年からJava EE 7の研修を担当 ◆前職でもJava EE 7の研修を担当(2017年くらいまで) ◆2016年くらいからSpringの研修も担当 ◆現職の開発ではSpring+AWSが中心 5

6.

[宣伝] 頑張って書いたので買ってください ハッシュタグ #つくまなBoot 書きました! 6

7.

環境 ◆Wildfly 40.0.0.Final ◆Jakarta MVC 3.0 ◆Thymeleaf 3.1 ◆JDK 25 7

8.

もくじ ① Jakarta MVC導入の背景 ② Jakarta MVCの機能 ③ Jakarta MVCのアーキテクチャ 8

9.

もくじ ① Jakarta MVC導入の背景 ② Jakarta MVCの機能 ③ Jakarta MVCのアーキテクチャ 9

10.

Webフレームワークの種類 ① アクションベースフレームワーク ◆HTTPリクエストを主眼に置く ◆Jakarta REST、Spring MVC、Strutsなど ② コンポーネントベースフレームワーク ◆画面の部品や、クリックなどのイベントを主眼に置く ◆Jakarta Faces、Apache Wicketなど 10

11.

フレームワークの分類 HTML を返す アクション ベース コンポーネント ベース JSONなど を返す Jakarta REST Jakarta Faces ー アクションベースかつHTMLを返す フレームワークが無かった 11

12.

レガシーフレームワークからの移行コス ト ◆Struts 1やサーブレットベースの独自フレームワークなどの レガシーフレームワークはアクションベースが多い ◆これらからコンポーネントベースのJakarta Facesへの移行は アーキテクチャが完全に異なるため高コスト(ほぼ作り直し) ◆それゆえ、アクションベースでHTMLを返すフレームワークが 求められてきた 12

13.

そこでMVC 1.0登場 ◆Java EE 8での導入を目指してMVC 1.0の開発がスタート ◆参照実装はOzark ◆https://github.com/mvc-spec/ozark (既にアーカイブ済み) ◆最初のコミットは2014年11月 13

14.

当初の開発は活発だった ◆当時のスペックリードであるOracle社の2名を中心に、 メーリングリストでの議論が活発 ◆この2名は、JSFのスペックリードとJAX-RSのスペックリードを兼務 ◆Ozarkのコミットも活発 14

15.

開発の停滞 ◆2016年前後から、Oracle社のスペックリード2名の活動が 目に見えて停滞 ◆メーリングリストに返信が無い ◆コミットが無い ◆MVC 1.0のみならず、Java EE 8に向けた開発全体が停滞 ◆Java EE Guardiansが発足したのもこの頃 ◆参考記事: Java EEを救うためにJava EEガーディアンズは結束した 15

16.

Java EEからJakarta EEへ ◆2017年9月: Java EE 8リリース ◆2019年9月: Jakarta EE 8リリース ◆2020年12月: Jakarta EE 9リリース ◆javax.* → jakarta.* ◆2022年9月: Jakarta EE 10リリース ◆2025年6月: Jakarta EE 11リリース ◆2026年?月: Jakarta EE 12リリース? 16

17.

この間、MVCはどうしてたの? ◆コミッターの一人だった このお二人は MVCの救世主 Christian Kaltepoth氏が 中心となって開発を継続 → 新たなスペックリードに ◆EE4Jの設立に尽力した Ivar Grimstad氏が (写真はお二人の GitHubから拝借) 共同スペックリードに → 近年の開発を主導 17

18.

OzarkからKrazoへ ◆MVC 1.0の参照実装Ozarkから、 Jakarta MVCの互換実装Krazoに変更 ◆https://github.com/eclipse-ee4j/krazo ◆「Ozark」を逆から読むと「Krazo」 18

19.

Jakarta MVCの苦労 ◆なかなかJakarta EEに含まれない ◆しかしChristianさん・Ivarさんを中心に、開発は続いた ◆そしてようやっと、Jakarta EE 12に含まれる予定 19

20.

まとめ ◆Jakarta MVCはHTMLを返すアクションベースフレームワーク ◆当初はJava EE 8でMVC 1.0として導入予定だったが停滞 ◆Christian Kaltepoth氏とIvar Grimstad氏の尽力で 開発が継続 ◆Jakarta EE 12でようやっと導入予定 ◆互換実装はKrazo 20

21.

もくじ ① Jakarta MVC導入の背景 ② Jakarta MVCの機能 ③ Jakarta MVCのアーキテクチャ 21

22.

機能説明の前に ◆Jakarta MVCはJakarta RESTベースの薄いフレームワーク ◆ほとんどはJakarta RESTの機能 22

23.

依存関係 <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> <version>11.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.mvc</groupId> <artifactId>jakarta.mvc-api</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>org.eclipse.krazo</groupId> <artifactId>krazo-resteasy</artifactId> <version>4.0.2</version> </dependency> 23

24.

依存関係(続き) <dependency> <groupId>org.eclipse.krazo.ext</groupId> <artifactId>krazo-thymeleaf</artifactId> <version>3.0.0</version> <exclusions> <exclusion> <!-- 古いバージョンのThymeleafを除外 --> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>3.1.5.RELEASE</version> </dependency> </dependencies> 24

25.

準備 ◆Applicationのサブクラスを作る ◆これは完全にJakarta RESTと同じ @ApplicationPath("/web") public class WebApplication extends Application { } 25

26.

コントローラーの作成 ◆リソースクラスまたはリソースメソッドに@Controllerを付加 ◆ビューに値を渡すModelsをDI ◆バリデーション結果を保持するBindingResultをDI @Controller @Path("/idol") public class IdolController { @Inject private IdolService idolService; @Inject private Models models; @Inject private BindingResult bindingResult; 26

27.
[beta]
検索してビューに遷移
◆検索結果はmodels.put()する

◆遷移先のビューはWEB-INF/views配下のパスを指定
@GET
@Path("/")
public String searchByName(
@QueryParam("keyword") @DefaultValue("") String keyword) {
List<Idol> idolList = idolService.findByNameOrderById(keyword);
models.put("idolList", idolList);
return "idol/index.html";
}
WEB-INF/views/idol/index.html
に遷移

27

28.

利用できるビュー ◆Krazo本体にはJSP連携機能のみ ◆krazo-thymeleaf: Thymeleaf連携 ◆krazo-freemarker: Freemarker連携 ◆他にもいろいろ ◆https://github.com/eclipse-ee4j/krazo-extensions 参照 28

29.

フォームクラス ◆各フィールドに@FormParam+@MvcBindingを付加 ◆@MvcBindingにより、バリデーションエラー時でも例外にならない public class IdolForm { @MvcBinding @FormParam("name") @NotBlank(...) @Size(...) private String name; @MvcBinding @FormParam("birthday") @NotBlank(...) @Pattern(...) private String birthday; @MvcBinding @FormParam("bloodType") @NotBlank(...) @Pattern(...) private String bloodType; 29

30.
[beta]
登録とバリデーション
◆引数に@Validを付加することでバリデーションを有効化

◆バリデーションエラーはBindingResultが保持
@POST @Path("/join")
public String join(@Valid @BeanParam IdolForm idolForm) {
if (bindingResult.isFailed()) { // エラーが1つでもあればtrue
models.put("bindingResult", bindingResult);
models.put("idolForm", idolForm);
return "idol/join.html";
}
Idol idol = idolForm.toEntity();
idolService.join(idol);
return "redirect:/idol"; // /idolにリダイレクト
}

30

31.
[beta]
バリデーションエラーメッセージの表示
◆BindingResult#getErrors()で

各項目のエラーメッセージを取得(戻り値はSet)
<th>名前</th>
<td>
<input type="text" name="name" th:value="*{name}">
<ul class="error"
th:unless="${#sets.isEmpty(bindingResult.getErrors('name'))}">
<li th:each="err : ${bindingResult.getErrors('name')}"
th:text="${err.message}">エラー</li>
</ul>
</td>

31

32.

MvcContext ◆アプリケーション情報を保持するインタフェース ◆ビューからは常に${mvc}で参照可能 32

33.
[beta]
CSRF対策
◆POSTの際にCSRFトークンを埋め込む

◆CSRFトークンのチェックは自動でやってくれる
→ トークンが不正な場合は例外発生
<form method="post" ...>
<input type="hidden"
th:name="${mvc.csrf.name}"
th:value="${mvc.csrf.token}">
...
</form>

33

34.
[beta]
パスの指定
◆MvcContext#getBasePath()で

コンテキストルート+アプリケーションパスが取得できる
<form method="post"
th:action="@{${mvc.basePath} + '/idol/join'}"
th:object="${idolForm}">
<input type="hidden"
th:name="${mvc.csrf.name}"
th:value="${mvc.csrf.token}">
...
</form>

34

35.

その他の機能 ◆@RedirectScoped ◆Cross-Site Scripting対策 ◆国際化 ◆フォームメソッドオーバーライド ◆ぜひ仕様書を読んでみてください(短いです) ◆https://jakarta.ee/specifications/mvc/3.0/jakarta-mvc-spec-3.0 35

36.

まとめ ◆リソースクラスまたはリソースメソッドに@Controllerを付加 ◆Modelsで値を保持 ◆BindingResultでバリデーション結果を保持 ◆ビューはWEB-INF/viewsに置く ◆その他、そんなに機能は多くない → Jakarta RESTの機能を活用する 36

37.

もくじ ① Jakarta MVC導入の背景 ② Jakarta MVCの機能 ③ Jakarta MVCのアーキテクチャ 37

38.

Jakarta MVCのアーキテクチャ ◆Jakarta MVCはJakarta RESTベースの薄いフレームワーク ◆Jakarta MVCのアーキテクチャ ≒ Jakarta RESTのアーキテクチャ ◆特にJakarta RESTのProcessing Pipelineが重要 38

39.

各コンポーネントの説明 ◆MessageBodyReader: リクエストボディをリソースメソッドの引数に変 換。 引数の型やリクエストボディの種類などで適切なものが1つ選ばれる ◆MessageBodyWriter: リソースメソッドの戻り値をレスポンスボディに 変換。 戻り値の型やレスポンスボディの種類などで適切なものが1つ選ばれる ◆ContainerRequestFilter: リクエストの前処理 ◆ContainerResponseFilter: リソースメソッドの後処理 ◆ReaderInterceptor: MessageBodyReaderの前処理+後処理 39

40.

Jakarta RESTのProcessing Pipeline リクエス ト PreMatch PreMatch Container Container Container Request Request Request Filter Filter Filter PreMatch PreMatch Container Reader Container Request Inter Request Filter ceptor Filter (前処理) Message Body Reader PreMatch PreMatch Container Reader Container Request Inter Request Filter ceptor Filter (後処理) リソース メソッド レスポン ス PreMatch PreMatch Container Writer Container Request Inter Request Filter ceptor Filter (後処理) Message Body Writer PreMatch PreMatch Container Writer Container Request Inter Request Filter ceptor Filter (前処理) PreMatch PreMatch Container Container Container Request Request Response Filter Filter Filter 40

41.

@NameBinding ◆特定のリソースメソッドにだけFilter・Interceptorを ここにだけ フィルターが 実行される 適用する目印 @NameBinding @Target({TYPE, METHOD}) @Retention(RUNTIME) public @interface Sample {} @Sample @Provider public class SampleResponseFilter implements ContainerResponseFilter { ... } @Path("/...") public class MyResource { @GET @Path("/...") @Sample public Response get1() { ... } @GET @Path("/...") public Response get2() { ... } } 41

42.

Jakarta MVCの処理の流れ ① @Controllerを付加した リソースメソッドの後処理に ViewResponseFilterが動く // @Controllerのソースコード @NameBinding @Target({TYPE, METHOD}) @Retention(RUNTIME) public @interface Controller {} ② ViewResponseFilterが リソースメソッドの戻り値を @Controllerの正体は @NameBinding Viewableに変換 ③ Viewableに対応した MessageBodyWriter実装である ViwableWriterが動く 42

43.

Jakarta MVCの処理の流れ ④ ViewableWriter内で、 ビューの拡張子などから <<interface>> ViewEngine 適切なViewEngine実装を選ぶ JspViewEngine ⑤ ViewEngine実装が ビューをレスポンスに書き出す Thymeleaf ViewEngine Freemarker ViewEngine 43

44.

まとめ ◆Jakarta MVCはJakarta RESTベースの薄いフレームワーク ◆特にJakarta RESTのProcessing Pipelineが重要 ◆@Controllerを付加することで MesageBodyWriter実装が動き、その中でViewEngineが動く 44

45.

最後のまとめ ◆Christianさん・Ivarさんに感謝して使いましょう ◆Jakarta RESTのProcessing Pipelineは しっかり理解しましょう 45