Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
12
Help us understand the problem. What is going on with this article?
@n_slender

thymeleafでenumを扱うためのtips

More than 1 year has passed since last update.

今年になってSpring bootを使う案件に関わることがあり、thymeleafやenumについての得られた知見を整理してみました。

「Thymeleaf enum」でググるとよくでてくるもの

SpringやSpring bootを使うと、テンプレートエンジンでThymeleafを使うのが通例でしょう。
入力フォームのセレクトボックスの値や表示名を、enumを使って管理する、というのも、よくあることでしょう。

https://www.baeldung.com/thymeleaf-enums より抜粋ですが、ググると下記のような例がそこそこ見かけます。

<select name="color">
    <option th:each="colorOpt : ${T(com.baeldung.thymeleaf.model.Color).values()}"
        th:value="${colorOpt}" th:text="${colorOpt.displayValue}"></option>
</select>

初期値の判定などで、特定のenumかどうかを判定する場合の例として、こういうのもあります。

<div th:if="${widget.color == T(com.baeldung.thymeleaf.model.Color).RED}">

このやり方で難がある点

よく見かけるのですが、これがベストかと言われると、なんともいえないです。

  1. 型のFQDNの部分が読みづらい (長い割に情報量がない)
  2. パッケージ構成を見直そうとすると、テンプレートまで改修しなければならない
  3. enumのリネームでも、テンプレートまで改修しなければならない

要は、テンプレートとは関係ないものが入ってくるため、可読性や保守性に悪影響がでています。
とりあえず動くものを作るなら、このやり方で問題ないですが、少々つらいです。

どうするとよいか

基本的には、テンプレートで使うものをenumに実装するのがよいです。
また、テンプレートから直接呼び出すよりも、必要なインスタンスをControllerから渡す形に変えるとよいです。

enumの全要素を使う場合(セレクトボックスなど)

Javaのenumには、暗黙的なpublic static T[] values()というメソッドがあります。
全要素を列挙するには、これを利用するといいです。(定番といえば、定番ネタです。)

public enum UserStatus {
   ACTIVE(1, "有効"),
   INACTIVE(0, "無効"),
   PENDING(2, "保留"),
   FORBIDDEN(3, "強制停止")
   ;

   private final int value;

   private final String viewName;

   private UserStatus(int value, String viewName) {
       this.value = value;
       this.viewName = viewName;
   }

   public int getValue() {
       return this.value;
   }

   public String getViewName() {
       return this.viewName;
   }

}
@Controller
public class SampleController

@RequestGetMapping
public ModelAndView index() {
   ModelAndView model = new ModelAndView();
   model.setAttribute("statusList", UserStatus.values());
   return model;
}

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

フォーム入力されたものをenumとして受け取る

上のやり方では、enumとして値を受け取るには不便です。
enumには name()valueOf(String name) という、暗黙的に宣言されたメソッドがあります。

name()につけた名前が返却され、valueOf(String name) は、名前が一致したら対応するインスタンスを返すものです。Springがこれらを使って対応づけしてくれます。

<select name="status">
    <option th:each="status : statusList}" 
            th:value="${status.name()}" th:text="${status.viewName}">
    </option>
</select>
public class NewUserForm {

  private UserStatus status;

  // ... 

}
@RequestPutMapping
public ModelAndView create(NewUserForm form) {
   ModelAndView model = new ModelAndView();
   // ... 
   return model;
}

とすると、フォームで選択されたものを、enumにマッピングして受け取ることができます。

特定のenumの判定

これはenumにisXXXというメソッドを足すやり方があります。

public enum UserStatus {
   // ...

   public boolean isActive() {
       return this == ACTIVE;
   }

   public boolean isForbidden() {
       return this == FORBIDDEN;
   }

}
<div th:if="${status.isForbidden()}">
    This user is forbidden.
</div>

このisXXXメソッドは、テンプレートだけでなく、ビジネスロジックを書く場面でも有効です。
たとえば、有効なユーザだけに絞り込むなら、こんな風になります。

public class User {

  //...

  private final UserStatus status;

  public UserStatus getStatus() {
     return this.status
  }

}
   List<User> users = ...
   List<User> activeUsers = users.stream()
                                 .filter(x -> x.getStatus().isActive())
                                 .collect(Collectors.toList());

まとめ

ぐぐって、ベストプラクティスが見つかることもあれば、そうでないこともあります。
また、検索して見つかった方法が自分の現状にあっているか、その判断基準も検索してみつかることもあまりないです。
テンプレートはいろんな関心事が入りやすいので、実装するときにはいろんな判断に迫られます。

参考リンク

12
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
n_slender
一応Javaエンジニアです。仕事の関係でPHP、Python、Rubyをやることも。開発環境を構築することもあるので、そのレベルでのインフラネタもたまに。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
12
Help us understand the problem. What is going on with this article?