我想从<h:selectOneMenu>
获取所选对象,但问题是我找不到所有类型实体的通用转换器。
我的第一个问题是,是否有适用于所有类型实体的通用转换器?我不想再为其他实体编写另一个转换器。我的第二个问题是,有没有办法获得没有任何转换器的选定对象?我不想一次又一次地调用数据库。
我有一个Car
实体,其id
和name
属性。
答案 0 :(得分:3)
我的第一个问题是,是否有适用于所有类型实体的通用转换器?
标准JSF中确实不存在这种情况。 JSF实用程序库OmniFaces在其组合omnifaces.SelectItemsConverter
中有一个这样的转换器。您需要做的就是将其声明为UISelectOne
或UISelectMany
组件的转换器,如下所示:
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
另见the SelectItemsConverter
showcase。此转换器依赖于对象项的toString()
。另外还有一个omnifaces.SelectItemsIndexConverter
,它依赖于选项列表中对象项的索引,另请参阅the SelectItemsIndexConverter
showcase。
目前还没有其他JSF组件/实用程序库提供相同的功能。
第二个问题是,有没有办法在没有任何转换器的情况下获取所选对象?
没有。只需使用OmniFaces,就可以不需要创建一个可以访问数据库的自定义转换器。或者,如果你想要超越,为<h:selectOneMenu>
创建一个自定义渲染器,它将项目索引呈现为选项值,并且能够将其设置为模型值,但这比简单的转换器还要多得多,而且你' d仍然需要做一些额外的工作,以便根据索引从列表中获取所需的对象 - 这没有任何意义。
答案 1 :(得分:1)
似乎应该有一个通用转换器,以便您可以轻松地从下拉列表中选择对象,而无需为每个对象类型编写转换器,也无需调用数据库(如大多数示例所示)。但我不知道,所以我写了自己的转换器来做到这一点。请注意,转换器期望对象具有getId()
方法,该方法返回某种唯一ID。如果没有,它将失败。如果需要确定要以编程方式用作键的方法的名称,可以向getMethodName()
添加逻辑。请注意,我们在项目中使用Seam。如果您不使用Seam,则可能会删除NO_SELECTION_VALUE部分以及该类上的三个注释。
此代码的灵感来自:http://arjan-tijms.omnifaces.org/2011/12/automatic-to-object-conversion-in-jsf.html
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectItem;
import javax.faces.component.UISelectItems;
import javax.faces.context.FacesContext;
import javax.faces.convert.ConverterException;
import javax.faces.model.SelectItem;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.faces.Converter;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
/**
* @author: Jason Wheeler
* @description Converter for lists (SelectOneMenu, SelectManyMenu, etc)
* @created: 09/05/2013
*/
@Name("listConverter")
@BypassInterceptors
@Converter
public class ListConverter implements javax.faces.convert.Converter {
private String NO_SELECTION_VALUE = "org.jboss.seam.ui.NoSelectionConverter.noSelectionValue";
@Override
public String getAsString(FacesContext facesContext, UIComponent component, Object obj) {
if (obj == null) {
return NO_SELECTION_VALUE;
} else {
try {
Method method = obj.getClass().getMethod(getMethodName(obj));
return String.valueOf(method.invoke(obj));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public String getMethodName(Object obj) {
return "getId";
}
@Override
public Object getAsObject(FacesContext facesContext, UIComponent component, String val) throws ConverterException {
if (val == null) {
return null;
} else if (val.equals(NO_SELECTION_VALUE)) {
return null;
} else {
for (SelectItem item : getSelectItems(component)) {
if (val.equals(getAsString(facesContext, component, item.getValue()))) {
return item.getValue();
}
}
return null;
}
}
protected Collection<SelectItem> getSelectItems(UIComponent component) {
Collection<SelectItem> collection = new ArrayList<SelectItem>();
for (UIComponent child : component.getChildren()) {
if (child instanceof UISelectItem) {
UISelectItem ui = (UISelectItem) child;
SelectItem item = (SelectItem) ui.getValue();
collection.add(item);
} else if (child instanceof UISelectItems) {
UISelectItems ui = (UISelectItems) child;
Object value = ui.getValue();
collection.addAll((Collection<SelectItem>) value);
}
}
return collection;
}
}
答案 2 :(得分:0)
我刚刚使用了@Bigwheels代码,对JSF 2.0进行了一些更改并解决了我的问题:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectItem;
import javax.faces.component.UISelectItems;
import javax.faces.context.FacesContext;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
import javax.faces.model.SelectItem;
import javax.persistence.Id;
@FacesConverter("selectItemConverter")
public class SelectItemConverter implements javax.faces.convert.Converter {
private String NO_SELECTION_VALUE = "SELECIONE";
@Override
public String getAsString(FacesContext facesContext, UIComponent component, Object obj) {
if (obj == null) {
return NO_SELECTION_VALUE;
} else {
try {
Method method = obj.getClass().getMethod(getIdMethodName(obj));
return String.valueOf(method.invoke(obj));
} catch (Exception e) {
throw new ConverterException(e);
}
}
}
public String getIdMethodName(Object obj) {
try {
Field[] fieldList = obj.getClass().getDeclaredFields();
Field id = null;
for (Field field : fieldList) {
if(field.isAnnotationPresent(Id.class)) {
id = field;
break;
}
}
return "get" + capitalize(id.getName());
} catch(Exception ex) {
throw new ConverterException(ex);
}
}
private String capitalize(final String line) {
return Character.toUpperCase(line.charAt(0)) + line.substring(1);
}
@Override
public Object getAsObject(FacesContext facesContext, UIComponent component, String val) throws ConverterException {
if (val == null) {
return null;
} else if (val.equals(NO_SELECTION_VALUE)) {
return null;
} else {
for (Object item : getSelectItems(component)) {
if (val.equals(getAsString(facesContext, component, item))) {
return item;
}
}
return null;
}
}
protected List getSelectItems(UIComponent component) {
List list = new ArrayList();
for (UIComponent child : component.getChildren()) {
if (child instanceof UISelectItem) {
UISelectItem ui = (UISelectItem) child;
SelectItem item = (SelectItem) ui.getValue();
list.add(item);
} else if (child instanceof UISelectItems) {
UISelectItems ui = (UISelectItems) child;
Object value = ui.getValue();
list.addAll((Collection<SelectItem>) value);
}
}
return list;
}
}