【问题标题】:Dynamic JSF converter动态 JSF 转换器
【发布时间】:2013-04-30 02:40:43
【问题描述】:

我的 JSF 应用程序背后的数据访问层使用两种不同的日期字段格式(有时是 ddmmyyyy,有时是 yyyymmdd);显示的日期始终为 dd/mm/yyyy。

有没有办法为单个字段使用两个不同的转换器并动态决定使用哪一个?就像“如果单击此命令按钮,则使用此转换器,否则如果单击此其他命令按钮,请使用该转换器”。

【问题讨论】:

  • 您的问题需要进一步澄清。如果日期总是一个格式显示,那么只有一个转换器的位置。转换器将从该字符串生成Date 对象。接下来,在您的托管 bean 中,您将设置日期,稍后,在操作方法中,您将决定以何种格式将数据传递给您的 DAO,具体取决于调用的操作方法。如果我对您的设置的理解与您的不一致,您可以相应地更新答案。

标签: jsf jsf-2 converter


【解决方案1】:

BalusC 在这里解释了为什么这很困难:https://stackoverflow.com/a/7123153/3284943

根据他的建议,我创建了这个:

在 JSF 文件中,我使用我的自定义转换器及其定义的属性,在运行时选择转换器和动态属性。这是来自动态 PrimeFaces 数据表的 sn-p:

<h:outputText rendered = "#{column.dateTime}" value="#{table[column.name]}">
    <f:converter converterId="runtimeConverterSelector" />
    <f:attribute name="converterId" value="#{column.converterName}" />
    <f:attribute name="pattern" value="#{column.converterPattern}" />
</h:outputText>

自定义转换器:

@FacesConverter ("runtimeConverterSelector")
public class RuntimeConverterSelector implements Converter {
    Converter delegateConverter;
    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        retrieveAttributes(component);
        return delegateConverter.getAsObject(context, component, value);
    }
    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        retrieveAttributes(component);
        return delegateConverter.getAsString(context, component, value);
    }
    private void retrieveAttributes(UIComponent component) {
        Object attribute;
        attribute = component.getAttributes().get("converterId");
        if (attribute != null) {
            String converterName = (String)attribute;
            switch (converterName) {
                case "javax.faces.BigDecimal":
                    delegateConverter = new BigDecimalConverter();
                    break;
                case "javax.faces.BigInteger":
                    delegateConverter = new BigIntegerConverter();
                    break;
                case "javax.faces.Boolean":
                    delegateConverter = new BooleanConverter();
                    break;
                case "javax.faces.Byte":
                    delegateConverter = new ByteConverter();
                    break;
                case "javax.faces.Character":
                    delegateConverter = new CharacterConverter();
                    break;
                case "javax.faces.DateTimeConverter":
                    delegateConverter = new DateTimeConverter();
                    attribute = component.getAttributes().get("pattern");
                    if (attribute != null) ((DateTimeConverter)delegateConverter).setPattern((String)attribute);
                    attribute = component.getAttributes().get("timeZone");
                    if (attribute != null) ((DateTimeConverter)delegateConverter).setTimeZone(TimeZone.getTimeZone((String)attribute));
                    attribute = component.getAttributes().get("dateStyle");
                    if (attribute != null) ((DateTimeConverter)delegateConverter).setDateStyle((String)attribute);
                    attribute = component.getAttributes().get("timeStyle");
                    if (attribute != null) ((DateTimeConverter)delegateConverter).setDateStyle((String)attribute);
                    attribute = component.getAttributes().get("type");
                    if (attribute != null) ((DateTimeConverter)delegateConverter).setDateStyle((String)attribute);
                    break;
                case "javax.faces.Double":
                    delegateConverter = new DoubleConverter();
                    break;
                case "javax.faces.Enum":
                    delegateConverter = new EnumConverter();
                    break;
                case "javax.faces.Float":
                    delegateConverter = new FloatConverter();
                    break;
                case "javax.faces.Integer":
                    delegateConverter = new IntegerConverter();
                    break;
                case "javax.faces.Long":
                    delegateConverter = new LongConverter();
                    break;
                case "javax.faces.Number":
                    delegateConverter = new NumberConverter();
                    attribute = component.getAttributes().get("currencyCode");
                    if (attribute != null) ((NumberConverter)delegateConverter).setCurrencyCode((String)attribute);
                    attribute = component.getAttributes().get("currencySymbol");
                    if (attribute != null) ((NumberConverter)delegateConverter).setCurrencySymbol((String)attribute);
                    attribute = component.getAttributes().get("groupingUsed");
                    if (attribute != null) ((NumberConverter)delegateConverter).setGroupingUsed(Boolean.parseBoolean((String)attribute));
                    attribute = component.getAttributes().get("integerOnly");
                    if (attribute != null) ((NumberConverter)delegateConverter).setIntegerOnly(Boolean.parseBoolean((String)attribute));
                    attribute = component.getAttributes().get("locale");
                    if (attribute != null) ((NumberConverter)delegateConverter).setLocale(new Locale((String)attribute));
                    attribute = component.getAttributes().get("maxFractionDigits");
                    if (attribute != null) ((NumberConverter)delegateConverter).setMaxFractionDigits(Integer.parseInt((String)attribute));
                    attribute = component.getAttributes().get("maxIntegerDigits");
                    if (attribute != null) ((NumberConverter)delegateConverter).setMaxIntegerDigits(Integer.parseInt((String)attribute));
                    attribute = component.getAttributes().get("minFractionDigits");
                    if (attribute != null) ((NumberConverter)delegateConverter).setMinFractionDigits(Integer.parseInt((String)attribute));
                    attribute = component.getAttributes().get("minIntegerDigits");
                    if (attribute != null) ((NumberConverter)delegateConverter).setMinIntegerDigits(Integer.parseInt((String)attribute));
                    attribute = component.getAttributes().get("pattern");
                    if (attribute != null) ((NumberConverter)delegateConverter).setPattern((String)attribute);
                    attribute = component.getAttributes().get("type");
                    if (attribute != null) ((NumberConverter)delegateConverter).setType((String)attribute);
                    break;
                case "javax.faces.Short":
                    delegateConverter = new ShortConverter();
                    break;
                default:
                    System.err.println("ConverterId provided to runtimeConverterSelector, '" + converterName + "' is invalid. The default converter will be used");
                    break;
            }
        } else {
            System.err.println("No converterId was provided to runtimeConverterSelector.  The default converter will be used.");
        }
    }
}

