Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Рендеринг при первой загрузке страницы JSF


Автор: nikss 4.3.2008, 10:44
Привет!
Столкнулся с такой проблемой: 
на странице jsp есть компонент <h:panelGrid  bind="#{state.menu}" ... > с дочерними компонентами <h:commandLink/>. Во время первой загрузки страницы, в фазе RENDER_RESPONSE, пытаюсь изменить в бине аттрубут "style" дочерних компонентов <h:commandLink/>, но оказывается , что "menu" (в бине, как HtmlPanelGrid) содержит нуль дочерних компонентов. 
Во всех последующих рендерингах дочерние компоненты присутствуют. Бин state объявлен как session бин в faces-config.
Может кто сталкивался с такой ситуацией? Жду помощи! Спасибо.

Автор: ivg 4.3.2008, 11:35
А почему стили на самой странице не прописать?
PS: Поставьте точки останова на геттер и сеттер поля menu, и увидите как работает биндинг, на каких фазах и т. п.
Покажите код и содержимое страницы, если не разберётесь.

Автор: nikss 4.3.2008, 12:00
ivg, стили прописать на странице можно, но в данном случае у меня отрисовывается текущий элемент меню.
Привожу код:
Бин state
Код

public class State {
    private String currentItemMenu = Constants.MAIN_VIEW;
    private HtmlPanelGrid menu = new HtmlPanelGrid();

    /** Creates a new instance of State */
    public State() {
        LifecycleFactory lifecycleFactory = (LifecycleFactory)
        FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
        Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
        lifecycle.addPhaseListener(
                  new PhaseListener()
                    {
                         public void beforePhase(PhaseEvent event)
                            {
                                doBeforeView();
                            }
                         public void afterPhase(PhaseEvent event)
                            {
                            }
                         public PhaseId getPhaseId()
                            {
                               return PhaseId.RENDER_RESPONSE;
                             }
                    });
    }
    
    private void doBeforeView(){
        createMenu();
    }
            
    public void createMenu(){
        Application app = FacesContext.getCurrentInstance().getApplication();
        List menuItems = menu.getChildren();
        //menu.setColumns(5);
        for (Iterator item = menuItems.iterator();item.hasNext();) {
            UIComponent temp = (UIComponent) item.next();
            if (temp instanceof UICommand) {
                HtmlCommandLink link = (HtmlCommandLink) temp;
                link.setStyle(Constants.BACKGROUND_MENU_ITEM);
                Map attr = link.getAttributes();
                link.setRendered(Permission.isAllowAction((String) attr.get(Constants.ACTION_MENUITEM_KEY), user.getUser()));
                if (attr.get(Constants.ACTION_MENUITEM_KEY).equals(Constants.MAIN_VIEW)) 
                    link.setStyle(Constants.BACKGROUND_CURRENT_MENU_ITEM);
            }
        }
    }

    public HtmlPanelGrid getMenu() {
        return menu;
    }
    
    public void setMenu(HtmlPanelGrid _menu) {
        menu=_menu;
    }
        
}


Страница header.jsp:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<f:loadBundle basename="ua.com.nikss.beans.Resources.messages" var="msgs"/>  
<head>
 <script language="javascript" src="/resources/jscript.js">
