Struts2.5でThymeleaf3を使う

# ThymeleafはHTMLのまま使えるテンプレートエンジン

[Thymeleaf](http://www.thymeleaf.org/) は HTMLをテンプレートとして使えるJavaWebアプリケーションのビュー用テンプレートエンジンです。

Webサイトのラフデザイン・モックアップ・デザインコンセプトとして作ったHTMLに対して、基本的にはそのHTML要素を崩すことなく、Java Webアプリケーションのレスポンスを盛り込めます。

もっとも簡単なサンプルコードを例に挙げると…

```html
<input type="text" name="userName" value="カピバラさん" th:value="${user.name}" />
```

これをブラウザで直接見た場合は、名前空間 thの属性はそのまま、

```html
<input type="text" name="userName" value="カピバラさん" th:value="${user.name}"/>
```

になり、th:valueの内容はブラウザで特に何も表示されません。

Thymeleafを経由した場合は、`th:value`に指定した値が出力します。例えば user.name の値が たわしネズミ の場合は、

```html
<input type="text" name="userName" value="たわしネズミ" />
```

と出力します。

このように、ブラウザで直接HTMLを見た場合と、Webアプリケーションから経由した場合とで別の属性を指定しますので、HTMLを使ったデザイン側と、Webアプリケーション側の実装で編集個所を分割でき、お互い同じHTMLで作業もできます。

## Struts2でThymeleaf3を使う方法

以下の2つどちらかをお使いください

* MavenのCentralRepositoryから入手
* Githubからクローン

### Maven Central Repositoryから入手

mavenのCentralRepositoryからも入手できるようになりました！以下はmavenでの設定例です。

```xml:pom.xml
<!-- https://mvnrepository.com/artifact/com.github.a-pz/struts2-thymeleaf3-plugin -->
<dependency>
    <groupId>com.github.a-pz</groupId>
    <artifactId>struts2-thymeleaf3-plugin</artifactId>
    <version>1.2.0-RELEASE</version>
</dependency>
```

[maven central repository:https://mvnrepository.com/artifact/com.github.a-pz/struts2-thymeleaf3-plugin/1.2.0-RELEASE](https://mvnrepository.com/artifact/com.github.a-pz/struts2-thymeleaf3-plugin/1.2.0-RELEASE)

### Githubからクローンする

[Struts2-Thymeleaf3-pluginの名前でプラグインを作成しました。Githubに公開しています](https://github.com/A-pZ/struts2-thymeleaf3-plugin) 
こちらをクローンするかmasterのzipをダウンロードしてください。mavenプロジェクトで作成しています。

導入方法は、Eclipseからmavenプロジェクトとしてインポートするだけです。

また、こちらを使った [Struts2+Thymeleaf3のサンプルプロジェクト](https://github.com/A-pZ/struts2-thymeleaf3-sampleapp/)も公開しています。導入方法の手間なく一発でインポートでき、すぐにWebアプリケーションとして実行できます。

## 導入方法

Pleiades All in one Eclipse 4.2以降を使います。
mavenプロジェクトですので、他のIDEでも特に問題ないでしょう。

### 1. 公式ブランクプロジェクトの導入
[Pleiades All in one Eclipseを用いたStruts2公式ブランクプロジェクトの導入](http://qiita.com/alpha_pz/items/e2feb0fd99c002032a52) に沿って、Struts2公式のArchetypeを導入してください。今回はリンク先に従い、conventionを使います。

### 2. Javaランタイムを1.8に修正
できあがったプロジェクトのpom.xmlを修正します。Javaランタイムバージョンが1.5を指定していますので、1.8に修正します。

build → plugins → plugin の artifactId が maven-compiler-plugin の箇所にて、sourceとtargetを1.5から1.8にします。

```xml
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
```

この後、Eclipseがmavenプロジェクトの更新を要求しますので、**クイックフィックスからプロジェクトの更新** をします。

### 3. WTPの準備をする
[EclipseでWTPを使ったアプリケーションサーバを準備する](http://qiita.com/alpha_pz/items/57c574c622fdaba152ff) に沿って、WTPを使ってアプリケーションサーバを準備します。今回もここに従いTomcat8を利用します。

### 4. Struts2-Thyemelaf3-pluginの設定を追加する。

ブランクプロジェクトに対して、Struts2-Thymeleaf3-pluginの設定をします。未設定時はデフォルトの設定になります。

以下は設定例です。（デフォルト設定）

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
	<constant name="struts.enable.DynamicMethodInvocation" value="false" />
	<constant name="struts.devMode" value="true" />
	<!-- ここから追加↓ -->
	<constant name="struts.thymeleaf.templateMode" value="HTML5" />
	<constant name="struts.thymeleaf.encoding" value="UTF-8" />
	<constant name="struts.thymeleaf.prefix" value="/WEB-INF/content/templates/" />
	<constant name="struts.thymeleaf.suffix" value=".html" />
	<constant name="struts.thymeleaf.cacheable" value="true" />
	<constant name="struts.thymeleaf.cacheTtlMillis" value="3600000" />
	<constant name="struts.thymeleaf.templateEngineName" value="default" />
	<!-- ここまで↑ -->
</struts>
```

設定内容の詳細を以下の表にまとめました。struts.thymeleaf.は省略しています。

|設定名|値の説明|
|:---|:---|
|templateMode|テンプレートファイルの形式。HTML5やXHTMLなど。|
|encoding|テンプレートファイルの文字コード|
|prefix|テンプレートファイルの配置ディレクトリ|
|suffix|テンプレートファイルの拡張子|
|cacheable|テンプレートファイルのキャッシュ化。falseにすると、テンプレートを毎回読み込む。開発用。|
|cacheTtlMillis|テンプレートキャッシュの有効期間(ミリ秒)|
|templateEngineName|Struts2-Thymeleaf3-pluginが実行するテンプレートエンジン形式の名前。defaultとoldがある。|

templateEngineNameでdefaultを選択すると、Spring framework管理にあるインスタンスもThymeleafから参照できます。これにより、Struts2-Spring-pluginとAspectJを利用して、ActionクラスとSpring管理にあるインスタンスをThymeleafのテンプレートから取得できます。

### 5. ActionクラスでThymeleafのResultを返す

Struts2-Thymeleaf3-pluginを導入すると、Actionクラスの実行結果であるResultに thymeleaf ならびに thymeleaf-spring が選べます。

Actionクラスの実装例を以下に示します。

```java
package serendip.sturts.thymeleaf.struts2_thymeleaf_sampleapp.actions;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;

import com.opensymphony.xwork2.ActionSupport;

/**
 * <code>Set welcome message.</code>
 */
@Namespace("/")
@ParentPackage("struts-thymeleaf")
@Results({@Result(name=ActionSupport.SUCCESS, type="thymeleaf", location="index")})
public class HelloAction extends ActionSupport {
	
	@Action("")
    public String execute() throws Exception {
        name = "This is thymeleaf3!";
        
        return SUCCESS;
    }
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	private String name;
}
```

このActionクラスでは、フィールド name に 文字列を設定しているかんたんなものです。

必要な設定は次の2箇所です。

* `@ParentPackage`に、Struts2-Thymeleaf3-Pluginのパッケージである struts-thymeleaf を指定します。
* `@Result`にて指定したtype属性に thymeleaf または thymeleaf-spring を指定します。

location属性では、特に拡張子は指定しません。この場合、先ほどのStruts2-Thymeleaf3-pluginの設定にて、prefixにhtmlを指定してたので、index.htmlへ遷移します。ファイルの置き場所は、/WEB-INF/content/templates/ です。

### 6. Thymeleafのテンプレートを作る

Struts2-Thymeleaf3-pluginの設定と、ActionクラスのResult設定から、表示するHTMLファイルは、/WEB-INF/content/templates/index.html ですから、ここにHTMLファイルをThymeleaf対応したHTMLテンプレートを置きます。

以下にサンプルを示します。

```html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org">
<body>
<form action="." th:action="@{selection}">
  [[${name}]]
  
  <input name="name" type="text" value="" th:value="${name}" />
</form>
</body>
</html>
```

アプリケーションを実行すると、`This is thymeleaf3!`の文字列と、テキストボックスにも This is thymeleaf3! の文字が出力されていることがわかります。これでStruts2とThymeleaf3を連携することができました！

## その他の機能

Actionクラスが持っているStruts2用のフィールドを出せます。具体的にはActionエラー、Actionメッセージ、FieldErrorメッセージです。それぞれ以下のようにすると出力できます。

```html
[[${actionErrors}]] ..... List形式
[[${actionMessages}]] ..... List形式
[[${fieldErrors}]]　..... Map形式(キー名はフィールド名)
```

## SpringBeanの参照機能

Spring管理にあるBeanのみが対象です。HTMLテンプレート中に何らかのJavaで処理を行った結果を得たい場合、例えばマスターデータをSpring経由で検索しておき、その内容をキャッシュしておいてあるものをそのまま出力する場合や、リストボックスの内容に利用するなどの使い方があるでしょう。

Spring管理にあるBeanの取得には以下の前提条件があります。

* Struts2-Spring-pluginを導入すること
* Struts2-Thymeleaf3-pluginの設定 templateEngineName を spring にする
* Actionにて戻すResultのtypeに thymeleaf-sping を設定する

こうすることで、Thymeleafテンプレート中で次のようにすると出力します。以下に、Spring管理にあるbeanを sampleServiceの名前で設定したクラスのメソッドを実行した結果を表示する例を示します。

```html
${beans.sampleService.getOrderedList()}
```
## Parent-PackageにThymeleafを使わない場合

継承するパッケージに Struts2-Thymeleaf3プラグイン用の struts-thymeleaf を指定せず、別のインターセプタスタックを利用する場合は、struts.xmlにてresult-typesの定義を追加します。

```xml:struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <package name="sample-package" abstract="true" extends="struts-default">
	<result-types>
            <result-type name="thymeleaf" class="serendip.struts.plugins.thymeleaf.ThymeleafResult"/>
            <result-type name="thymeleaf-spring" class="serendip.struts.plugins.thymeleaf.ThymeleafSpringResult"/>
        </result-types>
    </package>
</struts>
```

-----------------
この記事は、Struts2.5.x+Thymeleaf3.0.11でリリースしている Struts2-Thymeleaf3-plugin 1.2.0 での解説です。