JSTL c:forEach 在 JSF h:dataTable 中不起作用
Posted
技术标签:
【中文标题】JSTL c:forEach 在 JSF h:dataTable 中不起作用【英文标题】:JSTL c:forEach doesn't work inside a JSF h:dataTable 【发布时间】:2012-08-15 08:07:30 【问题描述】:我的 JSF 项目有问题。
GlassFish 服务器 3.1.2 Mojarra 2.1.6我正在尝试显示一个包含请求标头字段的表格。为此,我编写了这个托管 bean:
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
@ManagedBean
@RequestScoped
public class RequestHeader extends LinkedHashMap<String, List<String>>
private List<String> keys;
@PostConstruct
public void init()
final HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
keys = Collections.list(request.getHeaderNames());
for (final String key : keys)
final List<String> value = Collections.list(request.getHeaders(key));
final List<String> oldValue = get(key);
if (oldValue == null)
put(key, value);
else
oldValue.addAll(value);
public List<String> keys()
return keys;
这是我的 JSF 页面:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>HTTP request headers</title>
</h:head>
<h:body>
<h:dataTable value="#requestHeader.keys()" var="k" border="1">
<f:facet name="header">HTTP request headers</f:facet>
<h:column>
<f:facet name="header">Key</f:facet>
<h:outputText value="#k" />
</h:column>
<h:column>
<f:facet name="header">Value</f:facet>
<!-- This forEach seems to be ignored. -->
<c:forEach items="#requestHeader[k]" var="v">
<h:outputText value="#v" /><br />
</c:forEach>
</h:column>
</h:dataTable>
</h:body>
</html>
表格的第二列中没有值,而是单元格为空:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTTP request headers</title>
</head>
<body>
<table border="1">
<thead>
<tr><th colspan="2" scope="colgroup">HTTP request headers</th></tr>
<tr>
<th scope="col">Key</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>user-agent</td>
<td></td>
</tr>
<tr>
<td>host</td>
<td></td>
</tr>
<tr>
<td>accept</td>
<td></td>
</tr>
<tr>
<td>accept-language</td>
<td></td>
</tr>
<tr>
<td>accept-encoding</td>
<td></td>
</tr>
<tr>
<td>cache-control</td>
<td></td>
</tr>
<tr>
<td>connection</td>
<td></td>
</tr>
</tbody>
</table>
</body>
</html>
我做了几个测试。 <h:outputText value="#requestHeader[k]" />
和 c:forEach
可以在其他列表中使用。
为什么不能这样工作?
【问题讨论】:
【参考方案1】:像 JSTL 标签这样的标签处理程序在视图构建时运行,而像 JSF <h:xxx>
标签这样的 UI 组件在视图渲染时运行。因此它们不会像您对编码所期望的那样同步运行。在您的代码中,在<c:forEach>
运行的那一刻,<h:dataTable>
根本没有运行,因此它的var
属性未设置,因此#k
在<c:forEach>
运行时不可用,因此它检索一个空的/不存在的集合。
如果您想在另一个 UI 组件中嵌套迭代,则需要一个 UI 组件。其中之一是 Facelets <ui:repeat>
。
<ui:repeat value="#requestHeader[k]" var="v">
<h:outputText value="#v" /><br />
</ui:repeat>
如果您仍在使用 JSF 1.x,请改用 Tomahawk 的 <t:dataList>
,或直接使用另一个 <h:dataTable>
。
另见:
JSTL in JSF2 Facelets... makes sense? JSTL c:if doesn't work inside a JSF h:dataTable与具体问题无关:您根本不需要支持 bean。所有请求标头已经作为隐式 EL 对象 #header
可用的 Map
。
总而言之,您的方法可以简化如下,没有任何支持 bean:
<h:dataTable value="#header.keySet().toArray()" var="headerName" border="1">
<f:facet name="header">HTTP request headers</f:facet>
<h:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#headerName" />
</h:column>
<h:column>
<f:facet name="header">Value</f:facet>
<ui:repeat value="#header[headerName]" var="headerValue">
<h:outputText value="#headerValue" /><br />
</ui:repeat>
</h:column>
</h:dataTable>
另见:
Implicit EL objects【讨论】:
哦,典型的 JSF 初学者的错误。这导致了一些新问题:1) 你提到了view build time 和view render time。我在 JSF 生命周期中找不到这些术语。它们是否对应于 Restore View Phase 和 Render Response Phase?现在不相关了: 2.a) 由于header
EL 对象是Map<String, String>
,我根本不需要<ui:repeat>
,对吧? 2.b) 在HttpServletRequest
中,一个头域名称映射到多个值(而header
映射到一个值)。什么时候会有多个值?似乎最后一个具有相同名称的标题字段将“获胜”。
糟糕,#header.keySet()
会炸毁一切:java.lang.IllegalAccessException: Class javax.el.BeanELResolver can not access a member of class java.util.Collections$UnmodifiableMap with modifiers "public"
。所以我想这不会起作用,因为header
是一个 private 静态类java.util.Collections$UnmodifiableMap
,因此你不能调用它的方法?
这显然是特定于 servletcontainer 的。它在 Tomcat 7 上对我有用。无论如何,您至少已经得到了最初问题的解释和答案。【参考方案2】:
尝试使用 ui:repeat 标签代替 c:forEach。请参阅此link 了解为什么使用 ui:repeat 代替 c:forEach。
【讨论】:
以上是关于JSTL c:forEach 在 JSF h:dataTable 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
c:forEach vs ui:repeat(又名 ice:panelSeries)
JSTL--JSTL表达式:c:forEach--drp215
在 JSP/JSTL 中使用 <c:forEach> 需要帮助