六、Iteration
到目前为止,我们已经创建了一个主页,一个用户 Profile 页面以及一个允许用户订阅我们的新闻通讯的页面……但是我们的产品呢?为此,我们将需要一种方法来遍历集合中的项目以构建我们的产品页面。
6.1 迭代基础
要在我们的/WEB-INF/templates/product/list.html
页面上显示产品,我们将使用一个表格。我们的每种产品都将显示在一行中(一个<tr>
元素),因此对于我们的模板,我们需要创建一个* template row (模板行),该行将举例说明我们希望每种产品的展示方式,然后指示 Thymeleaf 对每个产品重复一次。
标准方言为我们提供了一个确切的属性:th:each
。
Using 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>
您在上面看到的prod : ${prods}
属性值的意思是“对于评估${prods}
的结果中的每个元素,使用名为 prod 的变量中的当前元素,重复此模板片段。”让我们给每一个看到的事物命名:
- 我们将
${prods}
称为迭代表达式或迭代变量。 - 我们将
prod
称为迭代变量或简称为* iter 变量*。
请注意,prod
iter 变量的作用域为<tr>
元素,这意味着它可用于<td>
之类的内部标记。
Iterable values
java.util.List
类不是 Thymeleaf 中唯一可用于迭代的值。有相当完整的一组对象,它们被th:each
属性视为“可迭代”:
- 任何实现
java.util.Iterable
的对象 - 任何实现
java.util.Enumeration
的对象。 - 实现
java.util.Iterator
的任何对象,其值将由迭代器返回,而无需在内存中缓存所有值。 - 任何实现
java.util.Map
的对象。迭代 Map 时,迭代变量将属于java.util.Map.Entry
类。 - Any array.
- 任何其他对象都将被视为包含该对象本身的单值列表。
6.2 保持迭代状态
使用th:each
时,Thymeleaf 提供了一种用于跟踪迭代状态的有用机制:* status variable *。
状态变量在th:each
属性中定义,并包含以下数据:
- 当前的迭代索引,从 0 开始。这是
index
属性。 - 从 1 开始的当前* iteration index *。这是
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 变量一样,status 变量的范围也由持有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
后缀来为您创建一个状态变量:
<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 通过延迟检索数据进行优化
有时我们可能想优化数据集合的检索(例如从数据库中),以便仅在 true 要使用它们的情况下才检索这些集合。
实际上,这可以应用于任何数据段,但是鉴于内存中集合可能具有的大小,在这种情况下,检索要迭代的集合是最常见的情况。
为了支持这一点,Thymeleaf 提供了一种延迟加载上下文变量的机制。实现ILazyContextVariable
接口的上下文变量(很可能是通过扩展其LazyContextVariable
默认实现)将在执行时立即解决。例如:
context.setVariable(
"users",
new LazyContextVariable<List<User>>() {
@Override
protected List<User> loadValue() {
return databaseRepository.findAllUsers();
}
});
在不了解其* lazyness *的情况下,可以在以下代码中使用此变量:
<ul>
<li th:each="u : ${users}" th:text="${u.name}">user name</li>
</ul>
但同时,如果condition
在以下代码中的值为false
,则将永远不会初始化(永远不会调用其loadValue()
方法):
<ul th:if="${condition}">
<li th:each="u : ${users}" th:text="${u.name}">user name</li>
</ul>
最新评论
Spring Cloud Alibaba 微服务架构实战 https://pan.baidu.com/s/1jF5voFRoeF0lYAzAPBWSbw?pwd=chqk
命令: nload
真是个良心站点哇,大公无私,爱了爱了
还可以直接搞一张映射表,存 uid | time | source_index, 第一次直接查对应的 time 选出前100, 第二次直接用 CompleteFuture 去分别用 source_in
干得漂亮,多个朋友堵条路
2021.2.2版本的不适用吧
现在还可以用么
激活码有用,感谢分享