Develop with pleasure!

福岡でCloudとかBlockchainとか。

Sitemesh+Freemarker

Tiles+FreeMarkerの構成だと、FreeMarker内でTilesのtaglibを使用することとなり、Servletコンテナを必要とし、FreeMarkerのローカルリソースを参照する機能が有効にならない。そのため、これを機にレイアウトエンジンをTiles→Sitemeshに変更してみた。

以下のjarをClassPathに追加

  • sitemesh.jar
  • struts2-sitemesh-plugin.jar

web.xmlを変更

ActionContextCleanUpとFreeMarkerPageFilterの定義を追加する。

<filter>
    <filter-name>struts-cleanup</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>

<filter-mapping>
    <filter-name>struts-cleanup</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>sitemesh</filter-name>
    <filter-class>org.apache.struts2.sitemesh.FreeMarkerPageFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

ActionContextCleanUpフィルタはFilterDispatcherフィルタに対し、HttpServletRequestからライフサイクルを終えたオブジェクトを通知する役割があるらしい。

定義ファイルを配置

WEB-INF直下にsitemesh.xml及びdecorators.xmlを配置。sitemesh.xmlはstruts2-showcase-xxx.war内にあったものをそのまま利用。decorators.xmlはこんな感じ。

<?xml version="1.0" encoding="UTF-8"?>

<decorators defaultdir="/WEB-INF/decorators">
    <!-- Any urls that are excluded will never be decorated by Sitemesh -->
    <excludes></excludes>

    <decorator name="freemarker" page="default.ftl">
        <pattern>/*</pattern>
    </decorator>

</decorators>

Tilesの場合は1画面ずつ、tiles-def.xmlにレイアウトの定義をしないといけなかったが、Sitemeshの場合は、タグでレイアウトを適用するパターンを定義できるため、定義内容がかなりすっきりする。上の設定例だと、全ての画面について、default.ftlが適用されることになる。

レイアウト定義

レイアウトファイルであるdefault.ftlの定義。これは、/WEB-INF/decorators直下に配置。どうもこのレイアウトファイルはwarの中にパッケージングされていないとダメらしい。

<?xml version="1.0" encoding="Shift_JIS"?>
<html>
    <head>
        <link href="url"/>
        <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"/>
        <title>Hoge</title>
    </head>
    <body background="url" bgcolor="white" text="black" link="green" vlink="fuchsia" alink="yellow">
        ${body}
    </body>
</html>

${body}の部分が実際にコンテンツが挿入される部分。

画面ファイル

画面ファイルはFreeMarkerも定義。

<form action="dispatch.action" method="POST">
    <input type="hidden" name="loginId" value="${loginId}"/>
    <input type="submit" value="ログイン"/>
</form>

${body}の部分に、formタグが挿入される。別に画面ファイルにheadやbody等のタグがあっても良く、レイアウト定義の${body}は、画面ファイルのタグの内容をそのままレイアウトの該当部分にマッピングする。タグが置換されているようなイメージ。この辺は、Tilesとちょっと異なる部分。Tilesは明示的に置換箇所をTilesのtaglibで定義する。

StrutsのResultの定義は今まで通り、画面ファイルのパスを返せば良い。基本的にSitemeshは、ブラウザにレスポンスが返る前にレスポンスを横取りし、レイアウト構成を適用させるという仕組みで動いているため、Struts2+FreeMarkerの構成としては、特にSitemeshを意識することが無い。なので、FreeMarkerのテンプレートファイルの場所も、web.xmlにtemplatePathとして設定した内容が生きる。