Исходя из истории ваших вопросов, вы используете JSF 2.x. Итак, вот целевой ответ JSF 2.x. В JSF 1.x вы будете вынуждены оборачивать значения / метки элементов в уродливые SelectItem
экземпляры. К счастью, в JSF 2.x это больше не требуется.
Базовый пример
Чтобы ответить на ваш вопрос напрямую, просто используйте <f:selectItems>
, чье value
указывает на свойство List<T>
, которое вы сохраняете в БД во время (пост) построения бина. Вот базовый пример начала, предполагая, что 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>
не обязательно должен быть тем же компонентом, что и компонент для значения <h:selectOneMenu>
. Это полезно всякий раз, когда значения на самом деле являются константами всего приложения, которые вам нужно загрузить только один раз при запуске приложения. Затем вы можете просто сделать его свойством bean-объекта приложения.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{data.names}" />
</h:selectOneMenu>
Сложные объекты как доступные предметы
Всякий раз, когда T
касается сложного объекта (javabean), такого как User
, который имеет свойство String
name
, тогда вы можете использовать атрибут 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
свойство 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
в компоненте, а 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
немного хакерский для того, чтобы иметь возможность вводить @EJB
в конвертере JSF; обычно его можно аннотировать как @FacesConverter(forClass=User.class)
, , но это к сожалению, не позволяет @EJB
инъекции )
Не забудьте убедиться, что класс сложных объектов имеет equals()
и hashCode()
, правильно реализованные , в противном случае JSF во время рендеринга не сможет показать предварительно выбранные элементы, и вы на лице отправки Ошибка проверки: значение недействительно .
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();
}
}
Сложные объекты с универсальным конвертером
Ответьте на этот ответ: Реализуйте конвертеры для сущностей с помощью 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>
Смотри также: