在 p:selectOneMenu 中使用带有 null/空值的“请选择”f:selectItem

2024-01-24

我正在填充一个<p:selectOneMenu/>来自数据库如下。

<p:selectOneMenu id="cmbCountry" 
                 value="#{bean.country}"
                 required="true"
                 converter="#{countryConverter}">

    <f:selectItem itemLabel="Select" itemValue="#{null}"/>

    <f:selectItems var="country"
                   value="#{bean.countries}"
                   itemLabel="#{country.countryName}"
                   itemValue="#{country}"/>

    <p:ajax update="anotherMenu" listener=/>
</p:selectOneMenu>

<p:message for="cmbCountry"/>

加载此页面时默认选择的选项是,

<f:selectItem itemLabel="Select" itemValue="#{null}"/>

转换器:

@ManagedBean
@ApplicationScoped
public final class CountryConverter implements Converter {

    @EJB
    private final Service service = null;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        try {
            //Returns the item label of <f:selectItem>
            System.out.println("value = " + value);

            if (!StringUtils.isNotBlank(value)) {
                return null;
            } // Makes no difference, if removed.

            long parsedValue = Long.parseLong(value);

            if (parsedValue <= 0) {
                throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "", "Message"));
            }

            Country entity = service.findCountryById(parsedValue);

            if (entity == null) {
                throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_WARN, "", "Message"));
            }

            return entity;
        } catch (NumberFormatException e) {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "", "Message"), e);
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return value instanceof Country ? ((Country) value).getCountryId().toString() : null;
    }
}

当菜单中的第一个项目由<f:selectItem>选择并提交表格,然后value获得在getAsObject()方法是Select这是的标签<f:selectItem>- 列表中的第一项直观上根本不是预期的。

当。。。的时候itemValue的属性<f:selectItem>然后设置为空字符串,它会抛出java.lang.NumberFormatException: For input string: "" in the getAsObject()方法,即使异常被精确捕获并注册ConverterException.

这似乎在某种程度上起作用,当return的声明getAsString()更改自

return value instanceof Country?((Country)value).getCountryId().toString():null;

to

return value instanceof Country?((Country)value).getCountryId().toString():"";

null被替换为空字符串,但当有问题的对象是时返回空字符串null,反过来又会产生另一个问题,如图所示here https://stackoverflow.com/q/23725629/1391249.

如何让这样的转换器正常工作呢?

Also tried with org.omnifaces.converter.SelectItemsConverter but it made no difference.


当选择项值为null,那么 JSF 将不会渲染<option value>, 但只有<option>。因此,浏览器将提交选项的标签。这在中明确规定HTML规范 http://www.w3.org/TR/html401/interact/forms.html#adef-value-OPTION(强调我的):

value = cdata [CS]

该属性指定控件的初始值。如果未设置此属性,则初始值将设置为 OPTION 元素的内容。

您还可以通过查看 HTTP 流量监视器来确认这一点。您应该看到正在提交的选项标签。

您需要将选择项值设置为空字符串。然后 JSF 将渲染一个<option value="">。如果您使用转换器,那么您实际上应该返回一个空字符串""当值为时从转换器null。这在《中》中也有明确规定Converter#getAsString() http://docs.oracle.com/javaee/6/api/javax/faces/convert/Converter.html#getAsString%28javax.faces.context.FacesContext,%20javax.faces.component.UIComponent,%20java.lang.Object%29javadoc(强调我的):

getAsString

...

返回:如果值为 null,则返回零长度字符串,否则为转换结果

所以如果你使用<f:selectItem itemValue="#{null}">与这样的转换器相结合,然后<option value="">将被渲染,浏览器将仅提交一个空字符串而不是选项标签。

至于处理空字符串提交值(或null),你实际上应该让你的转换器将这个责任委托给required="true"属性。所以,当传入value is null或空字符串,那么你应该返回null立即地。基本上您的实体转换器应按如下方式实现:

@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
    if (value == null) {
        return ""; // Required by spec.
    }

    if (!(value instanceof SomeEntity)) {
        throw new ConverterException("Value is not a valid instance of SomeEntity.");
    }

    Long id = ((SomeEntity) value).getId();
    return (id != null) ? id.toString() : "";
}

@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
    if (value == null || value.isEmpty()) {
        return null; // Let required="true" do its job on this.
    }

    if (!Utils.isNumber(value)) {
        throw new ConverterException("Value is not a valid ID of SomeEntity.");
    }

    Long id = Long.valueOf(value);
    return someService.find(id);
}

至于你的具体问题,

但当相关对象为 null 时返回空字符串,进而引发另一个问题,如图所示here https://stackoverflow.com/q/23725629/1391249.

正如那里所回答的,这是 Mojarra 中的一个错误,并在<o:viewParam>自 OmniFaces 1.8 起。因此,如果您至少升级到 OmniFaces 1.8.3 并使用其<o:viewParam>代替<f:viewParam>,那么你就不会再受到这个错误的影响了。

全方位面孔SelectItemsConverter在这种情况下也应该工作得很好。它返回一个空字符串null.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 p:selectOneMenu 中使用带有 null/空值的“请选择”f:selectItem 的相关文章

随机推荐