我正在创建一个 Web 应用程序,您必须在其中从数据库中读取对象/实体列表并将其填充到 JSF 中 <h:selectOneMenu>
.我无法对此进行编码。谁能告诉我怎么做?
我知道如何获得 List<User>
从数据库。我需要知道的是,如何在 <h:selectOneMenu>
中填充此列表.
<h:selectOneMenu value="#{bean.name}">
...?
</h:selectOneMenu>
最佳答案
根据您的问题历史记录,您使用的是 JSF 2.x。所以,这是一个针对 JSF 2.x 的答案。在 JSF 1.x 中,您将被迫用丑陋的 SelectItem
包装项目值/标签。实例。幸运的是,在 JSF 2.x 中不再需要了。
基本示例
要直接回答您的问题,只需使用 <f:selectItems>
谁的value
指向 List<T>
在 bean 的(后期)构造期间从数据库中保留的属性。这是一个基本的启动示例,假设 T
实际上代表一个String
.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{bean.names}" />
</h:selectOneMenu>
与
@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)
}
就这么简单。实际上,T
的 toString()
将用于表示下拉项标签和值。所以,当你不是 List<String>
使用复杂对象列表,如 List<SomeEntity>
而且你还没有覆盖类'toString()
方法,那么你会看到 com.example.SomeEntity@hashcode
作为项目值。请参阅下一节如何正确解决它。
另请注意 <f:selectItems>
的 bean value 不一定需要与 <h:selectOneMenu>
的 bean 相同值(value)。当值实际上是应用程序范围的常量时,这很有用,您只需在应用程序启动期间加载一次。然后,您可以将其设为应用程序作用域 bean 的属性。
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{data.names}" />
</h:selectOneMenu>
作为可用项的复杂对象
每当T
涉及复杂对象(javabean),例如User
它有一个 String
name
的属性(property), 那么你可以使用 var
属性来获取迭代变量,您又可以在 itemValue
中使用它和/或 itemLabel
属性(如果省略 itemLabel
,则标签将与值相同)。
示例#1:
<h:selectOneMenu value="#{bean.userName}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.name}" />
</h:selectOneMenu>
与
private String userName;
private List<User> users;
@EJB
private UserService userService;
@PostConstruct
public void init() {
users = userService.list();
}
// ... (getters, setters, etc)
或者当它有一个 Long
属性(property)id
您希望将其设置为项目值:
示例 #2:
<h:selectOneMenu value="#{bean.userId}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>
与
private Long userId;
private List<User> users;
// ... (the same as in previous bean example)
作为选定项的复杂对象
每当您想将其设置为 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>
与
private User user;
private List<User> users;
// ... (the same as in previous bean example)
和
@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);
}
}
}
(请注意 Converter
有点 hacky,以便能够在 JSF 转换器中注入(inject) @EJB
;通常人们会将其注释为 @FacesConverter(forClass=User.class)
、but that unfortunately doesn't allow @EJB
injections)
不要忘记确保复杂对象类具有 equals()
and hashCode()
properly implemented ,否则 JSF 将在渲染期间无法显示预选项目,并且您将在提交面上 Validation Error: Value is not valid .
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();
}
}
具有通用转换器的复杂对象
前往此答案:Implement converters for entities with 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>
另见:
关于database - 如何填充 h :selectOneMenu from database? 的选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6848970/