迭代
1、迭代基础
要在/WEB-INF/templates/product/list.html
页面中显示产品,将使用一个表格。都将显示在一行(一个<tr>
元素),所以对于我们的模板,我们将需要创建一个模板行 - 一个将举例说明我们希望如何显示每个产品 - 然后指示Thymeleaf重复它,每个产品一次。
标准方言为我们提供了一个属性:th:each
。
对于列表页面,我们将需要一个控制器方法,从服务层检索产品列表并将其添加到模板上下文中:
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:each
遍历产品列表:
<!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>
可重复的值
这个java.util.List
类不是唯一可用于Thymeleaf迭代的值。有一个相当完整的一组对象被认为可以被一个属性迭代th:each
:
- 任何对象的实现
java.util.Iterable
- 任何对象的实现
java.util.Enumeration
。 - 任何实现的对象
java.util.Iterator
,其值将被迭代器返回使用,而不需要缓存内存中的所有值。 - 任何对象的实现
java.util.Map
。当迭代映射时,iter变量将是类的java.util.Map.Entry
。 - 任何数组。
- 任何其他对象将被视为包含对象本身的单值列表
2、保持迭代状态
使用时th:each
,Thymeleaf提供了一个有用的机制来跟踪你的迭代状态:状态变量。
状态变量在一个th:each
属性中定义并包含以下数据:
- 当前迭代索引,从0开始。这是
index
属性。 - 当前迭代索引,从1开始。这是
count
属性。 - 迭代变量中的元素总数。这是
size
财产。 - 每个迭代的iter变量。这是
current
财产。 - 目前的迭代是偶数还是奇数。这些是
even/odd
布尔属性。 - 目前的迭代是否是第一个。这是
first
布尔属性。 - 目前的迭代是否是最后一个。这是
last
布尔属性。
让我们看看我们如何使用它与前面的例子:
<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:each
通过在iter变量本身之后写入名称来定义的,用逗号分隔。就像iter变量一样,状态变量的范围也是由持有th:each
属性的标签定义的代码片段。
让我们来看看处理我们的模板的结果:
<!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>
请注意,我们的迭代状态变量已经完美工作,只建立odd
奇数行的CSS类。
如果你没有明确地设置一个状态变量,Thymeleaf将总是为你添加一个Stat
迭代变量的名字后缀:
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>
但是同时,loadValue()
如果condition
评估false
的代码如下:将永远不会被初始化(它的方法永远不会被调用):
<ul th:if="${condition}"> <li th:each="u : ${users}" th:text="${u.name}">user name</li> </ul>