请求范围页面导航

时间:2012-05-28 08:11:08

标签: jsf-2 cdi

我正在使用标准Java EE组件(如JSF 2.0,CDI,EJB和JPA)设计站点。它处于早期阶段,因此导航非常简单。问题是我在导航时难以保留一些数据。

这是seminarController支持bean:

SeminarController.java

@Named
@RequestScoped
public class SeminarController {
    @Inject
    private SeminarDao seminarDao;

    private int seminarID;
    private Seminar seminar;

    ...
    // Getters and setters
    ...

    public Collection<Seminar> getSeminars() {...}

    public Collection<Seminar> getUpcomingSeminars() {...}

    public void initSeminar() {
        seminar = seminarDao.findSeminar(seminarID);
    }

    public String save() {
        seminarDao.save(seminar);
        return "details";
    }
}

第一页目前正在列出一些即将举行的研讨会,可能会有一些感兴趣。

index.xhtml

    <ul>
        <ui:repeat value="#{seminarController.upcomingSeminars}" var="seminar">
            <li>
                <h:link value="#{seminar.title}" outcome="details">
                    <f:param name="id" value="#{seminar.seminarID}"/>
                </h:link>
                on
                <h:outputText value="#{seminar.eventDate}"/>
            </li>
        </ui:repeat>
    </ul>

如您所见,我有一个包含链接的列表,如果单击该链接,将会转到详细信息页面。我正在使用f:param将研讨会的ID添加到HTTP请求参数中。

详细信息页面显示了有关即将举行的研讨会的更多细节(当然)。也可以点击链接编辑研讨会。

details.xhtml

<f:metadata>
    <f:viewParam name="id" value="#{seminarController.seminarID}"/>
    <f:event type="preRenderView" listener="#{seminarController.initSeminar}"/>
</f:metadata>
<ui:define name="body">

    <h2>#{seminarController.seminar.title}</h2>

    <p>
        <strong>When:</strong>
        #{seminarController.seminar.eventDate}
    </p>
    <p>
        <strong>Where:</strong>
        #{seminarController.seminar.address},
        #{seminarController.seminar.country}
    </p>
    ...
    <p>
        <h:link value="Edit" outcome="edit">
            <f:param name="id" value="#{seminarController.seminarID}"/>
        </h:link> |
        <h:link value="Back to List" outcome="index"/>
    </p>

到目前为止一切顺利,一切正常。

现在我们按照链接编辑研讨会,然后转到编辑页面。我们仍在使用f:param作为当前研讨会的ID。

edit.xhtml

<f:metadata>
    <f:viewParam name="id" value="#{seminarController.seminarID}"/>
    <f:event type="preRenderView" listener="#{seminarController.initSeminar}"/>
</f:metadata>
<ui:define name="body">
    <h:form>
        <h:messages title="Please correct the errors and try again."/>
        <fieldset>
            <h:panelGroup class="editor-label" layout="block">
                <h:outputLabel value="Seminar Title:" for="title"/>
            </h:panelGroup>
            <h:panelGroup class="editor-field" layout="block">
                <h:inputText id="title" value="#{seminarController.seminar.title}"/>
                <h:message for="title" title="*"/>
            </h:panelGroup>
            ...
            <p>
                <h:commandButton value="Save" action="#{seminarController.save}">
                    <f:param id="id" value="#{seminarController.seminar.seminarID}"/>
                </h:commandButton>
            </p>
        </fieldset>
    </h:form>

这是我开始遇到问题的地方。我想在按下“保存”按钮时返回详细信息页面。详细信息页面应显示当前研讨会以及最新更新的详细信息。问题是,当按下“保存”按钮时,seminar中的seminarController对象为null

渲染编辑视图时,会初始化研讨会对象并用于显示表单中的当前值。但是当按下“保存”按钮时,seminarController中不再存在研讨会对象。并且也不会调用initSeminar方法。

所以问题是我应该如何设计设计 - 编辑 - 设计页面导航?

ViewScope不起作用,因为我在按Save时导航到新视图。无论如何使用CDI时ViewScope都不存在。

任何帮助都会感激不尽!


修改

研讨会课程有一些不在表格中看到的字段。

Seminar.java

@Entity
public class Seminar {
    @Id
    private int seminarID;
    @Column
    private String title;
    @Column
    private Date eventDate;   // Date when the seminar occurs
    @Column
    private Date createdDate; // Not visible in forms
    ...
    // Some more fields and Getters/Setters
}

EDIT2:

我最终在SeminarController

中执行此操作

SeminarController.java

@PostConstruct
public void init() {
    if (FacesContext.getCurrentInstance().isPostback()) {
        seminar = new Seminar();
    } else {
        seminar = seminarDao.findSeminar(seminarID);
    }
}

public void setSeminarID(int seminarID) {
    if (this.seminarID != seminarID) {
        seminar = seminarDao.findSeminar(seminarID);
        this.seminarID = seminarID;
    }
}

public String save() {
    seminarDao.save(seminar);
    return "details?faces-redirect=true&includeViewParams=true";
}

然后我将<h:inputHidden value="#{seminarController.seminarID}"/>添加到edit.xhtml

<f:event/>已在details.xhtmledit.xhtml中相应更改,以调用init()方法而不是旧版initSeminar()

这似乎有效,虽然我不喜欢在回发中使用seminar创建new对象,然后在设置seminarID时覆盖它。

1 个答案:

答案 0 :(得分:2)

您需要在更新模型值阶段发生之前自己准备seminar。预渲染视图事件太晚了。

其中一种方法是创建@PostConstruct,其中检查当前请求是否为回发,如果是,则预先调整Seminar,以便JSF有机会在更新模型期间调用其setter价值观阶段。

@PostConstruct
public void init() {
    if (FacesContext.getCurrentInstance().isPostback()) {
        seminar = new Seminar();
    }
}

我不确定initSeminar()做了什么,但我认为您还需要相应地更改它if (!FacesContext.getCurrentInstance().isPostback())