2

转换器是否需要一个<h:selectOneMenu><p:selectOneMenu>任意用户创建的类作为其值?我的意思是,以下代码是否应该在没有转换器的情况下工作?

<p:selectOneMenu value="#{bean.language}">
    <f:selectItems value="#{bean.allLanguages}" />
</p:selectOneMenu>

@Named(value = "bean")
@ConversationScoped
public class Bean {

    private Language language; // appropriate getter and setter are present

    public List<SelectItem> getAllLanguages() {
        // populates a list of select items with Strings as item labels and Languages as item values
    }

}

我有一个与enum类型(语言)类似的代码,它工作得很好。但是当我用普通的 java 类替换类型时,我得到一个转换错误。

4

2 回答 2

1

您需要一个转换器,因为 JSF 默认假定字符串,这就是您编码它的方式。JSF 不知道如何将您的伪实体转换为字符串,反之亦然。

一些注意事项:

1. 您的getAsString方法定义了实体/POJO 的标识符,而不是 JSF(或其他)选择作为 itemLabel 获得的标识符。

2. 您的转换器可以使用这篇臭名昭著的文章挖掘数据库中的真实实体:

http://balusc.blogspot.de/2011/09/communication-in-jsf-20.html#ConvertingAndValidatingGETRequestParameters

您还可以将 CDI 注释与该“模式”一起使用。

3. 你value = "bean"是多余的,选择的 CDI 范围通常是@ViewScoped. 但是,您必须记住,如果不使用 Seam 3 或 Apache MyFaces CODI ,CDI @Named+ JSF就无法协同工作。@ViewScoped

于 2013-02-15T11:55:51.023 回答
1

如果您使用我编写的这个小类,则不需要转换器 :-) 它可以支持 selectOne 和 selecteMany 组件。它要求您的类的 toString() 提供对象的一对一唯一表示。如果您愿意,您可以替换 toString() 以外的方法名称,例如 toIDString()

要在 ManagedBean 中使用 ListBacker,请使用ListBacker<Type>您会使用的任何位置List<Type>

@ManagedBean
@RequestScoped
public class BackingBean {
    private ListBacker<User> users; // +getter +setter

    @PostConstruct
    public void init() {
        // fill it up from your DAO
        users = new ListBacker<User>(userDAO.find());
    }
    // Here's the payoff!  When you want to use the selected object, 
    // it is just available to you, with no extra database hits:
    User thisOneIsSelected = users.getSelectedItemAsObject();

    // or for multi-select components:
    List<User> theseAreSelected = users.getSelectedItemsAsObjects();
}

在您的 xhtml 文件中:

<p:selectOneMenu value="#{backingBean.users.selectedItem}">
    <f:selectItems value="#{backingBean.users.contents}" var="item" itemValue="#{item.value}" itemLabel="#{item.label}" />
</p:selectOneMenu>

ListBacker 类:

public class ListBacker<T extends AbstractEntityBase> {
    // Contains the String representation of an Entity's ID (a.k.a.
    // primary key) and the associated Entity object
    Map<String, T> contents = new LinkedHashMap<String, T>(); // LinkedHashMap defaults to insertion-order iteration.

    // These hold values (IDs), not labels (descriptions).
    String selectedItem; // for SelectOne list
    List<String> selectedItems; // for SelectMany list


    public class ListItem {
        private String value;
        private String label;


        public ListItem(String value, String label) {
            this.value = value;
            this.label = label;
        }

        public String getValue() {
            return value;
        }

        public String getLabel() {
            return label;
        }
    }


    public ListBacker() {}

    public ListBacker(List<T> lst) {
        put(lst);
    }


    public void clear() {
        contents.clear();
        selectedItem = null;
        if(selectedItems != null) {
            selectedItems.clear();
        }
    }

    public List<ListItem> getContents() {
        return convert(contents);
    }

    public String getSelectedItem() {
        return selectedItem;
    }

    public void setSelectedItem(String selectedItem) {
        this.selectedItem = selectedItem;
    }

    public List<String> getSelectedItems() {
        return selectedItems;
    }

    public void setSelectedItems(List<String> selectedItems) {
        this.selectedItems = selectedItems;
    }

    public T getSelectedItemAsObject() {
        return convert(selectedItem);
    }

    public List<T> getSelectedItemsAsObjects() {
        return convert(selectedItems);
    }


    public void put(T newItem) {
        contents.put(newItem.toString(), newItem);
    }

    public void put(List<T> newItems) {
        for (T t : newItems) {
            put(t);
        }
    }


    // PROTECTED (UTILITY) METHODS

    protected List<ListItem> convert(Map<String, T> maps) {
        List<ListItem> lst = new ArrayList<ListItem>();
        for (Entry<String, T> e : maps.entrySet()) {
            lst.add(new ListItem(e.getKey(), e.getValue().desc()));
        }
        return lst;
    }

    protected List<T> convert(List<String> ids) {
        List<T> lst = new ArrayList<T>();
        for (String id : ids) {
            lst.add(convert(id));
        }
        return lst;
    }

    protected T convert(String id) {
        return contents.get(id);
    }

}

我有两个 toString() 实现,一个用于 JPA 实体:

public abstract class AbstractEntityBase {
    @Override
    public final String toString() {
        return String.format("%s[id=%s]", getClass().getSimpleName(), getIdForToString().toString());
    }
    /**
    * Return the entity's ID, whether it is a field or an embedded ID class..
    * @return ID Object
    */
    protected abstract Object getIdForToString();
}

一个用于 JPA EmbeddedId:

public abstract class CompositeKeyBase {
    @Override
    public final String toString() {
        return String.format("%s[id=%s]", getClass().getSimpleName(), getIdForToString());
    }

    /**
     * Supports the class's toString() method, which is required for ListBacker.
     * Compile a string of all ID fields, with this format:
     * fieldName=StringVALUE,field2=STRINGvAlUE2,...,fieldx=stringvalue <br />
     * Recommended: start with Eclipse's "generate toString()" utility and move it to getIdForToString()
     * @return a 1-to-1 String representation of the composite key
     */
    public abstract String getIdForToString();
}

getIdForToString() 的示例实现,用于具有一个 Id 字段的实体:

@Override
public Object getIdForToString() {
    return userID;
}

getIdForToString() 的示例实现,用于具有两个字段的 EmbeddedId:

@Override
public String getIdForToString() {
    return "userID=" + userID + ",roleID=" + roleID;
}
于 2014-02-25T00:38:24.357 回答