既然您在谈论 Facelets,我将假设 JSF 2.x。
首先,HTML 是一个完整的字符串。 JSF 生成 HTML。默认情况下,非String Java 对象通过toString() 方法转换为它们的String 表示,同时JSF 生成HTML。要在这些 Java 对象和 String 之间正确转换,您需要一个 Converter。
我假设您的 Country 对象已经具有 equals() 方法 properly implemented,否则验证稍后将失败并显示“验证错误:值无效”,因为所选对象在测试时未返回 true equals() 用于任何可用的项目。
我还将对命名进行一些更改,因为 #{country} 是一个令人困惑的托管 bean 名称,因为它显然不代表 Country 类的实例。我将其称为Data,它应该包含应用程序范围的数据。
@ManagedBean
@ApplicaitionScoped
public class Data {
private static final List<Country> COUNTRIES = populateItSomehow();
public List<Country> getCountries() {
return COUNTRIES;
}
// ...
}
我假设Country 类有两个属性code 和name。我假设接收所选国家/地区的托管 bean 具有 private Country country 属性。在您的<f:selectItems> 中,您需要遍历#{data.countries} 并将国家对象指定为项目值,将国家名称指定为项目标签。
<h:selectOneMenu value="#{bean.country}">
<f:selectItems value="#{data.countries}" var="country" itemValue="#{country}" itemLabel="#{country.name}" />
</h:selectOneMenu>
现在,您需要为 Country 类创建一个 Converter。我们将根据每个国家/地区唯一的国家/地区代码进行转换(对吗?)。在getAsString() 中,您实现了将Java 对象转换为要在HTML 中使用的唯一字符串表示形式的代码。在getAsObject() 中,您实现了将唯一的 HTML 字符串表示形式转换回 Java 对象的代码。
@FacesConverter(forClass=Country.class)
public class CountryConverter implements Converter {
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return (value instanceof Country) ? ((Country) value).getCode() : null;
}
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null) {
return null;
}
Data data = context.getApplication().evaluateExpressionGet(context, "#{data}", Data.class);
for (Country country : data.getCountries()) {
if (country.getCode().equals(value)) {
return country;
}
}
throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to Country", value)));
}
}
@FacesConverter 将在 JSF 中自动注册它,并且 JSF 将在遇到 Country 类型的值表达式时自动使用它。最终,您最终将国家代码作为项目值,将国家名称作为项目标签。 JSF 将在提交表单时将提交的国家代码转换回完整的Country 对象。
在 JSF 1.x 中,原理并没有太大的不同。在此博客中,您可以找到两个基本的启动示例:Objects in h:selectOneMenu。