当前位置: 首页 > 知识库问答 >
问题:

h:为所有实体选择一个菜单通用转换器,无需反复调用DB

冯宏恺
2023-03-14

我想从中获取选定的对象

我的第一个问题是,所有类型的实体都有通用的转换器吗?我不想再为其他实体编写另一个转换器。我的第二个问题是,有没有一种方法可以在没有任何转换器的情况下获取选定对象?我不想一次又一次地给DB打电话。

我有一辆Car实体,拥有idname属性。


共有3个答案

南门欣怡
2023-03-14

我刚刚使用了@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;
    }
}
蒙墨竹
2023-03-14

似乎应该有一个通用转换器,这样您就可以轻松地从下拉列表中选择对象,而无需为每种对象类型编写转换器,也无需调用数据库(如大多数示例所示)。但据我所知并没有,所以我编写了自己的转换器来实现这一点。请注意,转换器希望对象具有一个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;
    }
}
陶飞鸿
2023-03-14

我的第一个问题是,所有类型的实体都有通用的转换器吗?

这在标准JSF中确实不存在。JSF实用程序库OmniFaces在其分类中有这样一个转换器,OmniFaces。选择项目转换器。您只需将其声明为UISelectOneUISelectMany组件的转换器,如下所示:

<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">

另请参见SelectItemsConvertershowcase。此转换器依赖于对象项的toString()。还有另一个,那就是omnifaces。选择ItemsIndexConverter,它依赖于选项列表中对象项的索引,另请参见SelectItemsIndexConvertershowcase。

目前没有其他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,但我想知道在这种情况下最好的做法是什么。

  • 我正在使用选择一个菜单从