7

我正在从 IceFaces 更改为 PrimeFaces(我真的很想更改为 RichFaces,但在新版本中会导致错误,我不会)并且我很难正确实现 primefaces autoComplete。根据他的手册,我只需要实现一个返回对象列表的方法,在这种情况下需要一个转换器。

我返回的列表是 javax.faces.model.SelectItem 的列表,我真的不明白为什么我需要为此创建一个转换器,但让我们继续。我创建了一个简单的转换器来测试,但 primefaces 无法识别我的转换器并在浏览器中返回此错误:

/resources/components/popups/popupBuscaPessoa.xhtml @35,41 itemLabel="#{pessoa.label}":类'java.lang.String'没有属性'label'。

这是我的转换器类(只是为了测试):

public class ConversorSelectItem implements Converter {

@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {      
     if (value!=null && value.isEmpty())
         return null;

     SelectItem selectItem=new SelectItem();
     selectItem.setLabel(value);
     return selectItem;     
}

@Override
public String getAsString(FacesContext context, UIComponent component, Object object) {
    return ((SelectItem)object).getLabel();
}
}

这是我尝试使用 p:autocomplete 的地方:

<p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}"
            completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}"
            var="pessoa" itemLabel="#{pessoa.label}" itemValue="#{pessoa.value}"
            converter="#{conversorSelectItem}"/>

我做错什么了吗?SelectItem 没有默认转换器吗?有没有更简单的方法来实现这个转换器?

4

5 回答 5

12

你不应该喂它List<SelectItem>。你应该喂它List<Pessoa>。您也不应该专注于转换SelectItem。您应该专注于转换项目值,即Pessoa. 这SelectItem是旧 JSF 1.x 时代的遗留物。在 JSF 2.x 中,这不再是强制性的,这要归功于视图中的var,itemValueitemLabel属性。这可以使您的 bean 远离特定于视图的混乱。

Converter仅当您使用和itemValue="#{pessoa}"引用#{modeloPopupBuscaPessoa.itemSelecionado}属性Pessoa时才需要。然后,您应该getAsString()转换Pessoa为它的唯一String表示(以便可以在 HTML 中打印)并getAsObject()转换 from Stringto Pessoa(以便可以在 bean 属性中设置它)。

但是,如果#{pessoa.value}是 aString并且#{modeloPopupBuscaPessoa.itemSelecionado}也是 a String,那么您应该完全使用itemValue="#{pessoa.value}"和删除Converter

也可以看看:

于 2011-10-04T20:41:21.690 回答
6

可用于 Primefaces 自动完成和所有其他目的的通用转换器:

import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.WeakHashMap;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

@FacesConverter(value = "entityConverter")
public class EntityConverter implements Converter {

    private static Map<Object, String> entities = new WeakHashMap<Object, String>();

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object entity) {
        synchronized (entities) {
            if (!entities.containsKey(entity)) {
                String uuid = UUID.randomUUID().toString();
                entities.put(entity, uuid);
                return uuid;
            } else {
                return entities.get(entity);
            }
        }
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String uuid) {
        for (Entry<Object, String> entry : entities.entrySet()) {
            if (entry.getValue().equals(uuid)) {
                return entry.getKey();
            }
        }
        return null;
    }

}
于 2013-06-13T10:14:49.203 回答
2

我遇到了同样的问题,作者在Primefaces autocomplete with POJO and String value的评论给了我在我的案例中找到问题根源的提示。

概述

问题是它value=#{objectValue}是类型String,但引用的方法completeMethod返回一个List<Object>.

该设计

我有以下 POJO(简化):

public class CollaboratorGroup {
   private String groupId;

   private String groupName;

   private Collaborator piUserId;

   ...
}

public class Collaborator {
   private String userId;

   private String fullName;

   private String groupId;
   ...
}

这是否是一个有用的设计并不重要。我只是想解决这个问题。

以下p:autoComplete(简化):

<p:autoComplete var="group"
    itemLabel="#{group.groupId}"
    itemValue="#{group.groupId}"
    completeMethod="#{bean.completeGroup}"
    value="#{collaborator.groupId}">
    <f:facet name="itemtip">
        <p:panelGrid columns="2">
            <f:facet name="header">
                <h:outputText value="#{group.groupId}" />
            </f:facet>
            <h:outputText value="Name:" />
            <h:outputText value="#{group.groupName}" />
            <h:outputText value="PI" />
            <h:outputText value="#{group.piUserId.fullName}" />
        </p:panelGrid>
    </f:facet>
</p:autoComplete>

会扔The class 'java.lang.String' does not have the property 'groupId'。当我更改为 时itemLabel=#{group},我会在输入字段中看到 groupId CG00255,但org.coadd.sharedresources.model.CollaboratorGroup@...在下拉列表中会看到很多。如果我选择其中之一,则此toString()值设置为不需要的 Collaborator.groupId。

问题的根源

p:autoComplete我用一段List<CollaboratorGroup>时间来喂Collaborator.groupIdaString并且itemLabel用于“格式化”两者,String groupId集合 asvalue="#{collaborator.groupId}"CollaboratorGroup来自 的List,由completeMethod="#{bean.completeGroup}".

可能的解决方案

  1. 如果它不会破坏您的设计,您可以Model通过将成员更改groupIdCollaboratorGroupin来调整它。Collaborator在这种情况下,尤其是CollaboratorGroup成员Collaborator piUserId
  2. 您可以只填写p:autoCompletewithList<String> groupIdList但在这种情况下,您必须为itemtip.

  3. 一个非常快速的解决方案是使用Primefaces autocomplete with POJO 和 String valueitemLabel="#{group.class.simpleName eq 'String' ? group : group.groupId}"中提到的。

    • 问题
      • 你必须关心NullPointerExceptions
      • View用逻辑填满你的。
      • 这不是一个非常灵活或动态的设计。
  4. 实施 3. 在itemLabel="#{bean.printGroupId(group)}"您可以完全控制逻辑的 bean 方法中。这就是我所做的。

    public String printGroupId(Object group) {
        if (group == null) return null;
        return (group instanceof String) ? (String) group : (group instanceof CollaboratorGroup) ? ((CollaboratorGroup) group).getGroupId() : null;
    }
    

    (不是最好的,只是给你一个想法。)

于 2018-07-27T02:25:52.250 回答
1

实现此目的的一种更简单的方法是:
覆盖 Pessoa Pojo 类中的toString()方法。这个 toString()应该只返回您想要显示的标签。
如果您使用此方法,则不需要转换器

例如:

public class Pessoa implements Serializable{

private String value;
private String label;

//Setter and getters

@Override
public void toString(){
return label;
}

}

然后你可以使用:

<p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}"
                completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}"
                var="pessoa" itemLabel="#{pessoa}" itemValue="#{pessoa.value}"/>

这是我目前使用和运作良好的方式。

于 2013-06-13T06:30:27.050 回答
-1
 ELContext elContext = FacesContext.getCurrentInstance().getELContext();
 ItemBean itemBean = (ItemBean) elContext.getELResolver().getValue(elContext, null, "itemBean");
 for(Item item : itemBean.getItems()){
     if(item.getId().getItemCode().equals(value)){
         return item;
     }
 }
于 2016-02-22T10:53:40.007 回答