我想从中获取选定的对象
我的第一个问题是,所有类型的实体都有通用的转换器吗?我不想再为其他实体编写另一个转换器。我的第二个问题是,有没有一种方法可以在没有任何转换器的情况下获取选定对象?我不想一次又一次地给DB打电话。
我有一辆
Car
实体,拥有id
和name
属性。
我刚刚使用了@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;
}
}
似乎应该有一个通用转换器,这样您就可以轻松地从下拉列表中选择对象,而无需为每种对象类型编写转换器,也无需调用数据库(如大多数示例所示)。但据我所知并没有,所以我编写了自己的转换器来实现这一点。请注意,转换器希望对象具有一个getId()
方法,该方法返回某种类型的唯一ID。如果不这样做,它就会失败。如果需要以编程方式确定要用作键的方法的名称,可以向getMethodName()
添加逻辑。请注意,我们在项目中使用Seam。如果不使用Seam,则可以删除无选择值部分以及类上的三个注释。
这段代码的灵感来自: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;
}
}
我的第一个问题是,所有类型的实体都有通用的转换器吗?
这在标准JSF中确实不存在。JSF实用程序库OmniFaces在其分类中有这样一个转换器,OmniFaces。选择项目转换器
。您只需将其声明为UISelectOne
或UISelectMany
组件的转换器,如下所示:
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
另请参见SelectItemsConverter
showcase。此转换器依赖于对象项的toString()
。还有另一个,那就是omnifaces。选择ItemsIndexConverter
,它依赖于选项列表中对象项的索引,另请参见SelectItemsIndexConverter
showcase。
目前没有其他JSF组件/实用程序库提供相同的功能。
第二个问题是,有没有一种方法可以在没有任何转换器的情况下获得选定的对象?
不需要。只需使用OmniFaces,这样你就不需要创建一个点击DB的自定义转换器。或者,如果你想做得过火,可以为
如何从数据库中填充h:selectOneMenu的选项
我想从“选择一个”菜单中选择自定义对象。它既不显示错误也不显示值。怎么办?请帮帮我。提前谢谢。 现在我在getAsObject的这一行看到空指针异常: 这是我的xhtml文档 这是我的管理豆类。 这是我的currencyConverter类代码:
问题内容: 我正在编写我的第一个Java EE 6 Web应用程序作为学习练习。我没有使用框架,只有JPA 2.0,EJB 3.1和JSF 2.0。 我有一个自定义转换器,可以将存储在SelectOne组件中的JPA实体转换回实体。我正在使用InitialContext.lookup获取对会话Bean的引用以查找相关实体。 我想创建一个通用的实体转换器,所以不必为每个实体创建一个转换器。我以为我会
我想从选择一个菜单中选择一个自定义对象。它既不显示错误也不显示值。我该怎么办? 我的xhtml文档: 我的管理Bean类:
问题内容: 我正在尝试更改select option边界,但是无法做到这一点,我已经尝试了很多次,但是找不到合适的解决方案。我已经附上了屏幕截图。 问题答案: 选择的下拉列表是所谓的ShadowDOM的一部分。在当前的CSS规范第3级中,无法定位大多数ShadowDOM元素。您可以在此处阅读有关ShadowDOM的规范,尽管关于所需内容的内容并不多。 Chrome有一些专有的选择器可以更改某些 s
我在表中显示了页面列表。每个页面都有属性主页,我希望在datatable中有一列单选按钮绑定到此属性,并且用户只能检查一个值。如何在服务器端获取此值? 我看到了一些类似以下的例子:http://jforum.icesoft.org/JForum/posts/list/14157.page,但我想知道在这种情况下最好的做法是什么。
我正在使用选择一个菜单从