【讨论】:

    【解决方案2】:

    AFAIK 这是不可能的。但是您可以在一个转换器中检查这两种格式。当然,转换为字符串将基于一种格式完成。或者,您可以根据当前的Locale 格式化日期。基本示例:

    @FacesConverter("doubleDateConverter")
    public class DateConverter implements Converter {
    
        public Object getAsObject(FacesContext context, UIComponent component, String value) {
            if(value == null || value.equals("")) {
                return null;
            }
            SimpleDateFormat format1 = new SimpleDateFormat("ddMMyyyy");
            SimpleDateFormat format2 = new SimpleDateFormat("yyyyMMdd");
            Date date = null;
            boolean valid = true;
            try {
                date = format1.parse(value);
            } catch (ParseException e) {
                valid = false;
            }
            if(!valid) {
                try {
                    date = format2.parse(value);
                } catch (ParseException e) {
                    valid = false;
                }
            }
            if((!valid) || (date == null)) {
                throw new ConverterException(new FacesMessage("Date is in wrong format: " + value));
            }
            return date;
        }
    
        public String getAsString(FacesContext context, UIComponent component, Object value) {
            if (!(value instanceof Date) || (value == null)) {
                return null;
            }
            SimpleDateFormat format = new SimpleDateFormat("ddMMyyyy");
            return format.format((Date)value);
        }
    
    }
    

    【讨论】:

    • 我编辑了我的问题以便更清楚:显示的日期都具有相同的格式(dd/mm/yyyy)。使用这种方法,我可以使用一个 getAsString 方法和两个正则表达式来选择如何显示我的日期,但是 getAsObject 方法不“知道”我的数据层需要哪种格式。
    • 请先测试代码,然后再将其作为答案发布。您忘记考虑 SDF 的 lenientness 以及例如12121212 在两种格式中都有效。最好按照 OP 的明确要求使其真正依赖于操作。
    猜你喜欢
    • 2012-02-03
    • 2012-12-26
    • 1970-01-01
    • 2011-11-29
    • 2018-12-24
    • 2011-01-06
    • 2011-07-05
    • 1970-01-01
    • 2011-06-06
    相关资源
    最近更新 更多