h:为所有实体选择selectOneMenu通用转换器而不再一次调用DB

时间:2013-04-22 14:02:00

标签: jsf jsf-2 javabeans converter selectonemenu

我想从<h:selectOneMenu>获取所选对象,但问题是我找不到所有类型实体的通用转换器。

我的第一个问题是,是否有适用于所有类型实体的通用转换器?我不想再为其他实体编写另一个转换器。我的第二个问题是,有没有办法获得没有任何转换器的选定对象?我不想一次又一次地调用数据库。

我有一个Car实体,其idname属性。

3 个答案:

答案 0 :(得分:3)

  

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

标准JSF中确实不存在这种情况。 JSF实用程序库OmniFaces在其组合omnifaces.SelectItemsConverter中有一个这样的转换器。您需要做的就是将其声明为UISelectOneUISelectMany组件的转换器,如下所示:

<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;
    }
}