我正在从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的默认转换器?有没有更简单的方法来实现这个转换器?
答案 0 :(得分:12)
您不应该使用List<SelectItem>
来提供它。你应该用List<Pessoa>
喂它。你也不应该专注于转换SelectItem
。您应该专注于转换项目值Pessoa
。 SelectItem
是旧JSF 1.x年代的遗留物。在JSF 2.x中,由于视图中的var
,itemValue
和itemLabel
属性,这不再是必需的。这样可以使bean保持清洁,不会出现特定于视图的混乱。
只有在您使用Converter
且itemValue="#{pessoa}"
引用#{modeloPopupBuscaPessoa.itemSelecionado}
属性时才需要Pessoa
。然后,您应该getAsString()
将Pessoa
转换为其唯一的String
表示形式(以便以HTML格式打印),并getAsObject()
从String
转换为{ {1}}(以便可以在bean属性中设置)。
但是,如果Pessoa
是#{pessoa.value}
且String
也是#{modeloPopupBuscaPessoa.itemSelecionado}
,那么您应该使用String
并删除itemValue="#{pessoa.value}"
完全。
答案 1 :(得分: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;
}
}
答案 2 :(得分:1)
实现这一目标的另一种最简单方法:
覆盖Pessoa Pojo类中的 toString()方法。
此toString()应仅返回您要显示的标签
如果您使用此方法,那么 NO NEED for converter 。
例如:
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}"/>
这是我目前使用和运作良好的方式。
答案 3 :(得分:0)
我遇到了同样的问题,作者在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.groupId
是String
,而itemLabel
用来对{{1} }设置为String groupId
,而value="#{collaborator.groupId}"
产生的CollaboratorGroup
由List
生成。
completeMethod="#{bean.completeGroup}"
中的成员Model
更改为groupId
来调整CollaboratorGroup
。在这种情况下,尤其是Collaborator
具有成员CollaboratorGroup
的情况。您可以只用Collaborator piUserId
填充p:autoComplete
,但是在这种情况下,您必须为List<String> groupIdList
找到不同的解决方案。
一种非常快速的解决方案是使用Primefaces autocomplete with POJO and String value中提到的itemtip
。
itemLabel="#{group.class.simpleName eq 'String' ? group : group.groupId}"
。NullPointerExceptions
。实现3.在bean方法View
中,您可以完全控制逻辑。这就是我所做的。
itemLabel="#{bean.printGroupId(group)}"
(不是最好的,只是给您一个主意。)
答案 4 :(得分:-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;
}
}