3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

thymeleaf + SpringでJavaの定数やEnum、Staticメソッドを使いたくなったときの対処法

Last updated at Posted at 2022-12-22

はじめに

以前に書いた記事の続編です。

「thymeleaf enum」「thymeleaf constant」で検索すると、 T(my.package.MyEnum).MONDAY, ${T(com.baeldung.thymeleaf.model.Color).values()}, T(com.example.Constants).MIN_VALUE といった、thymeleafから直接呼び出すような形の記事がでてくることが多いです。

では、この使い方が公式ドキュメントにあるものかというと、そうではないです。
T( で検索をかけても、上記の使い方に対応するものはヒットしないです。

この書き方は、特に考えずにすぐ動くものができるので、一見良さそうですが、保守性や可読性からみると良いといえないです。このやり方に頼らない、別の方法をまとめるのがこの記事の趣旨です。

結論

  • controllerのメソッド内でmodelAndViewにわたす
  • controllerでModelAttributeを定義する
  • Beanに登録する
  • インスタンスメソッドに委譲し、テンプレートでそれを呼び出す

T(com.example.Constants)のやり方の問題点

このやり方は、パッケージ構成やクラス名の変更が、テンプレート側にも影響してしまいます。
IDEのリファクタリング機能では、テンプレートの方までは変えてくれないので、安全にリファクタリングできなくなってしまいます。
テンプレートエンジンの基本は、「テンプレート内の変数に代入」です。テンプレートから直接アプリのコードを呼び出すのは、アプリとテンプレートを結合度を不要に高めてしまいます。

サンプルコード

UserStatus.java
public enum UserStatus {
    ACTIVE("有効"),
    INACTIVE("無効"),
    PENDING("保留");

    private final String viewName;

    ... 
}

UserConstants.java

public class UserConstants {

  public static final int MAX_PAGE_SIZE = 100;

  public static final int MIN_PAGE_SIZE = 10;

}

controllerのメソッド内でmodelAndViewにわたす

一番オーソドックスなやり方です。

enumの要素をfor-eachする場合は、Enum#values()をModelに渡します。
定数についても同様です。

UserController
@Controller
public class UserController {

   // 更新画面の表示
   // ステータスのセレクトボックスを表示
   public String updateView(ModelAndView model, UserUpdateForm form) {
        ...
        model.addAttribute("statusList", UserStatus.values());
        model.addAttribute("maxPageSize", UserConstants.MAX_PAGE_SIZE);
        ... 
   }

}

user_edit.html
<select name="status">
    <option th:each="status : statusList}" 
            th:value="${status}" th:text="${status.viewName}">
    </option>
</select>

<div th:text=${maxPageSize}>

controllerでModelAttributeを定義する

ひとつのcontroller内で扱う複数の画面で、使われる場合です。
@ModelAttributeは、controller内の各メソッドが呼び出される前に実行されます。
テンプレートでの使い方は通常どおりです。

UserController.java
@Controller
public class UserController {

  @ModelAttribute("activeStatus")
  public UserStatus active() {
       return UserStatus.ACTIVE;
  }

  ...

}
user_create.html
<input name="status" th:value="${activeStatus}" th:text="${activeStatus.viewName}">

Beanに登録する

複数のcontrollerが扱う画面で使う場合です。それぞれのcontrollerで@ModelAttributeを使う手もありますが、@Bean を使えば一箇所ですみます。
テンプレートでの使い方も、通常どおりです。

Configs.java
@Configuration
public class Configs {

  @Bean("userActiveStatus")
  public UserStatus activeStatus() {
      return UserStatus.ACTIVE;
  }
}
view.html
<input name="status" th:value="${userActiveStatus}" th:text="${userActiveStatus.viewName}">

インスタンスメソッドに委譲し、テンプレートでそれを呼び出す

冒頭にあげた、よくないやり方をつかえば、テンプレートからstaticメソッドを呼び出すこともできます。

User.java
public class User {

  private final String name;

  ...
}
UserUtil.java
public class UserUtil {

  public static String formatName(String name) {...}

}
<p th:text="${T(com.sample.UserUtil.formatName(user.name))}">

こういった場合は、インスタンスメソッドに移せば簡単に解決します。

User.java
public class User {
 
   private final String name;

   ...

   public final String getFormatedName() {
       // UserUtil#formatNameの中身を移す
       ...
   }
}

このように書き直せます。

<p th:text="${user.formatedName}">

まとめ

ModelAttribute,Beanや、controllerとテンプレートのやりとりの部分は、Springの知識が必要ですが、それ以外は、テンプレートエンジンの一般的な使い方と、thymeleafでの基本的な記法でできます。
上手にthymeleafと付き合っていきましょう。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?