绑定杀死支持豆...我做错了什么?

时间:2012-10-23 20:22:19

标签: jsf java-ee primefaces

我有以下页面:

<?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:ui="http://java.sun.com/jsf/facelets"
  xmlns:p="http://primefaces.org/ui"
  xmlns:h="http://java.sun.com/jsf/html">

<body>

    <ui:composition template="./templates/fireLeftMenuTemplate.xhtml">

        <ui:define name="left">
            <h:form>
                <p:menu model="#{gradingBean.courseMenu}"/>
            </h:form>
        </ui:define>

        <ui:define name="content">
            <h:form>
                <p:accordionPanel binding="#{gradingBean.assignmentView}"/>         
            </h:form>
        </ui:define>

    </ui:composition>

</body>

GradingBean:

@Named("gradingBean")
@ViewScoped
public class GradingBean {

@EJB
private AssignmentManager assignmentManager;

/*
 * The assignmentMenu, listing all assignments for each course currently
 * assisted by this grader
 */
private final DefaultMenuModel courseView = new DefaultMenuModel();
private final AccordionPanel assignmentView = new AccordionPanel();

public GradingBean() {
    FireLogger.logInfo("Created GradingBean for user {0}", FireUtil.getLoggedinUserEmail());
}

@PostConstruct
private void constructBean() {
    constructAssignmentView();
    constructCourseMenu();
    FireLogger.logInfo("Constructed bean");
}

private void constructAssignmentView() {

    Tab tab = new Tab();
    tab.setTitle("Hello");

    assignmentView.getChildren().add(tab);
    assignmentView.setRendered(true);

    FireLogger.logInfo("Constructed assignmentView");
}

private void constructCourseMenu() {

    /*
     * For now we default to just one course at a time, since we have not
     * implemented support for multiple courses as of yet.
     */
    Submenu defaultCourse = new Submenu();
    defaultCourse.setLabel("Objekt Orienterad Programmering IT");

    /*
     * add each assignment associated with this course
     */
    ExpressionFactory expressionFactory =
            FacesContext.getCurrentInstance()
            .getApplication()
            .getExpressionFactory();

    for (Assignment assignment : assignmentManager.getAll()) {

        MenuItem menuItem = new MenuItem();
        menuItem.setValue(assignment.getTitle());

        MethodExpression expression = expressionFactory.createMethodExpression(
                FacesContext.getCurrentInstance().getELContext(), "#{gradingBean.printstuff('yay!')}", String.class, new Class[0]);

        menuItem.setActionExpression(expression);
        defaultCourse.getChildren().add(menuItem);
    }
    courseView.addSubmenu(defaultCourse);

    FireLogger.logInfo("Constructed courseMenu");
}

public String printstuff(String stuff) {
    FireLogger.logInfo("Printing! " + stuff);
    return "hej";
}

public DefaultMenuModel getCourseMenu() {
    return courseView;
}

public AssignmentManager getAssignmentManager() {
    return assignmentManager;
}

public DefaultMenuModel getCourseView() {
    return courseView;
}

public AccordionPanel getAssignmentView() {
    return assignmentView;
}

public void setAssignmentManager(AssignmentManager assignmentManager) {
    this.assignmentManager = assignmentManager;
}

/**
 * Custom menuitem for the purpose of storing associated assignments and
 * information related to them.
 */
private class AssignmentMenuItem extends MenuItem {

    private static final long serialVersionUID = 1L;
    private Assignment assignment;

    public AssignmentMenuItem(Assignment assignment) {
        super();
        this.assignment = assignment;
        setValue(assignment.getTitle());
    }

    /**
     * Convenience method
     *
     * @param component
     */
    public void addChild(UIComponent component) {
        getChildren().add(component);
    }
}
}

请不要介意代码质量,它是用于调试的。 问题在于:每当我在xhtml页面上启用accordionPanel标签时,与此页面关联的所有其他bean都会停止工作:例如,单击courseView菜单上的任何菜单项(在没有手风琴的情况下,它可以完美地工作) ,除了重新加载页面。所有其他bean操作绑定(包括标头中生成的绑定)也是如此。

我在这里缺少什么?一旦我删除了accordionPanel标签,如上所述,它就可以正常工作。我猜它与请求周期有关,但我不知道出了什么问题。

编辑:

记录输出以按下菜单项(哪一个无关紧要)2次:

INFO: se.gu.fire.backend.GradingBean: Created GradingBean for user a@a.com
INFO: se.gu.fire.backend.GradingBean: Constructed assignmentView
INFO: se.gu.fire.backend.GradingBean: Constructed courseMenu
INFO: se.gu.fire.backend.GradingBean: Constructed bean

INFO: se.gu.fire.backend.GradingBean: Created GradingBean for user a@a.com
INFO: se.gu.fire.backend.GradingBean: Constructed assignmentView
INFO: se.gu.fire.backend.GradingBean: Constructed courseMenu
INFO: se.gu.fire.backend.GradingBean: Constructed bean

注意循环似乎是如何重置的,并且只要发生这种情况就重新加载bean ...这也适用于此页面上其他bean的所有其他绑定。

1 个答案:

答案 0 :(得分:5)

到目前为止发布的代码并不表示(使用@Named @ViewScoped没有意义),但是如果在属性上使用binding属性,则可以识别症状值得信赖的JSF视图作用域托管bean(@ManagedBean @ViewScoped)。

在视图构建期间评估binding属性(如id属性和所有标记处理程序)。默认情况下(在启用了部分状态保存的情况下)视图构建在每个HTTP请求上。构建视图后,视图范围即可使用。视图范围的托管bean存储在那里。

但是,在视图构建期间,视图范围默认不可用。这意味着引用在构建视图期间评估的视图范围bean的任何EL表达式将创建视图范围bean的全新且完全独立的实例,并将所有属性设置为默认值。然后重新使用它。

这个鸡蛋问题可以通过在请求作用域上专门使用binding属性来解决,或者通过将web.xml上下文参数javax.faces.PARTIAL_STATE_SAVING设置为{来关闭部分状态保存{1}}。这被报告为JSF issue 1492,并在即将到来的JSF 2.2中得到修复。

另见: