Spring BootとThymeleafでWebアプリを書く

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

よく訓練されたアップル信者、都元です。しばらくブログ業を怠っておりました。気を引き締めて、ブロガー復帰宣言。

さてここまでこのSpring Frameworkシリーズでは下記のような流れで色々紹介して来ました。

  • Springの基礎
  • DBの扱い方
  • Spring Bootの紹介
  • AWSへのデプロイ

っていうのがおさらい(適当)。ここまでは、 text/plain を返すようなアプリケーションしか書いていませんでしたが、今回いよいよ、HTMLを返せるようにしてみたいと思います。

前回からの微調整

その前にちょっとコードの整理をしました。

mainメソッドのシンプル化

まず SpringApplication の起動方法。static methodの run を使って1行で起動するように簡略化して書いてみました。 → /diff

シンプルにやる場合は、起動はこれだけでいいんですね。

SpringApplication.run(BerserkerApplication.class, args);

リクエストハンドラの整理

次に、ここまでHTTPリクエストハンドラとなるメソッドを BerserkerApplication 内に書いていましたが、これをコントローラ専用のクラス RootController を作って移動させました。通常のアプリケーションではリクエストハンドラが数個で済むことは無いので、複数のクラスを使ってハンドラを整理するのが一般的です。 → /diff

RestController から Controller へ

その上で、@RestController というコントローラ指定をやめ、代わりに @Controller を使うようにしました。 → /diff

@RestController が付いたクラスにあるリクエストハンドラメソッドは、戻り値としてHTTP response bodyそのものを表すクラス(ResponseEntity等)を返すように作ります。

一方で、@Controller が付いたクラスでは、戻り値として「ビューの名前」を文字列で返すように作ります。 @Controller クラスで ResponseEntity 等を直接返すように作りたい場合は、そのメソッドに @ResponseBody を付けます。

言い換えると @RestController はハンドラにいちいち @ResponseBody を付けずにすませるための仕組みでした。

今回作るハンドラでは、HTTP response bodyを直接返すのではなく、HTMLビューを使いたいので、@Controller 方式に書き換えました。

ユーザ一覧のパスを "/" から "/users" に変更

最後に、今までサンプルで使ってきたDBからユーザ一覧を読み込んで表示する機能は/ではなく/usersにマッピングしました。 → /diff

Thymeleaf

screenshot 2016-05-25 11.55.12

さて、Javaの世界においてHTMLのビューを司る技術は、JSPTilesが有名かもしれません。その他にも、VelocityFreemarkerといったテンプレートエンジンを使ったビューの構築という選択肢があります。

その中でもSpringとの相性が良く、お勧めしたいのがThymeleafです。嬉しいことに日本語のドキュメントもあります。余談ですが、Thymeleafというのは「タイムリーフ」と読むので間違いないようです。

本連載はSpring Frameworkの紹介に寄せたいので、Tyhmeleafに関するご紹介は最低限に留めたいと思っています。当ブログでも過去に何件かの記事がありますので、詳しくはそちらをご覧ください。

Spring BootアプリケーションでThymeleafを導入する

これがまた簡単なんですよ。まずは依存ライブラリとして spring-boot-starter-thymeleaf を追加します。これだけで、Thymeleafを使う環境が整います。 → /diff

次に、src/main/resources/templates/ 内にHTMLを配置します。このディレクトリに配置したindex.htmlというファイルは、indexという名前のビューとして利用できます。

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>Berserker index page</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <meta charset="UTF-8" />
</head>
<body>
  <p>Hello, berserker!</p>
</body>
</html>

最後に、/に対するハンドラメソッドを追加します。内容としては、表示したいビュー名を文字列で返すだけです。index.htmlをビューにしたいので、return "index" としています。

以上。

恒例の、動かしてみようのコーナー

$ git clone https://github.com/classmethod-aws/berserker.git
$ cd berserker
$ git checkout 12.0
$ ./gradlew bootRun
(略)
2016/05/25 11:30:13.711 [main] INFO  o.s.b.c.e.t.TomcatEmbeddedServletContainer:162 - Tomcat started on port(s): 8080 (http)
2016/05/25 11:30:13.716 [main] INFO  j.c.e.berserker.BerserkerApplication:57 - Started BerserkerApplication in 6.286 seconds (JVM running for 7.16)

起動したようなので、 http://localhost:8080/ にアクセスします。

screenshot 2016-05-25 11.31.04

もう、なんてことないですが、普通にHTMLが出力されました。

動的なページを作る

せっかくなら、動的に変わるページを作ってみたいですよね。というわけで、ビューを以下のように書き換えてみました。

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>Berserker index page</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <meta charset="UTF-8" />
</head>
<body>
  <p>Hello, berserker!</p>
  <p>Now <span th:text="${now}">foobar</span></p>
  <ul>
    <li th:each="user : ${users}" th:text="${user.username}">bazqux</li>
  </ul>
</body>
</html>

そしてコントローラは、こう。引数に Model を受け取って、そのモデルに nowusers という名前で2つの情報を詰め込んでいます。 → /diff

@RequestMapping(value = "/", method = RequestMethod.GET)
@Transactional
public String index(Model model) {
  log.debug("index");
  Iterable<User> users = userRepos.findAll();
  model.addAttribute("now", new Date().toString());
  model.addAttribute("users", users);
  return "index";
}

Spring MVCではこれ以外にもビューにモデルを渡す方法がいくつかありますが、今回は紹介しません。

さて結果は下記でお試しください。

$ git clone https://github.com/classmethod-aws/berserker.git
$ cd berserker
$ git checkout 12.1
$ ./gradlew bootRun

screenshot 2016-05-25 11.56.57