JavaEEでは、JSF(JavaServer Faces)というJavaベースのWebアプリケーションフレームワークを用いて画面表示を行うことが多いが、JSFの代わりにThymeleafというテンプレートエンジンを用いることもできる。
今回は、JavaEEのプロジェクトを作成し、Thymeleafによる画面表示を行ってみたので、その手順やサンプルプログラムを共有する。
前提条件
下記記事の環境構築が完了していること。
やってみたこと
動的Webプロジェクトの作成
JavaEEのプロジェクトの作成は、動的Webプロジェクトを作成後、必要なライブラリを追加することによって行う。その手順は以下の通り。
1) パッケージ・エクスプローラー上で右クリックし、「新規」メニューから「その他」を選択する。
2) Webメニューの「動的Webプロジェクト」を選択し、「次へ」ボタンを押下する。
3) プロジェクト名を入力し、ターゲット・ランタイムにGlassFishを選択した状態で、「次へ」ボタンを押下する。
5) 「web.xml デプロイメント記述子の生成」にチェックを入れ、「完了」ボタンを押下する。
JavaEEのプロジェクトで必要なライブラリの配置
作成した動的Webプロジェクトを、JavaEEプロジェクトとして動作させるには、以下のjarファイルが必要である。
- disruptor-3.3.2.jar
- javax.mvc-api-1.0-edr2.jar
- log4j-api-2.4.jar
- log4j-core-2.4.jar
- log4j-slf4j-impl-2.4.jar
- ognl-3.1.jar
- ozark-1.0.0-m02.jar
- ozark-thymeleaf-1.0.0-m02.jar
- slf4j-api-1.7.12.jar
- thymeleaf-2.1.4.RELEASE.jar
- unbescape-1.1.0.RELEASE.jar
例えば、「distruptor-3.3.2.jar」は、以下のURLの「jar」リンクを押下することで取得できる。
https://mvnrepository.com/artifact/com.lmax/disruptor/3.3.2
また、取得したライブラリは全て、以下のように、WebContent/WEB-INF/lib下にコピーして貼り付ける。
サンプルプログラムの作成
作成したサンプルプログラムの構成は以下の通り。
なお、上記の赤枠は、今回追加・変更したプログラムである。
アプリケーション定義クラスの内容は以下の通りで、アプリケーションのルートパスを指定している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package demo; import javax.ws.rs.ApplicationPath; /** * JAX-RSアプリケーションのルートパスを@ApplicationPathアノテーションで * 指定するためのクラス * なお、JAX-RSとは、JavaEEでREST(HTTPをベースとしたアーキテクチャスタイル)に * 準拠したWebサービスを作るための機能のことをいう */ @ApplicationPath("/app") public class DemoApplication extends javax.ws.rs.core.Application { } |
また、コントローラクラスの内容は以下の通りで、indexメソッドでメッセージを設定し、初期表示画面に遷移するようになっている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package demo; import javax.inject.Inject; import javax.mvc.Models; import javax.mvc.annotation.Controller; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; /** * コントローラクラス */ @Path("/demo") @Controller public class DemoController { /** * Modelオブジェクト */ @Inject Models models; /** * メッセージを設定し、初期表示画面に遷移する * * @return 初期表示画面 */ @GET @Path("/index") @Produces(MediaType.TEXT_HTML) public String index() { models.put("message", "これはテストです"); return "index"; } } |
さらに、Thymeleafをテンプレートエンジンに設定するクラスの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | package demo; import java.io.IOException; import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.mvc.engine.ViewEngineContext; import javax.mvc.engine.ViewEngineException; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.glassfish.ozark.engine.ViewEngineBase; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.WebContext; import org.thymeleaf.templateresolver.ServletContextTemplateResolver; /** * Thymeleafをテンプレートエンジンに利用するためのクラス */ @ApplicationScoped public class ThymeleafViewEngine extends ViewEngineBase { /** * サーブレットコンテキスト */ @Inject private ServletContext servletContext; /** * テンプレートエンジン */ private TemplateEngine engine; /** * 指定したビュー名をサポートしているか判定 * @param view ビュー名 */ public boolean supports(String view) { return !view.contains("."); } /** * オブジェクト生成後に行う処理 */ @PostConstruct public void postConstruct() { // ViewにThymeleafを使用することを指定する ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(); resolver.setSuffix(".html"); // Viewファイルの拡張子 resolver.setPrefix("/WEB-INF/templates/"); // Viewファイルの配置場所 resolver.setTemplateMode("HTML5"); // Viewファイルのモード resolver.setCacheable(false); // Viewファイルをキャッシュするか resolver.setCharacterEncoding("UTF-8"); // Viewファイルの文字コード // (これを指定しないと日本語が文字化けする) // Viewのテンプレートエンジンに先ほどの設定内容を反映する engine = new TemplateEngine(); engine.setTemplateResolver(resolver); } /** * 指定したビュー名に対応する画面を表示 * @param ViewEngineContext ビューエンジンのコンテキスト */ public void processView(ViewEngineContext context) throws ViewEngineException { try { HttpServletRequest request = context.getRequest(); HttpServletResponse response = context.getResponse(); WebContext ctx = new WebContext(request, response, servletContext, request.getLocale()); ctx.setVariables(context.getModels()); request.setAttribute("view", context.getView()); // 指定したビュー(HTMLファイル)名に対応するHTMLを解析し画面に表示する engine.process(context.getView(), ctx, response.getWriter()); } catch (IOException e) { throw new ViewEngineException(e); } } } |
また、初期表示画面の内容は以下の通りで、Spring Bootのときと同じような内容を記載している。
1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html> <html lang="ja" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>初期表示画面</title> </head> <body> 初期表示画面に遷移しました。<br/><br/> 設定されたメッセージ: <span th:text="${message}">メッセージ</span> </body> </html> |
さらに、beans.xmlの内容は以下の通りで、「bean-discovery-mode=”all”」の設定を追加している。
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="all"> <!-- bean-discovery-mode="all"で、全てのクラスをCDIでインジェクションさせる対象としている --> <!-- なお、CDIとは、Java EEでDI(依存性の注入)やインスタンスのスコープの管理を行う機能のことをいう --> </beans> |
その他、動的Webプロジェクトを作成時と同じ内容であるが、glassfish-web.xml、web.xmlの内容はそれぞれ以下の通り。
1 2 3 4 5 6 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd"> <glassfish-web-app> <context-root>/demo</context-root> </glassfish-web-app> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <!-- Webアプリケーションの表示名 --> <display-name>demo</display-name> <!-- URLがスラッシュ(/)で終わっていた場合に表示させるファイル名 --> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> </web-app> |
サンプルプログラムの実行
サンプルプログラムの実行結果は、以下の通り。
1) demoプロジェクトをサーバーに追加するために、サーバービューのGlassFishサーバーを選択し右クリックし、「追加および除去」を選択する。
2) demoプロジェクトを選択した状態で「追加」ボタンを押下する。
3) 「構成済み」欄にdemoプロジェクトが移動するので、「完了」ボタンを押下する。
4) 以下のように、GlassFishサーバーにdemoプロジェクトが追加されていることが確認できる。
5) GlassFishサーバーを選択し右クリックし、「開始」を選択する。
6) GlassFishサーバーが起動すると、以下のように、サーバーのステータスが「始動済み、同期済み」に変更される。
7) Webブラウザ上で「http:// (ホスト名):(ポート番号)/(Webアプリケーションの表示名)/(アプリケーションのルートパス)/(コントローラクラスパス)/(コントローラメソッドパス)」とアクセスすると、下記画面(index.html)が表示されることが確認できる。
なお、(Webアプリケーションの表示名)はweb.xmlで、(アプリケーションのルートパス)はDemoApplication.javaで、それぞれ指定している。
要点まとめ
- JavaEEのプロジェクトの作成は、動的Webプロジェクトを作成後、必要なライブラリを追加することによって行う。
- アプリケーションのルートパスは、「javax.ws.rs.core.Application」クラスのサブクラスで定義する。
- コントローラクラスで、画面遷移に必要なパス指定等を行う。
- Thymeleafをテンプレートエンジンに利用する定義は、ViewEngineBaseクラスのサブクラスで行う。
- 全てのクラスをCDIでインジェクションさせる対象とするには、beans.xmlで「bean-discovery-mode=”all”」を指定する。