我想从中获取选定的对象<h:selectOneMenu>
,但问题是我找不到适用于所有类型实体的任何通用转换器。
我的第一个问题是,是否有适用于所有类型实体的通用转换器?我不想再次为每个其他实体编写另一个转换器。我的第二个问题是,有没有办法在没有任何转换器的情况下获得选定的对象?我不想一次又一次地调用数据库。
我有一个具有和属性的Car
实体。id
name
我想从中获取选定的对象<h:selectOneMenu>
,但问题是我找不到适用于所有类型实体的任何通用转换器。
我的第一个问题是,是否有适用于所有类型实体的通用转换器?我不想再次为每个其他实体编写另一个转换器。我的第二个问题是,有没有办法在没有任何转换器的情况下获得选定的对象?我不想一次又一次地调用数据库。
我有一个具有和属性的Car
实体。id
name
我的第一个问题是,是否有适用于所有类型实体的通用转换器?
这在标准 JSF 中确实不存在。JSF 实用程序库OmniFaces在其分类中有这样一个转换器,omnifaces.SelectItemsConverter
. 您需要做的就是将其声明为一个UISelectOne
或UISelectMany
组件的转换器,如下所示:
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
另请SelectItemsConverter
参阅陈列柜。此转换器依赖于toString()
对象项的 。还有另一个, the ,它依赖于选项列表中对象项的索引,另请omnifaces.SelectItemsIndexConverter
参见showcase。SelectItemsIndexConverter
当前没有其他 JSF 组件/实用程序库提供相同的功能。
第二个问题是,有没有办法在没有任何转换器的情况下获得选定的对象?
不,只需使用 OmniFaces 即可,这样您就无需创建自定义转换器来访问数据库。或者,如果您想做得过火,请创建一个自定义渲染器<h:selectOneMenu>
,将项目索引渲染为选项值并能够将其设置为模型值,但这比简单的转换器要多得多,您仍然需要做一些额外的工作是为了根据索引从列表中获取所需的对象——这没有任何意义。
似乎应该有一个通用转换器,以便您可以轻松地从下拉列表中选择对象,而无需为每种对象类型编写转换器,也无需调用数据库(如大多数示例所示)。但是我不知道,所以我编写了自己的转换器来做到这一点。请注意,转换器希望对象具有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;
}
}
我刚刚采用了@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;
}
}