【问题标题】:How can I create a reusable view using JSF如何使用 JSF 创建可重用视图
【发布时间】:2012-02-09 22:11:55
【问题描述】:

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

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

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

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

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

我确定我一定遗漏了一些简单的东西。 (相对于 JSF/CDI 术语来说很简单!)

【问题讨论】:

    标签: java jsf-2 cdi


    【解决方案1】:

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

    例如

    <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 的隐式对象)

    并通过&lt;f:viewParam&gt; 设置它,以便您可以在编辑地址支持bean的提交方法中返回它:

    public String save() {
        // ...
    
        return from + "?faces-redirect=true";
    }
    

    另见:

    【讨论】:

    • 感谢@BalusC,这是非常有用的信息。就我而言,我不想在父实体编辑完成之前保留任何实体。使用您的方法,如果不先保留地址,我想不出一种从地址编辑中恢复过来的方法。
    【解决方案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 的实例,然后在调用 action 方法时设置地址和返回视图属性。

    @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());
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果你想在地址OK时设置另一个实体,只需给地址进程你要设置的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;
      

      【讨论】:

        猜你喜欢
        • 2012-05-31
        • 1970-01-01
        • 2011-08-19
        • 2015-09-16
        • 1970-01-01
        • 2019-05-08
        • 1970-01-01
        • 2013-01-05
        • 2016-03-15
        相关资源
        最近更新 更多