きり丸の技術日記

技術・エンジニアのイベント・資格等はこちらにまとめる予定です

Thymeleafを使ってSpringBootからhtmlにパラメータを渡して画面表示させる

きり丸アドベントカレンダー2020の6記事目です。


始めに宣言しておくと、この辺から「やはりIntelliJ IDEAいいなぁ…」みたいに思うことが多くなってきます。しょうがないとはいえ、GitpodやVS Codeはライブラリのimport機能が貧弱です。

コーディング中に引っかかった点は、ちゃんと明記しますが、気を付けて写経してください。

Thymeleafとは

Spring Bootが推奨しているテンプレートエンジンです。ただ、現在も推奨しているのかは、どこのリファレンスを見ればいいのかわかりませんでした。

特徴としてはJavaで画面といえばJSPだったのが、HTMLを使用できることにより、Javaを起動していない状態でもデザインを確認できることができます。つまり、デザイナーが作ったものをほとんど修正を加えずに開発者が使用できます。


と、いいつつ個人的にはあまり推奨はしません…。

理由としては、2点あります。

  1. テンプレートを分割できるせいで、HTML単体ではCSSが読み込まれなくなり、デザイン確認は難しい
  2. サーバからHtmlにパラメータを渡した際に、不備があった時の原因把握が難しい

個人的にThymeleafにいい思い出がありません。

ただし、次の2点からアドベントカレンダーにはThymeleafを採用しました。

  1. 画面を「React.js」や「Vue.js」でSPAとして作成するのは難易度が高い
  2. JSPよりはThymeleafがいい

ゴール

  • 画面を表示する
  • Javaから渡した値が画面に表示されている

手順

build.gradleにThymeleafを追加する


build.gradleに依存関係を追加する。

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
}

ThymeleafのモードをHTMLにする


ThymeleafのモードをHTMLにしてください。

デフォルトだとHTML5モードで動いてしまうらしいので、意図的にHTMLモードを設定する必要があります。

spring:
  thymeleaf:
    mode: HTML

HTMLファイルを格納する


src/main/resourcesディレクトリの下に、templatesディレクトリを作成します。

src/main/resources/templatesディレクトリに配備したファイルが、公開対象のファイルとなります。

今回は、index.htmlファイルを格納します。

${message}と${todos}等は、Java側から設定するパラメータを表示しています。

<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
   <meta charset="UTF-8" />
   <title>TODOアプリ</title>
</head>

<body>
    <h1>TODOアプリ</h1>
    <h1 th:text="${message}"></h1>
    <table border="1">
        <tr>
            <th>ID</th>
            <th>USER_ID</th>
        </tr>
        <tr th:each="todo : ${todos}">
            <td th:text="${todo.id}"></td>
            <td th:text="${todo.userId}"></td>
        </tr>
    </table>
</body>

</html>

Javaでindex.htmlを表示するようにする


@Controller@GetMappingを付与したJavaファイルを作成します。ファイル自体は基本的にどこにおいても大丈夫です。

今回は、src/main/java/com/example/demo/controllerディレクトリにIndexController.javaを作成しています。

ちなみに、この@XXXアノテーションと言います。

// 自動でimportされていなければ、手入力してください。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller // HTMLとのやり取りをするためのアノテーション
public class IndexController {
    @GetMapping("/") // パラメータでURLを指定します。
    public String index() {
        return "index"; // src/main/resources/templates配下のindex.htmlにマッピングします
    }
}

起動確認


一旦、ここで起動確認してください。

ここまでうまく作成できていれば、今まではエラー画面だったのが、今回作ったhtmlファイルを表示できます。

./gradlew bootRun

または、git pushしてHerokuを確認する。

f:id:nainaistar:20201123164301p:plain

JavaからHTMLにパラメータを渡す(単純なString)


パラメータにModelを追加してください。このModelに値を設定すると、Springがいい感じにマッピングしてくれて画面に表示されます。

今回は、index.htmlに${message}という項目を作成しました。Javaもこのmessageに対して値を設定すると画面に表示されます。

@Controller
public class IndexController {
    @GetMapping("/")
    public String index(Model model) { // Modelを追加
        model.addAttribute("message", "きり丸さんこんにちは"); // message
        return "index";
    }
}

f:id:nainaistar:20201123164319p:plain

JavaからHTMLにパラメータを渡す(DTO


TODOアプリですので、TODOに関するクラスを作成します。

まだ何が必要かわからないので、iduserIdの項目を持たせるようにしましょう。また、lombokという便利なライブラリがあるので、@Data@Builderをクラスに付与します。

クラス名はなんでもいいですが、私はControllerが使うクラスはDtoと名付けることが多いです。DTOはData transfer Objectの略称で、データ転送用のクラスです。

@Data // lombokの便利なもの(setter, getterを自動作成してくれる)
@Builder // lombokのBuilderパターンを作れるようになります。
public class TodoDto {
    int id;
    String userId;
}

また、TODOアプリですので、複数のTODOを渡したほうがいいでしょう。Thymeleaf側にも、複数のTODOデータをもらう前提で作りました。

挙動としてはJavaから受け取った${todos}を変数todoに設定し、変数に含まれているiduserIdを取得しています。

<tr th:each="todo : ${todos}"> 
    <td th:text="${todo.id}"></td>
    <td th:text="${todo.userId}"></td>
</tr>

Javaは単純にList<TodoDto>をmodelに設定しています。

import java.util.List;

@Controller
public class IndexController {
    @GetMapping("/")
    public String index(Model model) {
        // Listで複数のTODOを用意する
        List<TodoDto> todos = List.of(TodoDto.builder().id(1).userId("kirimaru").build(),
                TodoDto.builder().id(2).userId("kirimaru").build());

        model.addAttribute("message", "きり丸さんこんにちは");
        model.addAttribute("todos", todos); // todosを設定する。
        return "index";
    }
}

うまく設定できていれば、画面がこのように表示されています。

f:id:nainaistar:20201123164333p:plain

ついでにうまくいかないパターンを試す


Thymeleaf側はgetterを準備していないとパラメータを取得できません。

今回はTodoDtoクラスに@Dataを付与していたので、うまく動きました。

この@Dataをコメントにして、起動確認をしてみましょう。うまく動かないことが分かります。エラーメッセージからはtodo.idが悪いことは分かるのですが…。Javaが悪いのか、HTMLが悪いのかを切り分けられないので、私にThymeleafは難しいです。

f:id:nainaistar:20201123164347p:plain

ソースコード

アドベントカレンダー6日目。
github.com

終わりに

まだおおがかりではないものの、JavaとHTMLを接続できました。ただ、今回のはJava -> HTMLの一方通行のみです。保存していたデータを表示することしかできません。

画面で編集したデータを更新するためには、HTML -> Javaの接続ができなければなりません。

アドベントカレンダー7日目はHTML -> Javaの接続を行います。

ぜひお楽しみに!


この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。

参考記事

Thymeleaf公式ドキュメント www.thymeleaf.org

類似記事

きり丸アドベントカレンダー2020 adventar.org

きり丸のHerokuページ
https://kirimaru-todoapp.herokuapp.com/

7日目のアドベントカレンダーの記事 https://nainaistar.hatenablog.com/entry/2020/12/07/083000nainaistar.hatenablog.com

f:id:nainaistar:20201109133010p:plain