1

我正在设计一个使用标准 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>

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

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

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

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

任何帮助将不胜感激!


编辑

Seminar 类有一些在表单中看不到的字段。

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
}

编辑2:

我最终在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在设置时将其覆盖。

4

1 回答 1

2

您需要seminar在更新模型值阶段发生之前做好自己的准备。预渲染视图事件为时已晚。

其中一种方法是创建一个@PostConstruct检查当前请求是否是回发的方法,如果是,则预先创建,Seminar以便 JSF 有机会在更新模型值阶段调用其设置器。

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

我不确定是什么initSeminar(),但我认为您还需要相应地对其进行更改,以使其仅完成其工作if (!FacesContext.getCurrentInstance().isPostback())

于 2012-05-28T12:11:59.290 回答