Basierend auf Ihrem Fragenverlauf verwenden Sie JSF 2.x. Hier ist eine gezielte Antwort auf JSF 2.x. In JSF 1.x wären Sie gezwungen, Elementwerte / Beschriftungen in hässlichen SelectItem
Fällen zu verpacken . Dies wird in JSF 2.x glücklicherweise nicht mehr benötigt.
Grundlegendes Beispiel
Um Ihre Frage direkt zu beantworten, verwenden Sie einfach <f:selectItems>
deren value
Punkte für eine List<T>
Eigenschaft, die Sie während der (Post-) Konstruktion von Bean aus der DB beibehalten. Hier ist ein grundlegendes Kickoff-Beispiel unter der Annahme, dass es sich T
tatsächlich um a handelt String
.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{bean.names}" />
</h:selectOneMenu>
mit
@ManagedBean
@RequestScoped
public class Bean {
private String name;
private List<String> names;
@EJB
private NameService nameService;
@PostConstruct
public void init() {
names = nameService.list();
}
}
So einfach ist das. Tatsächlich werden die T
's toString()
verwendet, um sowohl die Dropdown-Elementbezeichnung als auch den Wert darzustellen. Wenn Sie also List<String>
keine Liste komplexer Objekte wie verwenden List<SomeEntity>
und die toString()
Methode der Klasse nicht überschrieben haben , werden sie com.example.SomeEntity@hashcode
als Elementwerte angezeigt. Siehe nächster Abschnitt, wie man es richtig löst.
Beachten Sie auch, dass die Bean für den <f:selectItems>
Wert nicht unbedingt dieselbe Bean sein muss wie die Bean für den <h:selectOneMenu>
Wert. Dies ist immer dann nützlich, wenn es sich bei den Werten tatsächlich um anwendungsweite Konstanten handelt, die Sie beim Start der Anwendung nur einmal laden müssen. Sie können es dann einfach zu einer Eigenschaft einer Bean mit Anwendungsbereich machen.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{data.names}" />
</h:selectOneMenu>
Komplexe Objekte als verfügbare Elemente
Wenn es sich T
um ein komplexes Objekt (eine Javabean) handelt, das beispielsweise User
die String
Eigenschaft hat name
, können Sie das var
Attribut verwenden, um die Iterationsvariable abzurufen, die Sie wiederum in itemValue
und / oder itemLabel
attribtues verwenden können (wenn Sie die weglassen itemLabel
, dann die label wird gleich dem Wert).
Beispiel 1:
<h:selectOneMenu value="#{bean.userName}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.name}" />
</h:selectOneMenu>
mit
private String userName;
private List<User> users;
@EJB
private UserService userService;
@PostConstruct
public void init() {
users = userService.list();
}
Oder wenn es eine Long
Eigenschaft hat, id
die Sie lieber als Elementwert festlegen möchten:
Beispiel 2:
<h:selectOneMenu value="#{bean.userId}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>
mit
private Long userId;
private List<User> users;
Komplexes Objekt als ausgewähltes Element
Wann immer Sie es auch auf eine T
Eigenschaft in der Bean setzen möchten und T
eine darstellen User
möchten, müssen Sie einen benutzerdefinierten Converter
Wert backen , der zwischen User
einer eindeutigen Zeichenfolgendarstellung konvertiert (die die id
Eigenschaft sein kann). Beachten Sie, dass das itemValue
muss das komplexe Objekt selbst darstellen, genau den Typ, der als Auswahlkomponente festgelegt werden muss value
.
<h:selectOneMenu value="#{bean.user}" converter="#{userConverter}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
mit
private User user;
private List<User> users;
und
@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);
}
}
}
(Bitte beachten Sie, dass das Converter
etwas hackig ist, um einen @EJB
in einen JSF-Konverter einspeisen zu können ; normalerweise hätte man es als kommentiert @FacesConverter(forClass=User.class)
, aber das erlaubt leider keine @EJB
Einspritzungen )
Vergessen Sie nicht , um sicher zu stellen , dass die komplexe Objektklasse hat equals()
und hashCode()
ordnungsgemäß umgesetzt werden , sonst JSF wird während machen nicht vorher ausgewählte Artikel zeigen (s), und Sie werden auf Gesicht einreichen Validierungsfehler: Wert nicht gültig ist .
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();
}
}
Komplexe Objekte mit einem generischen Konverter
Gehen Sie zu dieser Antwort: Implementieren Sie Konverter für Entitäten mit Java Generics .
Komplexe Objekte ohne benutzerdefinierten Konverter
Die JSF-Dienstprogrammbibliothek OmniFaces bietet einen speziellen Konverter, mit dem Sie komplexe Objekte verwenden können, <h:selectOneMenu>
ohne einen benutzerdefinierten Konverter erstellen zu müssen. Der SelectItemsConverter
wird einfach die Konvertierung basierend auf leicht verfügbaren Artikeln in durchführen <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>
Siehe auch: