JSF 2 лицевыев шаблоне и странице - PullRequest
9 голосов
/ 27 сентября 2011

У меня есть следующий шаблон (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) в шаблоне, потому что есть много других страниц.Этот метод проверяет, что пользователь вошел в систему (в соответствии с состоянием сеанса), и, если нет, проверяет, доступен ли файл cookie, который можно использовать для входа в систему, и, если да (и если он действителен), автоматически регистрирует пользователя.,Система работает в коде выше, но когда я пытаюсь вставить это в шаблон, мои параметры просмотра больше не устанавливаются.

Вот модифицированная версия выше, с userSessionBean.preRenderViewCookieLogin(e), выдвинутой доtemplate.

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/>.В этом случае этот метод выполняется после того, как все параметры просмотра были установлены и вызваны searchBean.preRenderView(e).Я хочу, чтобы userSessionBean.preRenderViewCookieLogin(e) вызывался до вызова preRenderView(e) любой страницы, а не после.И просто для удовольствия я попытался поместить <f:metadata/> вокруг 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.

Ответы [ 2 ]

13 голосов
/ 27 сентября 2011

Почему это происходит и есть ли способ исправить это?

Из документации <f:metadata> (выделение2-й абзац мой):

Объявите фасет метаданных для этого представления.Это должно быть дитя <f:view>. Этот тег должен находиться в XHTML-файле верхнего уровня для данного viewId или в клиенте шаблона, но не в шаблоне. Реализация должна обеспечивать, чтобы прямой дочерний элемент фасета был UIPanel,даже если есть только один ребенок аспекта.Реализация должна установить идентификатор UIPanel равным значению символической константы UIViewRoot.METADATA_FACET_NAME.

Таким образом, он действительно должен идти в виде сверху, а не в шаблоне.


Есть ли лучший способ убедиться, что один и тот же метод вызывается для каждой страницы перед чем-либо еще?

В вашем конкретном случаесохраните вошедшего в систему пользователя как свойство управляемого bean-объекта области сеанса вместо файла cookie и используйте filter в соответствующем шаблоне URL-адреса для его проверки.Управляемые компоненты сеанса находятся в фильтре в виде атрибутов HttpSession.Доморощенные куки не нужны, так как вы в основном изобретаете здесь HttpSession.Если только вы не хотите «запомнить меня», но это не должно решаться таким образом.Сделайте это и в фильтре.

См. Также:

0 голосов
/ 28 сентября 2011

Я получил это, работая вместо PhaseListener.

public class CookieLoginPhaseListener implements PhaseListener
{
    @Override
    public void beforePhase(PhaseEvent event)
    {
    }

    @Override
    public void afterPhase(PhaseEvent event)
    {
        UserSessionBean userSessionBean = Util.lookupCdiBean("userSessionBean");
        userSessionBean.handleAuthCookie();
    }

    @Override
    public PhaseId getPhaseId()
    {
        return PhaseId.RESTORE_VIEW;
    }
}

и немного магии поиска бобов здесь:

public static <T> T lookupCdiBean(String name)
{
    return (T) FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{" + name + "}", Object.class);
}

Спасибо @BalusC за это: JSF - получить управляемый бин по имени . Поскольку я использую CDI, я не могу использовать более декларативную опцию @ManagedProperty. Ничего страшного, хотя.

...