103

我在 JSF 2 应用程序中使用 Primefaces。我有一个<p:dataTable>, 而不是选择行,我希望用户能够直接对各个行执行各种操作。为此,我<p:commandLink>在最后一列中有几个 s。

我的问题:如何将行 ID 传递给命令链接启动的操作,以便我知道要对哪一行进行操作?我尝试使用<f:attribute>

<p:dataTable value="#{bean.items}" var="item">
    ...
    <p:column>
        <p:commandLink actionListener="#{bean.insert}" value="insert">
            <f:attribute name="id" value="#{item.id}" />
        </p:commandLink>
    </p:column>
</p:dataTable>

但它总是产生 0 - 显然行变量f在呈现属性时不可用(当我使用固定值时它工作)。

有人有替代解决方案吗?

4

4 回答 4

216

至于原因,<f:attribute>特定于组件本身(在视图构建期间填充),而不是迭代行(在视图渲染期间填充)。

有几种方法可以达到要求。

  1. 如果您的 servletcontainer 至少支持 Servlet 3.0 / EL 2.2,那么只需将其作为UICommand 组件或AjaxBehavior标记的操作/侦听器方法的参数传递。例如

     <h:commandLink action="#{bean.insert(item.id)}" value="insert" />
    

    结合:

     public void insert(Long id) {
         // ...
     }
    

    这只需要为表单提交请求保留数据模型。最好的方法是将 bean 放在视图范围内@ViewScoped

    你甚至可以传递整个 item 对象:

     <h:commandLink action="#{bean.insert(item)}" value="insert" />
    

    和:

     public void insert(Item item) {
         // ...
     }
    

    在 Servlet 2.5 容器上,如果您提供支持此功能的 EL 实现,例如 JBoss EL,这也是可能的。有关配置详细信息,请参阅此答案


  2. <f:param>UICommand组件中使用。它添加了一个请求参数。

     <h:commandLink action="#{bean.insert}" value="insert">
         <f:param name="id" value="#{item.id}" />
     </h:commandLink>
    

    如果您的 bean 是请求范围的,让 JSF 设置它@ManagedProperty

     @ManagedProperty(value="#{param.id}")
     private Long id; // +setter
    

    或者,如果您的 bean 范围更广,或者您想要更细粒度的验证/转换,<f:viewParam>请在目标视图上使用,另请参阅f:viewParam 与 @ManagedProperty

     <f:viewParam name="id" value="#{bean.id}" required="true" />
    

    无论哪种方式,这都有一个优点,即不一定需要为表单提交保留数据模型(对于您的 bean 是请求范围的情况)。


  3. <f:setPropertyActionListener>UICommand组件中使用。优点是当 bean 的范围比请求范围更广时,这消除了访问请求参数映射的需要。

     <h:commandLink action="#{bean.insert}" value="insert">
         <f:setPropertyActionListener target="#{bean.id}" value="#{item.id}" />
     </h:commandLink>
    

    结合

     private Long id; // +setter
    

    它只能通过idaction 方法中的属性获得。这只需要为表单提交请求保留数据模型。最好的方法是将 bean 放在视图范围内@ViewScoped


  4. 将数据表值绑定到DataModel<E>反过来包装项目。

     <h:dataTable value="#{bean.model}" var="item">
    

     private transient DataModel<Item> model;
    
     public DataModel<Item> getModel() {
         if (model == null) {
             model = new ListDataModel<Item>(items);
         }
         return model;
     }
    

    transient当您在视图或会话范围的 bean 上使用它时,必须在 getter 中懒惰地实例化它,因为DataModel没有实现Serializable

    然后,您将能够访问当前行,DataModel#getRowData()而无需传递任何内容(JSF 根据单击的命令链接/按钮的请求参数名称确定行)。

     public void insert() {
         Item item = model.getRowData();
         Long id = item.getId();
         // ...
     }
    

    这也要求为表单提交请求保留数据模型。最好的方法是将 bean 放在视图范围内@ViewScoped


  5. 用于Application#evaluateExpressionGet()以编程方式评估当前#{item}.

     public void insert() {
         FacesContext context = FacesContext.getCurrentInstance();
         Item item = context.getApplication().evaluateExpressionGet(context, "#{item}", Item.class);
         Long id = item.getId();
         // ...
     }
    

选择哪种方式取决于功能要求以及其中一种或另一种是否为其他目的提供更多优势。我个人会继续使用#1,或者,当您也想支持 servlet 2.5 容器时,使用#2。

于 2011-02-14T16:54:55.087 回答
11

在 JSF 1.2 中,这是由<f:setPropertyActionListener>(在命令组件中)完成的。在 JSF 2.0(准确地说是 EL 2.2,感谢 BalusC)中,可以这样做:action="${filterList.insert(f.id)}

于 2011-02-14T16:48:50.327 回答
11

在我的视图页面中:

<p:dataTable  ...>
<p:column>
<p:commandLink actionListener="#{inquirySOController.viewDetail}" 
               process="@this" update=":mainform:dialog_content"
           oncomplete="dlg2.show()">
    <h:graphicImage library="images" name="view.png"/>
    <f:param name="trxNo" value="#{item.map['trxNo']}"/>
</p:commandLink>
</p:column>
</p:dataTable>

后备豆

 public void viewDetail(ActionEvent e) {

    String trxNo = getFacesContext().getRequestParameterMap().get("trxNo");

    for (DTO item : list) {
        if (item.get("trxNo").toString().equals(trxNo)) {
            System.out.println(trxNo);
            setSelectedItem(item);
            break;
        }
    }
}
于 2011-05-09T08:50:05.373 回答
0

感谢Mkyong 的这个网站,唯一真正为我们传递参数的解决方案是这个

<h:commandLink action="#{user.editAction}">
    <f:param name="myId" value="#{param.id}" />
</h:commandLink>

public String editAction() {

  Map<String,String> params = 
            FacesContext.getExternalContext().getRequestParameterMap();
  String idString = params.get("myId");
  long id = Long.parseLong(idString);
  ...
}

从技术上讲,您不能直接传递给方法本身,而是传递给JSF request parameter map.

于 2015-04-20T20:21:10.753 回答