JSTL c:forEach循环end属性绑定EL表达式计算值仅执行一次问题
问题根因
- JSTL标准函数库中的
fn:replace仅支持普通字符串替换,不支持正则表达式语法,你写的${fn:replace(data, '[^,]', '')}无法实现“删除所有非逗号字符”的效果,得到的count变量并非预期的仅含逗号的字符串,fn:length(count)的结果不符合预期。 - 部分JSTL版本中,动态计算的数值如果没有显式声明为整数类型,
c:forEach的end属性会将其识别为字符串类型,导致解析错误、循环次数异常。
解决方案
这里提供两种可行方案,优先推荐第一种:
方案1:直接遍历拆分后的数组(最优,无边界计算问题)
你已经用fn:split将字符串拆分为了数组,直接遍历数组即可,无需手动计算循环边界:
<b:dataTableColumn label="Misc. Documents: " > <c:set var="data" value="#{item.miscDocs}"/> <c:set var="splitPart" value="${fn:split(data, ',')}"/> <c:forEach items="${splitPart}" var="docPart"> <a href="/homekey/${docPart}">${fn:replace(docPart, '%20', ' ')}</a><br/> </c:forEach> </b:dataTableColumn>
该写法天然适配拆分后的元素数量,不会出现越界、循环次数不对的问题。
方案2:修正逗号计数逻辑并显式转换数值类型
如果你需要保留索引遍历的写法,按如下步骤修改:
- 用字符串长度差的方式计算逗号数量,该方法不需要正则,兼容所有JSTL版本
- 显式将计数结果转为整数类型,避免
end属性识别异常
修改后的代码如下:
<!-- 需先引入fmt标签库,放在页面顶部 --> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <b:dataTableColumn label="Misc. Documents: " > <c:set var="data" value="#{item.miscDocs}"/> <c:set var="splitPart" value="${fn:split(data, ',')}"/> <!-- 用原字符串长度减去删除所有逗号后的字符串长度,得到逗号数量 --> <c:set var="commaCount" value="${fn:length(data) - fn:length(fn:replace(data, ',', ''))}"/> <!-- 显式转为整数 --> <fmt:parseNumber var="max" value="${commaCount}" integerOnly="true" /> <c:forEach var = "i" begin = "0" end = "${max}"> <a href="/homekey/${splitPart[i]}">${fn:replace(splitPart[i], '%20', ' ')}</a><br/> </c:forEach> </b:dataTableColumn>
内容的提问来源于stack exchange,提问作者Zack T.
相关产品推荐
相关产品推荐

