这个帖子有点旧,但我没有看到任何更新的帖子。它可以用正确的秘方来完成。
在Java代码中,你必须做三件事:
- 使用@javax.transaction.Transactional 注释
- 手动调用 Thymeleaf 处理模板
- 在模板处理中使用 try-with-resources 块来保证流已关闭
在您的模板中,如果您传递 Stream 的迭代器,您不必做任何不同的事情,因为 Thyemeleaf 已经了解迭代器。
从 Spring Data 返回流时需要 @Transactional 注解。关键是带注释的方法必须在流结束之前实际使用流 - 使用 Thyemleaf 不会发生这种情况,方法只是返回字符串模板名称的“正常”方式。
同时,流已关闭(当您使用流来执行诸如将列表转换为地图之类的操作时,您不必这样做)。通过自己控制模板生成过程,您可以确保在您的 @Transactional 方法中关闭和使用流。
Java 代码如下所示(我使用的是 Spring 5 MVC):
@Controller
public class CustomerController {
@Autowired
SpringTemplateEngine templateEngine;
@Autowired
private CustomerRepository customerRepository;
@RequestMapping("/customers")
@Transactional
public void customers(
final String firstName,
final HttpServletRequest request,
final HttpServletResponse response
) throws IOException {
final WebContext ctx = new WebContext(
request,
response,
request.getServletContext(),
request.getLocale()
);
try (
final Stream<CustomerModelEntity> models =
(firstName == null) || firstName.isEmpty() ?
customerRepository.findAll() :
customerRepository.findByFirstNameIgnoringCaseOrderByLastNameAscFirstNameAsc(firstName)
) {
ctx.setVariable(
"customers",
models.iterator()
);
response.setContentType("text/html");
templateEngine.process(
"customer-search",
ctx,
response.getWriter()
);
}
}
}
Thymeleaf 模板如下(我使用的是解耦逻辑):
<?xml version="1.0"?>
<thlogic>
<attr sel=".results" th:remove="all-but-first">
<attr sel="/.row[0]" th:each="customer : ${customers}">
<attr sel=".first-name" th:text="${customer.firstName}" />
<attr sel=".middle-name" th:text="${customer.middleName}" />
<attr sel=".last-name" th:text="${customer.lastName}" />
</attr>
</attr>
</thlogic>