<LINK href="/resources/styleclass.css" rel="stylesheet" type="text/css">
</head>
<f:subview id="header" >
    <h:form>
            <center>
            <h:panelGrid columns="5" cellpadding="4" cellspacing="2" >
                <h:graphicImage url="/images/logo_nokia.gif"/>
                <h:outputText value="Пользователь: #{state.user.login}"/>
                <h:selectOneListbox  size="1" onchange="submit()" valueChangeListener="#{state.changeLocale}" value="#{state.locale}">
                    <f:selectItems value="#{state.locales}"/>
                </h:selectOneListbox>
                <h:commandButton action="#{state.logoff}" value="Выйти"/>
            </h:panelGrid>
            </center>
    </h:form>
            
            
   <h:form>
            <h:panelGrid columns="6" border="0" styleClass="border" binding="#{state.menu}">
                <h:commandLink value="Главная" action="#{state.onActionMenu}" actionListener="#{state.onClickMenu}"> 
                    <f:attribute name="itemMenu" value="/content/main.jsp"/>
                </h:commandLink>
                <h:commandLink value="Журнал тренингов" action="#{state.onActionMenu}" actionListener="#{state.onClickMenu}"> 
                    <f:attribute name="itemMenu" value="/content/listOfTrainings.jsp"/>
                </h:commandLink>
                <h:commandLink value="Управление тренингами" action="#{state.onActionMenu}" actionListener="#{state.onClickMenu}"> 
                    <f:attribute name="itemMenu" value="/content/manageOfTrainings.jsp"/>
                </h:commandLink>
                <h:commandLink value="Регистрация нового тренинга" action="#{state.onActionMenu}" actionListener="#{state.onClickMenu}"> 
                    <f:attribute name="itemMenu" value="/content/addNewTraining.jsp"/>
                </h:commandLink>
                <h:commandLink value="Статус регистрации" action="#{state.onActionMenu}" actionListener="#{state.onClickMenu}"> 
                    <f:attribute name="itemMenu" value="/content/statusOfRegistration.jsp"/>
                </h:commandLink>
                <h:commandLink value="Администрирование" action="#{state.onActionMenu}" actionListener="#{state.onClickMenu}"> 
                    <f:attribute name="itemMenu" value="/content/admin.jsp"/>
                </h:commandLink>
            </h:panelGrid>
   </h:form>        
     
</f:subview>

Страница main.jsp:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">


<f:view>
    <jsp:include page="Header.jsp"/>
    <h:outputText value="Главная"/>
</f:view>

Автор: Maksym 4.3.2008, 13:17
nikss
jsf инстанциирует managed beans по требованию (on demand), то есть тогда когда они необходимы для генерации ответа. Видимо, в твоем случае menu понадобилось позже.
Ты проверял в beforePhase или afterPhase?

Автор: nikss 4.3.2008, 15:26
Maksym, каким образом это можно проверить?

Автор: Maksym 4.3.2008, 15:46
nikss
я уже сам увидел в твоем коде -- ты вызываешь createMenu(); в beforePhase() PhaseListener'а. 
Попробуй сделать это в afterPhase(). Правда я не уверен что сработает  smile 

Автор: ivg 4.3.2008, 17:15
Цитата из JSF Spec, правда для 1.1:
Цитата

3.1.5 Component Bindings
A component binding is a special value binding expression that can be used to facilitate “wiring up” a component instance to a corresponding property of a JavaBean that is associated with the page, and wants to manipulate component instances programatically. It is established by calling setValueBinding() (see Section 3.1.4 “Value Binding Expressions”) with the special property name binding.
The specified ValueBinding must point to a read-write JavaBeans property of type UIComponent (or appropriate subclass). Such a component binding is used at two different times during the processing of a Faces Request:

  • When a component instance is first created (typically by virtue of being referenced by a UIComponentTag in a JSP page), the JSF implementation will retrieve the ValueBinding for the name binding, and call getValue() on it. If this call returns a non-null UIComponent value (because the JavaBean programmatically instantiated and configured a component already), that instance will be added to the component tree that is being created. If the call returns null, a new component instance will be created, added to the component tree, and setValue() will be called on the ValueBinding (which will cause the property on the JavaBean to be set to the newly created component instance).
  • When a component tree is recreated during the Restore View phase of the request processing lifecycle, for each component that has a ValueBinding associated with the name binding, setValue() will be called on it, passing the recreated component instance.

Component bindings are often used in conjunction with JavaBeans that are dynamically instantiated via the Managed Bean Creation facility (see Section 5.3.1.2 “Default VariableResolver Implementation”). It is strongly recommend that application developers place managed beans that are pointed at by component binding expressions in “request” scope. This is because placing it in session or application scope would require thread-safety, since UIComponent instances depend on running inside of a single thread.

Как я понимаю, всё дело в механизме этого самого биндинга. Попробуйте, на всякий случай, обнулить поле menu в 3 строке бина.

Автор: nikss 30.3.2008, 15:33
В общем, все перепробовал! Объявлял и так
Код

..
private HtmlPanelGrid menu = new HtmlPanelGrid();
...
 

и так 
Код

..
private HtmlPanelGrid menu = null;
..


в конечном счете все равно приходим к нулевому значению дочерних элементов.

пытался сделать это в  методе afterPhase() - возвращает правильное количество дочерних элементов, но в этой фазе я немогу ничего сделать, так как мои изменения не будут применены.


Понемногу начинаю разочаровываться в JSF. :(

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)