如何从数据库中填充h:selectOneMenu的选项?

Ill*_*lep 69 database jsf selectonemenu

我正在创建一个Web应用程序,您必须从DB中读取对象/实体列表并在JSF中填充它<h:selectOneMenu>.我无法对此进行编码.有人可以告诉我该怎么做吗?

我知道如何List<User>从数据库中获取数据.我需要知道的是,如何填充此列表<h:selectOneMenu>.

<h:selectOneMenu value="#{bean.name}">
    ...?
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)

Bal*_*usC 171

根据您的问题历史记录,您使用的是JSF 2.x. 所以,这是一个JSF 2.x目标答案.在JSF 1.x中,您将被迫在丑陋的SelectItem实例中包装项值/标签.幸运的是,在JSF 2.x中不再需要这个.


基本的例子

要直接回答您的问题,只需在bean(post)构造期间使用<f:selectItems>其对数据库保留valueList<T>属性.这是一个基本的启动示例,假设T实际上代表了一个String.

<h:selectOneMenu value="#{bean.name}">
    <f:selectItems value="#{bean.names}" />
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)

@ManagedBean
@RequestScoped
public class Bean {

    private String name;
    private List<String> names; 

    @EJB
    private NameService nameService;

    @PostConstruct
    public void init() {
        names = nameService.list();
    }

    // ... (getters, setters, etc)
}
Run Code Online (Sandbox Code Playgroud)

就那么简单.实际上,T's' toString()将用于表示下拉项标签和值.因此,当您不List<String>使用复杂对象列表而List<SomeEntity>没有覆盖类的toString()方法时,您会看到com.example.SomeEntity@hashcode项目值.请参阅下一节如何正确解决它.

另请注意,bean的<f:selectItems>值不一定需要与bean的bean相同<h:selectOneMenu>.每当值实际上是应用程序范围的常量时,这非常有用,您只需在应用程序启动期间加载一次.然后,您可以将其设置为应用程序范围bean的属性.

<h:selectOneMenu value="#{bean.name}">
    <f:selectItems value="#{data.names}" />
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)

复杂对象作为可用项

只要T关注一个复杂的对象(一个JavaBean),如User其中有一个String财产name,那么你可以使用var属性来获取迭代变量的保持,你又可以在使用itemValue和/或itemLabelattribtues(如果省略itemLabel,那么label变得与值相同).

示例#1:

<h:selectOneMenu value="#{bean.userName}">
    <f:selectItems value="#{bean.users}" var="user" itemValue="#{user.name}" />
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)

private String userName;
private List<User> users;

@EJB
private UserService userService;

@PostConstruct
public void init() {
    users = userService.list();
}

// ... (getters, setters, etc)
Run Code Online (Sandbox Code Playgroud)

或者当它具有您希望设置为项值的Long属性时id:

示例#2:

<h:selectOneMenu value="#{bean.userId}">
    <f:selectItems value="#{bean.users}" var="user" itemValue="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)

private Long userId;
private List<User> users;

// ... (the same as in previous bean example)
Run Code Online (Sandbox Code Playgroud)

复杂对象作为选定项

无论何时你想将它设置T为bean中的属性并T表示一个属性User,那么你需要烘焙一个自定义的Converter转换User和一个唯一的字符串表示(可以是id属性).请注意,itemValue必须表示复杂对象本身,正好是需要设置为选择组件的类型value.

<h:selectOneMenu value="#{bean.user}" converter="#{userConverter}">
    <f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)

private User user;
private List<User> users;

// ... (the same as in previous bean example)
Run Code Online (Sandbox Code Playgroud)

@ManagedBean
@RequestScoped
public class UserConverter implements Converter {

    @EJB
    private UserService userService;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
        if (submittedValue == null || submittedValue.isEmpty()) {
            return null;
        }

        try {
            return userService.find(Long.valueOf(submittedValue));
        } catch (NumberFormatException e) {
            throw new ConverterException(new FacesMessage(String.format("%s is not a valid User ID", submittedValue)), e);
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
        if (modelValue == null) {
            return "";
        }

        if (modelValue instanceof User) {
            return String.valueOf(((User) modelValue).getId());
        } else {
            throw new ConverterException(new FacesMessage(String.format("%s is not a valid User", modelValue)), e);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

(请注意,Converter为了能够注入@EJBJSF转换器,有点hacky ;通常会注释它@FacesConverter(forClass=User.class),但遗憾的是不允许@EJB注入)

不要忘记,以确保复杂的对象类equals()hashCode()正确实施,否则,JSF将在呈现无法显示预选项目(S),你会在提交脸验证错误:值无效.

public class User {

    private Long id;

    @Override
    public boolean equals(Object other) {
        return (other != null && getClass() == other.getClass() && id != null)
            ? id.equals(((User) other).id)
            : (other == this);
    }

    @Override
    public int hashCode() {
        return (id != null) 
            ? (getClass().hashCode() + id.hashCode())
            : super.hashCode();
    }

}
Run Code Online (Sandbox Code Playgroud)

具有通用转换器的复杂对象

回答这个问题:为使用Java Generics的实体实现转换器.


没有自定义转换器的复杂对象

JSF实用程序库OmniFaces提供了一个特殊的转换器,允许您使用复杂的对象,<h:selectOneMenu>而无需创建自定义转换器.将SelectItemsConverter只会做基于转换现成的项目<f:selectItem(s)>.

<h:selectOneMenu value="#{bean.user}" converter="omnifaces.SelectItemsConverter">
    <f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)

也可以看看:


Nay*_*kar 8

查看页

<h:selectOneMenu id="selectOneCB" value="#{page.selectedName}">
     <f:selectItems value="#{page.names}"/>
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)

支持bean

   List<SelectItem> names = new ArrayList<SelectItem>();

   //-- Populate list from database

   names.add(new SelectItem(valueObject,"label"));

   //-- setter/getter accessor methods for list
Run Code Online (Sandbox Code Playgroud)

要显示特定的选定记录,它必须是列表中的值之一.