Rails における ERB と同様に、Spring Boot でもテンプレートエンジンを利用できます。今回は特に Thymeleaf (タイムリーフ) のサンプルコードを、こちらのページで構築した環境をもとにまとめます。
公式ドキュメント
.
|-- build.gradle
|-- gradle
| `-- wrapper
| |-- gradle-wrapper.jar
| `-- gradle-wrapper.properties
|-- gradlew
|-- gradlew.bat
`-- src
`-- main
|-- java
| `-- hello
| |-- Application.java
| `-- GreetingController.java
`-- resources
|-- static
| `-- index.html
`-- templates
`-- greeting.html
設定内容についてはこちらをご参照ください。
buildscript {
ext {
springBootVersion = '1.5.3.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'gs-serving-web-content'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
// `spring-boot-starter-web` に依存するため、`spring-boot-starter-web` を明記する必要はありません。
// https://github.com/spring-projects/spring-boot/blob/v1.5.3.RELEASE/spring-boot-starters/spring-boot-starter-thymeleaf/pom.xml#L27
compile('org.springframework.boot:spring-boot-starter-thymeleaf')
// 開発時に便利な機能を利用できるようにします。
compile('org.springframework.boot:spring-boot-devtools')
}
Spring Boot のエントリーポイントとなるクラスです。アノテーションの意味については、こちらをご参照ください。
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package hello;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
//import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class GreetingController {
@RequestMapping("/greeting") // HTTP GET/POST/PUT/PATCH/DELETE などすべてマッピングされます。
// @RequestMapping(path = "/greeting", method = RequestMethod.GET) // GET だけをマッピングする場合の記法
public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
// `src/main/resources/templates/` 内の View ファイル名を指定します。
// メソッド名や `@RequestMapping` で指定したパス名と一致する必要はありません。
return "greeting";
}
}
項目 | 概要 |
---|---|
@Controller |
メソッドに @RequestMapping アノテーションを設定するクラスに付与します。 |
@RequestMapping("/greeting") |
HTTP リクエスト /greeting を処理するアクションメソッドとして設定します。 |
@RequestParam |
アノテーションが設定された引数 String name に対して、HTTP リクエスト内の value="name" パラメータを代入します。required=false となっているため、HTTP リクエスト内に存在する必要はなく、既定値は defaultValue="World" です。 |
model.addAttribute("name", name) |
Thymeleaf テンプレート内で name という名称で変数 name の値を参照できるようにします。 |
こちらのページに記載の Optional を利用しても required=false
相当の設定ができます。
public String greeting(@RequestParam(value="name") Optional<String> name, Model model) {
model.addAttribute("name", name.orElse("World"));
return "greeting";
}
通常の HTML ファイルは static ディレクトリに格納します。
<!DOCTYPE HTML>
<html>
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Get your greeting <a href="/greeting">here</a></p>
</body>
</html>
Thymeleaf の機能を用いて <p th:text="'Hello, ' + ${name} + '!'" />
を動的に生成しています。th:text
は data-th-text
としても機能します。前者は html タグ内の xmlns:th="http://www.thymeleaf.org"
を記述しないと IDE が警告を表示しますが、後者は HTML5 の記法であるため、警告されません。公式ドキュメントに合わせて、本ページでは前者を利用します。
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
./gradlew build
java -jar build/libs/gs-serving-web-content-0.1.0.jar
(or ./gradlew bootRun ←spring-boot-devtools を利用する場合はこちら)
以下の URL にアクセスしてみましょう。
http://localhost:8080/
http://localhost:8080/greeting
http://localhost:8080/greeting?name=xxxxx
spring-boot-devtools
についてSpring Boot は Java アプリケーションのため、「コードの変更、ビルド、アプリケーション再起動、ブラウザリロード」の一連のサイクルを回すための時間がかかります。spring-boot-devtools を導入すると、開発時において、以下のような事項が改善されます。ただし、java -jar
での実行時などは production 環境扱いとなるため、以下の機能は有効になりません。
.class
が変更されると、アプリケーションが自動で再起動されるようになります。
.java
はクラスパス外のファイルです。.class
と異なり、再起動せずに変更を動作確認できます。hello.Application
に設定して適用Rails の多言語対応と同様の機能が Thymeleaf にも存在します。既定では以下のファイルが参照されます。ブラウザの言語設定を切り替えることで表示確認できます。
src/main/resources/messages.properties
(ja,en に存在しない場合の既定値)
hello.sub=Hello world default
src/main/resources/messages_ja.properties
(日本語; UTF-8 で保存すれば native2ascii で変換する必要はありません。文字化けする場合は、Eclipse 設定における「General → Content Types → Content types → Text → Java Properties File → Default encoding → UTF-8 → Update → OK」で解消します)
hello.sub=こんにちは世界
src/main/resources/messages_en.properties
(英語)
hello.sub=Hello world en
greeting.html
<p th:text="#{hello.sub}" />
messages.properties
hello.sub=Hello {0} and {1}
GreetingController.java
model.addAttribute("msgKey", "hello.sub");
model.addAttribute("name1", "aaa");
model.addAttribute("name2", "bbb");
greeting.html
<p th:text="#{hello.sub(${name1}, ${name2})}" />
<p th:text="#{${msgKey}(${name1}, ${name2})}" />
th:text
は Rails の ERB における <%= %>
に相当します。エスケープせずに出力するためには <%== %>
に相当する th:utext
を利用します。セキュリティ上の観点から、通常は th:text
でエスケープします。
messages.properties
hello.sub=Hello <b>world</b> default
greeting.html
<p th:utext="#{hello.sub}" />
th:text
内で利用できる記法文字列、数値、変数の結合
<p th:text="'Hello ' + ${name}" + 123 />
文字列への変数の埋め込み
<p th:text="|Hello ${name}|" />
数値計算
<p th:text="'1 + 1 = ' + (1 + 1)" />
真偽値
<p th:text="!true" />
<p th:text="true and false" />
<p th:text="1 gt 1" />
条件分岐 (>
や <
は使用されるべきでないため、gt (>), lt (<), ge (>=), le (<=) を利用します。)
<p th:text="(2 gt 1) ? 'mystr'" />
<p th:text="(1 gt 1) ? 'mystr' : 'elsestr'" />
Getter の利用
<p th:text="${user.name}" />
<p th:text="${user.getName()}" />
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
User user = new User();
user.setName("user name");
model.addAttribute("user", user);
<p th:text="${#strings.length('aaa')}" />
<p th:text="${#strings.toUpperCase('aaa')}" />
その他の特殊変数
<p th:text="${#vars}" />
<p th:text="${#locale}" />
th:object
でオブジェクトを選択することで、ブロック内部で略記 (*{}
または #object.
) できます。
<div th:object="${user}">
<p th:text="*{name}" />
<p th:text="${#object.name}" />
</div>
GreetingController.java
model.addAttribute("url", "https://www.qoosky.io");
model.addAttribute("query", "spring boot");
model.addAttribute("uuid", "2496c58738");
greeting.html
<a th:href="@{https://www.qoosky.io/search(q=${query})}">qoosky search</a>
<a th:href="@{https://www.qoosky.io/techs/{uuid}(uuid=${uuid})}">qoosky Thymeleaf</a>
<a th:href="@{${url} + '/techs/{uuid}'(uuid=${uuid})}">qoosky Thymeleaf</a>
th:with
を利用して、ブロック内で有効な一時変数を定義できます。
model.addAttribute("count", 123);
<div th:with="isEven=${count % 2 == 0}">
<p th:text="${isEven} ? 'even' : 'odd'" />
</div>
<p th:if="false">本タグは表示されません。</p>
<p th:unless="true">本タグは表示されません。</p>
<div th:switch="1 + 1">
<p th:case="0">zero</p>
<p th:case="1">one</p>
<p th:case="*">default</p>
</div>
GreetingController.java (参考: Java コレクション)