【问题标题】:How to have a custom non null value for empty input component dispite INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL = true尽管INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL = true,如何为空输入组件设置自定义非空值
【发布时间】:2019-02-07 12:28:08
【问题描述】:

在我的faces-config.xml我已经设置了

<context-param>
 <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
 <param-value>true</param-value>
</context-param>

因此,没有输入的任意输入组件将null 放入绑定到value="#{myBean.someDate}" 属性的bean 属性中,并在从该bean 属性获取null 时呈现一个空组件。

虽然这通常是应用程序想要的行为,但我有一个特定的组件,我想用自定义的 non null 值替换 null

是否有通用的好方法来实现这一点?

我已经为 Primefaces (6.2) 日历使用 Mojarra 2.3.8 进行了尝试:

<h:form id="myForm">
        <p:calendar value="#{myBean.someDate}" pattern="MM/dd/yyyy"
            converter="mySpecialDateConverter" locale="en" />
        <p:commandButton value="send" process="@form" update="@form" />
        <hr />
        <h:outputText value="#{myBean.someDate}" />
</h:form>

我使用转换器进行了尝试,当我从#{myBean.someDate} 接收到我的自定义值时,渲染组件时在getAsString() 中返回empty String,或者当getAsObject() 或纯时在getAsObject() 中吐出我的自定义值空提交:

import java.util.Date;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.DateTimeConverter;
import javax.faces.convert.FacesConverter;

@FacesConverter("mySpecialDateConverter")
public class MyConverter extends DateTimeConverter {

    private static final Date PAST = new Date(0);

    public MyConverter() {
        setPattern("MM/dd/yyyy");
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (PAST.equals(value)) {
            return "";
        }
        return super.getAsString(context, component, value);
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (null == value || "".equals(value.trim())) {
            return PAST;
        }
        return super.getAsObject(context, component, value);
    }

}

当 bean 属性等于 PAST 时呈现一个空的日历组件按预期工作。但是在没有输入的情况下提交日历会将属性设置为null,因为Primefaces CalendarRenderer 根本不会在提交空白值时参考Converter

package org.primefaces.component.calendar;

public class CalendarRenderer extends InputRenderer {
    // ...
    public Object getConvertedValue(FacesContext context, UIComponent component, Object value) throws ConverterException {
        Calendar calendar = (Calendar) component;
        String submittedValue = (String) value;
        SimpleDateFormat format = null;

        if (isValueBlank(submittedValue)) {
            return null;
        }

        //Delegate to user supplied converter if defined
        try {
            Converter converter = calendar.getConverter();
            if (converter != null) {
                return converter.getAsObject(context, calendar, submittedValue);
            }
        }
        // ...
    }
    // ...
}

这部分没问题,正如Converter.getAsObject() 上的 JavaDoc 所说:

/** 
 * @return <code>null</code> if the value to convert is <code>null</code>, 
 * otherwise the result of the conversion 
 */

因此 Primefaces 没有理由在空输入上解析转换器。如果我们设置javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL = false,恕我直言。然后我会认为上述行为不正确,因为"" 不是null

为了完整起见,这是我的 bean aka myBean:

import java.io.Serializable;
import java.util.Date;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class MyBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private Date someDate;

    public Date getSomeDate() {
        return someDate;
    }

    public void setSomeDate(Date someDate) {
        this.someDate = someDate;
    }

}

我不想更改该 bean,因为在实际应用程序中,日历的值绑定到持久的实体属性值。我也不希望持久层完成这项工作。

背景:

我想阻止某些数据库 DATE 字段中的 null 值。例如,在期间的情况下,我希望开始默认为与应用程序上下文无关的某个遥远的过去日期,对于该期间的结束,我希望在遥远的将来的日期与应用程序上下文无关,并且两者都不会打扰用户哪些日期默认情况下。这些默认日期有助于过滤当前 Date 处于或超出该周期的实体,而用户没有输入实际上是周期 for ever

【问题讨论】:

    标签: jsf primefaces


    【解决方案1】:

    JSF 组件不会在 null 值或它们认为为 null 的任何值上调用转换器 - 这对于 JSF 中的默认组件也是如此。所以在这方面,我猜 PrimeFaces 的行为符合预期,这是正确的结果。这里有两种方法可以立即浮现在脑海中;

    使用 OmniFaces

    JSF converter with null value 中所述,OmniFaces o:param 将调用您的转换器,而不考虑空值 - 您可以使用它将参数传递给组件。在您的具体情况下,您应该能够执行类似的操作;

    <h:form id="myForm">
            <p:calendar value="#{myBean.someDate}" pattern="MM/dd/yyyy" locale="en" />
            <p:commandButton value="send" process="@form" update="@form">
                <o:param name="date" value="#{myBean.someDateConversion}"
                         converter="mySpecialDateConverter" /> 
            </p:commandButton>
            <hr />
            <h:outputText value="#{myBean.someDate}" />
    </h:form>
    

    使用自定义渲染器

    第二种选择是使用自定义渲染器,只需修改组件的行为以始终调用转换器,如本答案中所述 - JSF Custom Converter not called on null value

    【讨论】:

    • 感谢您的协助 - o:param 似乎只使用转换器处理 输出 方向,以通过 Converter.getAsString() 获得正确的字符串以进行渲染,这已经为我工作了.它似乎没有通过Converter.getAsObject() 将提交的值从用户input 传送到bean 属性中。所以你认为我必须覆盖渲染器?顺便说一句,您的两个链接具有相同的目标 URL。
    • @Selaron 很抱歉。修改了第二个链接。对于处理空输入 - 这两种方法都应该适用于您的目的。 o:param 显然不会调用 getAsObject() - 相反,我们的想法是在它调用的 setter 方法中处理这个并从父组件中读取这个值。这是一种“强制”转换的简单方法。根据您的目标,您甚至可能不必在 o:param 中使用转换器 - 只需使用普通的 f:paramf:attribute 可能就可以了。
    • @Selaron 并回答您的问题 - 真正依赖并确保 JSF 为您调用转换器 - 据我所知,您必须如上所述修改它的行为。如前所述,另一种选择是解决它。
    • 我最终创建了一个自定义渲染器,它以与the Q/A linked by your 中描述的类似方式覆盖CalendarRenderer.getConvertedValue。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2014-03-06
    • 2021-03-30
    • 1970-01-01
    • 2019-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多