Spring Thymeleaf中state.last在FindIterable遍历中抛异常的原因
问题原因及解决方案
这问题我之前做MongoDB+Thymeleaf项目时也踩过坑,核心原因和MongoDB的FindIterable特性直接相关:
为什么state.first正常,state.last报错?
FindIterable是MongoDB提供的惰性加载迭代器,它不会一次性把所有查询结果加载到内存,而是每次迭代时才从数据库取一条数据。
Thymeleaf的state.last属性需要知道整个集合的总元素数量,才能判断当前迭代的元素是不是最后一个。但惰性迭代器的特性决定了它无法提前获取总长度——它甚至不知道后续还有没有元素,除非把所有元素都遍历完,但这时候已经没法在当前迭代步骤中判断了。
而state.first就简单多了:它只需要记录当前是不是第一次迭代,不需要知道集合的总长度或者后续元素,所以完全能正常工作。
解决方案
有两种常用的解决办法,根据你的数据量选择:
1. 转换为普通List集合(推荐,数据量不大时)
在Java代码里把FindIterable转换成普通的List,这样Thymeleaf就能获取集合的总长度,state.last就能正常使用了:
// 原来的查询代码 FindIterable<Document> data = mongoCollection.find(); // 转换成List(需要导入java.util.ArrayList) List<Document> dataList = new ArrayList<>(data); // 将List传入Thymeleaf模板 model.addAttribute("data", dataList);
模板里的代码不需要修改,直接用state.last就没问题了。
2. 手动判断(适合大数据量,避免内存压力)
如果数据量很大,转成List会占用过多内存,可以先单独查询总记录数,然后用state.count和总数量对比来判断是不是最后一个:
// 先查询符合条件的总记录数(注意查询条件要和find一致) long totalCount = mongoCollection.countDocuments(); // 将总数量和FindIterable都传入模板 model.addAttribute("data", mongoCollection.find()); model.addAttribute("totalCount", totalCount);
模板里修改判断逻辑:
<tr th:each="document, state : ${data}"> <td th:text="${state.count}"></td> <td th:text="${state.count == totalCount}"></td> <!-- 替代state.last的判断 --> </tr>
关于异常的补充
你看到的TemplateProcessingException本质是SpringEL在尝试计算state.last时,底层调用了迭代器的相关方法,但FindIterable的惰性特性导致无法完成这个判断,最终抛出了表达式求值异常。
内容的提问来源于stack exchange,提问作者john cena
相关产品推荐
相关产品推荐

