如何使用JSF创建可重用的视图

时间:2012-01-13 18:04:18

标签: java jsf-2 cdi

这是场景 - 我想创建一个视图,可以从许多其他视图中使用它来创建和编辑特定类型的对象。

我的应用程序有一个地址实体,可以在其他实体之间共享。 在维护实体的视图中,我想要一个按钮/链接,它导航到链接到该实体的地址的地址编辑视图。 处理不同实体的另一个视图还需要能够使用其地址导航到地址编辑视图。 完成编辑后,地址视图将导航回调用视图。

我的问题是我似乎找不到将地址实体从第一个视图传递到地址视图的方法。

我想我想要某种对话范围,但不知道如何获取地址而不知道引用它的页面bean,但显然我的地址视图只能知道地址。

我正在使用JSF2.1(MyFaces / PrimeFaces)和CDI(OpenWebBeans)和CODI。

我确定我必须遗漏一些简单的东西。 (简单来说就是JSF / CDI术语!)

3 个答案:

答案 0 :(得分:2)

我想我已经找到了解决方案。

当我使用CODI时,我可以利用ConversationGroup注释。 我创建了一个emtpy接口AddressConversation,然后将其添加到需要显示address/addressEdit.xhtml视图的所有支持bean,以及addressEdit视图的支持bean。

我也在使用CODI视图配置,所以我的动作方法返回ViewConfig派生类对象。

@Named
@ConversationScoped
@ConversationGroup(AddressConversation.class)
public class AddressView implements Serializable
{
    private Class<? extends Views> fromView;
    private Address editAddress;
    private Address returnAddress;

    // Getters/setters etc...

    public Class<? extends Views> cancelEdit()
    {
        returnAddress = null;

        return fromView;
    }
}

所以在调用视图中我有(PrimeFaces commandLink)

<p:commandLink value="#{enquiryView.addressLinkText}" action="#{enquiryView.editAddress()}" immediate="true"/>

在支持bean EnquiryView中,我可以在正确的会话组中@Inject AddressView的实例,然后在调用操作方法时设置地址和返回视图属性。

@Named
@ConversationScoped
@ConversationGroup(AddressConversation.class)
public class EnquiryView implements Serializable
{
    @Inject @ConversationGroup(AddressConversation.class) private AddressView addrView;

    public Class<? extends Views> editAddress()
    {
        addrView.setAddress(editEnq.getAddress());
        addrView.setFromView(Views.Enquiry.EnquiryEdit.class);
        return Views.Address.AddressEdit.class;
    }
}

我还可以观察EnquiryView中的导航,并在地址编辑视图中“保存”地址时更新查询实体。

protected void onViewConfigNav(@Observes PreViewConfigNavigateEvent navigateEvent)
{
    if (navigateEvent.getFromView() == Views.Address.AddressEdit.class && 
            navigateEvent.getToView() == Views.Enquiry.EnquiryEdit.class)
    {
        onEditAddressReturn();
    }
}

private void onEditAddressReturn()
{
    if (addrView.getReturnAddress() != null) {
        // Save pressed
        editEnq.setAddress(addrView.getReturnAddress());
    }
}

答案 1 :(得分:1)

只需将地址ID作为请求参数传递,并使目标视图通过<f:viewParam>转换,验证并在bean中进行设置。

E.g。

<h:link value="Edit address" outcome="addresses/edit">
    <f:param name="id" value="#{address.id}" />
</h:link>

然后在addresses/edit.xhtml

<f:metadata>
    <f:viewParam id="id" name="id" value="#{editAddressBacking.address}"
        converter="#{addressConverter}" converterMessage="Bad request. Unknown address."
        required="true" requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:message for="id" />

<h:form rendered="#{not empty editAddressBacking.address}">
    <h:inputText value="#{editAddressBacking.address.street}" />
    ...
</h:form>

为了导航回原始页面,您可以传递另一个请求参数。

<h:link value="Edit address" outcome="addresses/edit">
    <f:param name="id" value="#{address.id}" />
    <f:param name="from" value="#{view.viewId}" />
</h:link>

(其中#{view}是引用当前UIViewRoot的隐式对象)

并将其设置为<f:viewParam>,以便您可以在编辑地址支持bean的submit方法中返回它:

public String save() {
    // ...

    return from + "?faces-redirect=true";
}

另见:

答案 2 :(得分:0)

如果您希望在地址正常时设置其他实体,只需为地址流程提供您要设置的bean的EL名称:

<f:param name="targetBeanSetter" value="enquiryBean.adress" />

在Java中:

public String executeAndBack() {
    int last = this.targetBeanSetter.lastIndexOf('.');
    String base = this.targetBeanSetter.substring(0, last);
    String property = this.targetBeanSetter.substring(last + 1);
    Object yourEntityToSet = FacesContext.getCurrentInstance().getELContext().getELResolver().getValue(context.getELContext(), null, base);
    try {
            PropertyUtils.setSimpleProperty(yourEntityToSet, property, constructeurHolder.getConstructeur());
        } catch (Throwable e) {
            throw new RuntimeException(e.getMessage());
        }
    return from + "?faces-redirect=true";
}

如果您只需要访问选择的地址,而无需构建链接对象,当您返回第一页时,只需使用

注入EnquiryView
@ManagedProperty(value="{address}")
Address adress;