6反復
現在、ホームページ、ユーザープロフィールページ、およびユーザーがニュースレターを購読できるページについて説明しましたが、製品についてはどうですか? これを行うには、コレクション内の要素を反復処理する方法が必要です。
6.1反復の基本
/WEB-INF/templates/product/list.htmlページに製品を表示するには、テーブルを使用します。 各製品は行(要素<td>)に表示されるため、そのような行を作成し、Thymeleafに各製品に対して1回繰り返すように指示します。
標準の方言は特別な属性th:eachを提供します。
thを使用:それぞれ
製品リストページには、サービスレベルから製品のリストを抽出し、テンプレートコンテキストに追加するコントローラーメソッドが必要です。
public void process( final HttpServletRequest request, final HttpServletResponse response, final ServletContext servletContext, final ITemplateEngine templateEngine) throws Exception { ProductService productService = new ProductService(); List<Product> allProducts = productService.findAll(); WebContext ctx = new WebContext(request, response, servletContext, request.getLocale()); ctx.setVariable("prods", allProducts); templateEngine.process("product/list", ctx, response.getWriter()); }
次に、テンプレートのth:を使用して、製品のリストを反復処理します。
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Good Thymes Virtual Grocery</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" type="text/css" media="all" href="../../../css/gtvg.css" th:href="@{/css/gtvg.css}" /> </head> <body> <h1>Product list</h1> <table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOCK</th> </tr> <tr th:each="prod : ${prods}"> <td th:text="${prod.name}">Onions</td> <td th:text="${prod.price}">2.41</td> <td th:text="${prod.inStock}? #{true} : #{false}">yes</td> </tr> </table> <p> <a href="../home.html" th:href="@{/}">Return to home</a> </p> </body> </html>
上記のprod:$ {prods}属性は 、「各要素について、結果は$ {prods}であり 、prodという変数の現在の要素を使用してこのテンプレートフラグメントを繰り返す」ことを意味します。 表示される各項目に名前を付けましょう。
- $ {prods}を反復式または反復変数と呼びます
- prodを反復変数または単にiter変数と呼びます
- prod変数は<td>要素にバインドされているため、<td>などの内部タグで使用できることに注意してください。
反復可能な値
Thymeleafを反復処理するために使用できるのは、java.util.Listクラスだけではありません。 th:各属性に適したかなり大きなオブジェクトのセットがあります:
- java.util.Iterableを実装するオブジェクト
- java.util.Enumerationを実装するオブジェクト
- すべての値をメモリにキャッシュする必要なく、イテレータによって返される値が使用されるjava.util.Iteratorを実装するオブジェクト
- java.util.Mapを実装するオブジェクト。 マップを反復するとき、反復変数はクラスjava.util.Map.Entryを持ちます。
- 任意の配列
- 他のオブジェクトは、オブジェクト自体を含む単一値のリストであるかのように処理されます
6.2反復ステータスの保存
th:eachを使用する場合、Thymeleafは、反復の状態を追跡するのに役立つメカニズム(状態変数)を提供します。
状態変数はth:各属性内で定義され、次のデータが含まれます。
- 0から始まる現在の反復インデックス。これはインデックスプロパティです
- 1から始まる現在の反復インデックス。これはcountプロパティです。
- 反復変数内の要素の総数。 これはサイズプロパティです
- 各反復のiter変数。 これは現在のプロパティです。
- 現在の反復が偶数か奇数か。 これらは偶数/奇数のブールプロパティです
- 現在の反復が最初です。 これは最初のブール型プロパティです
- 現在の反復は最後です。 これは最後のブール型プロパティです
反復プロパティを使用する方法を見てみましょう。
<table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOCK</th> </tr> <tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'"> <td th:text="${prod.name}">Onions</td> <td th:text="${prod.price}">2.41</td> <td th:text="${prod.inStock}? #{true} : #{false}">yes</td> </tr> </table>
状態変数(この例ではiterStat )はth:で定義されています。各属性は、カンマで区切られたiter変数自体の後に名前を書き込みます。 反復変数と同様に、ステータス変数はth:各属性を含むタグで定義されたコードにバインドされます。
テンプレートを処理した結果を見てみましょう:
<!DOCTYPE html> <html> <head> <title>Good Thymes Virtual Grocery</title> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/> <link rel="stylesheet" type="text/css" media="all" href="/gtvg/css/gtvg.css" /> </head> <body> <h1>Product list</h1> <table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOCK</th> </tr> <tr class="odd"> <td>Fresh Sweet Basil</td> <td>4.99</td> <td>yes</td> </tr> <tr> <td>Italian Tomato</td> <td>1.25</td> <td>no</td> </tr> <tr class="odd"> <td>Yellow Bell Pepper</td> <td>2.50</td> <td>yes</td> </tr> <tr> <td>Old Cheddar</td> <td>18.75</td> <td>yes</td> </tr> </table> <p> <a href="/gtvg/" shape="rect">Return to home</a> </p> </body> </html>
反復ステータス変数は正常に機能し、奇数行にのみ奇数CSSクラスを設定することに注意してください。
明示的にステータス変数を設定しない限り、Thymeleafは常に反復変数の名前にStatを付加することで、自動的にステータス変数を作成します。
<table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOCK</th> </tr> <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'"> <td th:text="${prod.name}">Onions</td> <td th:text="${prod.price}">2.41</td> <td th:text="${prod.inStock}? #{true} : #{false}">yes</td> </tr> </table>
6.3遅延データマイニングによる最適化
これらのコレクションが実際に使用されている場合にのみ取得されるように、データコレクションのクロールを最適化する必要がある場合があります(たとえば、データベースから)。
実際、これは任意のデータに適用できるものですが、コレクションがメモリ内に保持できるサイズを考えると、繰り返しを目的としたコレクションの取得がこのシナリオの最も一般的なケースです。
このメカニズムをサポートするために、Thymeleafはコンテキスト変数を遅延ロードするためのツールを提供しています。 ILazyContextVariableインターフェイスを実装するコンテキスト変数は、デフォルトの実装であるLazyContextVariableを拡張する可能性が高く、実行時に許可されます。 例:
context.setVariable( "users", new LazyContextVariable<List<User>>() { @Override protected List<User> loadValue() { return databaseRepository.findAllUsers(); } });
この変数は、遅延があるかどうかを知らなくても使用できます。次に例を示します。
<ul> <li th:each="u : ${users}" th:text="${u.name}">user name</li> </ul>
ただし、コードで条件がfalseと評価された場合、同時に初期化されることはありません(loadValue()メソッドが呼び出されることはありません)。
<ul th:if="${condition}"> <li th:each="u : ${users}" th:text="${u.name}">user name</li> </ul>