我有以下模板(masterLayout.xhtml):

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <f:view contentType="text/html">
        <ui:insert name="metadata"/>
        <h:head>
            <title><ui:insert name="windowTitle"/> | MySite</title>
        </h:head>

        <h:body>
            <div id="container">
                <div id="header">
                    <ui:insert name="header">
                        <ui:include src="/WEB-INF/templates/header.xhtml"/>
                    </ui:insert>
                </div>
                <div id="content">
                    <ui:insert name="content"/>
                </div>
                <div id="footer">
                    <ui:insert name="footer">
                        <ui:include src="/WEB-INF/templates/footer.xhtml"/>
                    </ui:insert>
                </div>
            </div>
        </h:body>
    </f:view>
</html>

以及使用它的页面(search.xhtml):
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <title></title>
    </h:head>
    <h:body>
        <ui:composition template="/WEB-INF/templates/masterLayout.xhtml">
            <ui:define name="metadata">
                <f:metadata>
                    <f:viewParam name="address" value="#{searchBean.address}"/>
                    <f:event type="preRenderView" listener="#{userSessionBean.preRenderViewCookieLogin(e)}"/>
                    <f:event type="preRenderView" listener="#{searchBean.preRenderView(e)}"/>
                </f:metadata>
            </ui:define>
            <ui:define name="windowTitle">#{searchBean.address}</ui:define>

            <ui:define name="content">

                <!-- Content goes here -->

            </ui:define>
        </ui:composition>
    </h:body>
</html>

问题是我想在模板中放置对userSessionBean.preRenderViewCookieLogin(e)的调用,因为还有许多其他页面。此方法检查用户是否已登录(根据 session 状态),如果没有,则检查可用于登录用户的cookie,如果可以,则自动登录用户(如果有效)。 。系统可以在上面的代码中运行,但是当我尝试将其插入模板时,不再设置我的 View 参数。

这是上述内容的修改后的版本,其中userSessionBean.preRenderViewCookieLogin(e)推送至模板。

masterLayout.xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <f:view contentType="text/html">
        <f:metadata>
            <f:event type="preRenderView" listener="#{userSessionBean.preRenderViewCookieLogin(e)}"/>
            <ui:insert name="metadata"/>
        </f:metadata>
        <h:head>
            <title><ui:insert name="windowTitle"/> | MySite</title>
        </h:head>

        <h:body>
            <div id="container">
                <div id="header">
                    <ui:insert name="header">
                        <ui:include src="/WEB-INF/templates/header.xhtml"/>
                    </ui:insert>
                </div>
                <div id="content">
                    <ui:insert name="content"/>
                </div>
                <div id="footer">
                    <ui:insert name="footer">
                        <ui:include src="/WEB-INF/templates/footer.xhtml"/>
                    </ui:insert>
                </div>
            </div>
        </h:body>
    </f:view>
</html>

search.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <title></title>
    </h:head>
    <h:body>
        <ui:composition template="/WEB-INF/templates/masterLayout.xhtml">
            <ui:define name="metadata">
                <f:viewParam name="address" value="#{searchBean.address}"/>
                <f:event type="preRenderView" listener="#{searchBean.preRenderView(e)}"/>
            </ui:define>
            <ui:define name="windowTitle">#{searchBean.address}</ui:define>

            <ui:define name="content">

                <!-- Content goes here -->

            </ui:define>
        </ui:composition>
    </h:body>
</html>

注意,我已经将<f:metadata/>标记移到了模板上。这就是问题所在,因为删除userSessionBean.preRenderViewCookieLogin(e)没什么区别。我还尝试了有效代码的变体,即仅将userSessionBean.preRenderViewCookieLogin(e)移入模板,这意味着它不能位于<f:metadata/>标记内。在这种情况下,将在设置所有 View 参数并调用searchBean.preRenderView(e)之后执行该方法。我希望在调用任何页面的userSessionBean.preRenderViewCookieLogin(e)之前而不是之后调用preRenderView(e)。只是为了好玩,我尝试在<f:metadata/>周围放置一个userSessionBean.preRenderViewCookieLogin(e),它调用了此方法,但是没有设置 View 参数。

因此,我想知道:
  • 为什么会发生这种情况,并且有办法解决?
  • 是否有更好的方法来确保对每个页面先调用相同的方法?

  • 编辑:
    我只是尝试了其他东西-阶段事件:<f:view contentType="text/html" beforePhase="#{userSessionBean.beforePhase(e)}">这是在masterLayout.xhtml中。它根本没有被调用;没有任何阶段。

    编辑:
    删除了e(该死的NetBeans!):<f:view contentType="text/html" beforePhase="#{userSessionBean.beforePhase}">这仅在渲染响应阶段之前调用,这当然意味着在preRenderView事件引发之后调用它。

    最佳答案


    <f:metadata> tag documentation(第二段的重点是我的):

    因此,它实际上必须放在顶 View 中,而不是模板中。


    在您的特定情况下,将登录的用户存储为 session 范围内的受管Bean的属性而不是cookie,并在适当的URL模式上使用filter进行检查。 session 范围内的受管Bean在过滤器中可以作为HttpSession属性使用。本地化的cookie是不必要的,因为您基本上是在这里重新发明HttpSession。除非您想要“记住我”的设施,否则不应以这种方式解决此问题。还要在过滤器中进行过滤。
    也可以看看:

  • Prevent accessing restricted page without login in Jsf2
  • 10-06 07:35