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>

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への他のすべてのバインディングでも発生します。

4

1 に答える 1

5

これまでに投稿されたコードは、(使用しても意味がありません)ことを示していませんが、完全に価値のあるJSFビュースコープのマネージドBeanのプロパティで属性@Named @ViewScopedを使用した場合(with)、症状は認識できます。binding@ManagedBean @ViewScoped

binding属性は(属性idやすべてのタグハンドラーと同様に)ビューのビルド時に評価されます。ビューはデフォルトで(部分的な状態保存が有効になっている)すべてのHTTPリクエストに基づいて構築されます。ビューが作成されると、ビュースコープを使用できるようになります。ビュースコープのマネージドBeanはそこに格納されます。

ただし、ビュースコープはデフォルトではビューのビルド時に使用できません。つまり、ビューの構築中に評価されるビュースコープのBeanを参照するEL式は、すべてのプロパティがデフォルトに設定された、ビュースコープのBeanのまったく新しい完全に別個のインスタンスを作成します。その後、これは代わりに再利用されます。

この鶏卵の問題は、リクエストスコープのBeanで排他的に属性を使用するか、コンテキストパラメータをにbinding設定して部分的な状態の保存をオフにすることで解決できます。これはJSFの問題1492として報告されており、次のJSF2.2で修正されています。web.xmljavax.faces.PARTIAL_STATE_SAVINGfalse

参照:

于 2012-10-23T21:45:45.480 に答える