1

我有以下页面:

<?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>

分级豆:

@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 操作绑定(包括在标头中生成的绑定)也是如此。

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

编辑:

按下菜单项(哪个无关紧要)的记录输出 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 的所有其他绑定上。

4

1 回答 1

5

到目前为止发布的代码并未表明这一点(使用@Named @ViewScoped没有意义),但如果在binding完全值得的 JSF 视图范围托管 bean 的属性上使用该属性(带有@ManagedBean @ViewScoped),则症状是可以识别的。

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

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

这个鸡蛋问题可以通过仅在请求范围的 bean 上使用属性来解决,或者通过将context 参数binding设置为关闭部分状态保存来解决。这已被报告为JSF 问题 1492,并在即将发布的 JSF 2.2 中得到修复。web.xmljavax.faces.PARTIAL_STATE_SAVINGfalse

也可以看看:

于 2012-10-23T21:45:45.480 回答