模板和页面中的JSF 2 facelets <f:metadata />

Dis*_*tum 9 facelets jsf-2

我有以下模板(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>
Run Code Online (Sandbox Code Playgroud)

和使用它的页面(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>
Run Code Online (Sandbox Code Playgroud)

问题是我想将调用userSessionBean.preRenderViewCookieLogin(e)放在模板中,因为还有很多其他页面.此方法检查用户是否已登录(根据会话状态),如果没有,则检查cookie是否可用,可用于记录用户,如果是,(如果有效),则自动记录用户.系统在上面的代码中工作,但是当我尝试将其推入模板时,我的视图参数不再被设置.

这是上面的修改版本,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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

请注意,我已将<f:metadata/>标记移动到模板.仅此就是问题,因为删除userSessionBean.preRenderViewCookieLogin(e)没有任何区别.我还尝试了一个有效的代码变体,只是userSessionBean.preRenderViewCookieLogin(e)进入模板,这意味着它不能在<f:metadata/>标签内.在这种情况下,在设置和searchBean.preRenderView(e)调用所有视图参数之后执行该方法.我想userSessionBean.preRenderViewCookieLogin(e)在调用任何页面之前preRenderView(e)调用,而不是之后调用.而且只是为了好玩,我尝试了一个调用此方法的<f:metadata/>around userSessionBean.preRenderViewCookieLogin(e),但没有设置视图参数.

所以,我想知道:

  1. 为什么会发生这种情况,有没有办法解决这个问题?
  2. 有没有更好的方法来确保在每个页面之前调用相同的方法?

编辑: 我刚刚尝试了其他的东西 - 阶段事件: <f:view contentType="text/html" beforePhase="#{userSessionBean.beforePhase(e)}"> 这是在masterLayout.xhtml中.根本没有被召唤; 不适合任何阶段.

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

Bal*_*usC 13

为什么会发生这种情况,有没有办法解决这个问题?

<f:metadata>标签文档(第2段的重点是我的):

声明此视图的元数据构面.这一定是孩子的<f:view>.此标记必须位于给定viewId的顶级XHTML文件中,或位于模板客户端中,但不能位于模板中.实施必须确保方面的直接子项是a UIPanel,即使该方面只有一个子项.实现必须将id的id设置UIPanelUIViewRoot.METADATA_FACET_NAME符号常量的值.

所以,它必须进入顶视图,而不是模板中.


有没有更好的方法来确保在每个页面之前调用相同的方法?

在您的特定情况下,将登录用户存储为会话范围的托管bean而不是cookie的属性,并使用适当的URL模式上的过滤器进行检查.会话范围的托管bean在过滤器中可用作HttpSession属性.本土饼干是不必要的,因为你基本上重新发明了HttpSession这里.除非你想要一个"记住我"的设施,但这不应该以这种方式解决.也可以在过滤器中进行.

也可以看看: