【问题标题】:JSF2/Primefaces dataTable sort not working with ViewScoped beanJSF2/Primefaces dataTable 排序不适用于 ViewScoped bean
【发布时间】:2012-08-27 02:39:29
【问题描述】:

我想为 PrimeFaces 3.3 数据表添加排序功能,并创建了以下 ViewScoped bean 来存储列表,因此不会一直从 EJB 获取它:

@Named
@ViewScoped
public class CustomerList implements Serializable {

    private static final long serialVersionUID = 6168621124401208753L;

    @EJB 
    CustomerEJB customerBean;

    List<Customer> allCustomers = null;

    public void loadCustomerList() {
        allCustomers = customerBean.findAll();
    }

    public List<Customer> getList() {
        if (allCustomers == null) {
            loadCustomerList();
        }
        return allCustomers;
    }

}

这是使用 bean 的视图:

<ui:composition template="/WEB-INF/templates/template.xhtml">

  <ui:define name="content">

        <h:form id="customerList">

          <p:dataTable id="customer" var="customer"
            value="#{customerList.list}" sortBy="#{customer.id}"
            paginator="true" rows="10" paginatorAlwaysVisible="false"
            paginatorPosition="top">
            <p:column sortBy="#{customer.id}">
              <f:facet name="header">
                <h:outputText value="#{msg.customerIdLabel}" />
              </f:facet>
              <h:outputText value="#{customer.id}" />
            </p:column>
            <p:column sortBy="#{customer.lastName}">
              <f:facet name="header">
                <h:outputText value="#{msg.customerLastNameLabel}" />
              </f:facet>
              <h:outputText value="#{customer.lastName}" />
            </p:column>

问题是我可以单击列标题进行排序,但表格仍然未排序,即使初始排序也不起作用。当您在 getList() 方法中设置断点时,我可以看到在处理请求期间从 EJB 中多次获取列表。 只要 ViewScope 处于活动状态,不应该存储 bean 吗?

【问题讨论】:

    标签: sorting jsf-2 datatable primefaces


    【解决方案1】:

    你需要使用这个 Annotation Bean 组合:

    对于@ManagedBean 你需要使用@ViewScoped

    对于@Named (CDI) 你需要使用@ConversationScoped

    【讨论】:

      【解决方案2】:

      CDI 不支持@ViewScoped,所以如果你需要在 CDI 中使用@ViewScoped,你应该

      • 使用seam-facesMyFaces CODI 模块。只需将其中一个添加到您的类路径中,@ViewScoped 将在 CDI 中工作。 MyFaces CODI 对@ViewScoped 的支持更加稳固
      • 使用 MyFaces CODI 的 @ViewAccessScoped,它是 Apache 在 CDI 之上编写的扩展,只需 download 它并使用 @ViewAccessScoped 注释而不是 @ViewScoped
      • 使用 CDI @ConversationScoped 并使其长时间运行。见here for more info

      不幸的是,seam3 解决方案存在内存泄漏问题,所以不要使用 seam3 解决这个特殊问题,更好的解决方案是 CODIs @ViewAccessScoped

      见:Memory leak with ViewScoped bean?

      【讨论】:

      • - 关于第一种可能性,只需将 MyFaces CODI 添加到类路径:我将 myfaces-extcdi-core-api 和 myfaces-extcdi-core-impl 添加到我的 pom 中,但没有任何改变。 @ViewScoped bean 仍然在每次“排序点击”时创建。
      • - 使用 @ViewAccessScoped 打开 bean 引用视图时收到以下错误消息: WELD-001303 No active contexts for scope type org.apache.myfaces.extensions.cdi.core.api.scope .conversation.ViewAccessScoped
      • -@ConversionScoped:我用这个范围注释了 bean,但是当我使用通常的 url 导航到那个页面时,我可以开始对话,但我不知道什么时候结束对话。因为用户可能会点击菜单上的其他页面 url。而且,从我呈现实体的数据表中,用户可以打开一个编辑页面,在该页面中为编辑会话创建新的转换。然后使用保存或取消按钮结束对话。
      • 使用 CDI 时一般不要使用@ViewScoped,如果你想使用 CODI,@ViewAccessScoped 应该会有所帮助。对于您的其他问题,请随时提出其他问题,我很乐意为您提供帮助;)
      • 不要忘记 MyFaces CODI 提供的 JSF 模块。核心独立于 JSF。或者使用其中一个包(用于 JSF 1.2 或 2.x)。
      【解决方案3】:

      首先,与您的问题没有直接关系,但是: 您永远不应该将您的业务方法放入组件 getter 中(即使使用 null 检查,我认为这是一种不好的做法)。请改用@PostConstruct 注解:

      @PostConstruct
      public void loadCustomerList() {
          allCustomers = customerBean.findAll();
      }
      
      public List<Customer> getList() {
          return allCustomers;
      }
      

      每次构造 ViewScoped bean 时都会调用 loadCustomerList。 另外,检查您的导入以获取范围注释:

      import javax.faces.bean.ManagedBean;
      import javax.faces.bean.ViewScoped;
      

      最后你的类应该是这样的:

      @ViewScoped
      @ManagedBean
      public class CustomerList implements Serializable {
          ...
      }
      

      【讨论】:

      • 感谢您对 PostConstruct 的提示。更改它并且工作得很好:) 关于 ViewScope 和 ManagedBean:不幸的是,我不确切知道何时使用 Named 以及何时使用 ManagedBean。当我开始这个项目时,我只使用了 ManagedBean,但后来 CDI 对我来说很有趣,我改为 Named,并在合适的时候改为 ConversationScoped。现在我为这个用例使用命名和(CDI)ConversationScoped,它可以工作。所以,我会坚持下去。我不想混合 ManagedBean 和 Named,虽然我不知道什么时候使用什么。有最佳做法还是不良做法?
      • 在很多情况下@PostConstruct确实更好,但延迟加载不一定是坏习惯。如果 getter 只是偶尔被调用,那么预先加载它可以让您为所有不调用 getter 的情况支付加载数据的成本。
      • @Joysn 不确定在一般情况下选择 Faces Managed Beans 而不是 CDI managed bean 有什么好的/坏的做法。在我的 JSF 应用程序(PF 和 PF-Extensions 应用程序)中,由于@ViewScoped,我将使用 Faces Managed Beans。每个 PF/PF-E 组件在这些示波器上都按预期工作,所以我坚持使用它们。如果您想了解有关 Faces Managed Beans 的更多信息,我推荐 BalusC 的 Communication in JSF 2.0 文章。
      • 要了解不同之处,请参见此处:stackoverflow.com/questions/11986847/…
      • @Heidarzadeh 感谢您的指点。有了这些见解,我需要提出另一个问题:) stackoverflow.com/questions/12235464/…
      猜你喜欢
      • 2013-09-30
      • 1970-01-01
      • 2012-04-14
      • 2013-12-26
      • 2013-11-20
      • 2011-09-22
      • 1970-01-01
      • 1970-01-01
      • 2013-02-01
      相关资源
      最近更新 更多