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>

我做了几个测试。 &lt;h:outputText value="#requestHeader[k]" /&gt;c:forEach 可以在其他列表中使用。

为什么不能这样工作?

【问题讨论】:

【参考方案1】:

像 JSTL 标签这样的标签处理程序在视图构建时运行,而像 JSF &lt;h:xxx&gt; 标签这样的 UI 组件在视图渲染时运行。因此它们不会像您对编码所期望的那样同步运行。在您的代码中,在&lt;c:forEach&gt; 运行的那一刻,&lt;h:dataTable&gt; 根本没有运行,因此它的var 属性未设置,因此#k&lt;c:forEach&gt; 运行时不可用,因此它检索一个空的/不存在的集合。

如果您想在另一个 UI 组件中嵌套迭代,则需要一个 UI 组件。其中之一是 Facelets &lt;ui:repeat&gt;

<ui:repeat value="#requestHeader[k]" var="v">
    <h:outputText value="#v" /><br />
</ui:repeat>

如果您仍在使用 JSF 1.x,请改用 Tomahawk 的 &lt;t:dataList&gt;,或直接使用另一个 &lt;h:dataTable&gt;

另见:

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 timeview render time。我在 JSF 生命周期中找不到这些术语。它们是否对应于 Restore View PhaseRender Response Phase?现在不相关了: 2.a) 由于header EL 对象是Map&lt;String, String&gt;,我根本不需要&lt;ui:repeat&gt;,对吧? 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> 需要帮助

使用 c:foreach (JSP/JSTL) 遍历 ArrayList,变量不起作用

jstl c:forEach

JSTL--JSTL表达式:c:forEach,varstatus/begin end/循环控制标签--drp215