jsf - 如何为 h :dataTable/ui:repeat? 的每一行/项目设置转换器属性

标签 jsf datatable jsf-2 converters uirepeat

我创建了一个自定义 ISO 日期时间 Converter :

public class IsoDateTimeConverter implements Converter, StateHolder {

    private Class type;
    private String pattern;

    private boolean transientValue = false;

    public void setType(Class type) {
        this.type = type;
    }

    public void setPattern(String pattern) {
        this.pattern = pattern;
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
        if (StringCheck.isNullOrEmpty(value)) {
            throw new ConverterException("value not specified");
        }

        try {
            if (IsoDate.class.equals(type)) {

                if (WebConst.ISO_DATE_NONE.equals(value)) {
                    return IsoDate.DUMMY;
                } else {
                    //TODO User spezifische TimeZone auslesen
                    return new IsoDate(value, TimeZone.getDefault().getID());
                }

            } else if (IsoTime.class.equals(type)) {

                if (WebConst.ISO_TIME_NONE.equals(value)) {
                    return IsoTime.DUMMY;
                } else {
                    //TODO User spezifische TimeZone auslesen
                    return new IsoTime(value, TimeZone.getDefault().getID());
                }

            } else if (IsoTimestamp.class.equals(type)) {

                if (WebConst.ISO_TIMESTAMP_NONE.equals(value)) {
                    return IsoTimestamp.DUMMY;
                } else {
                    //TODO User spezifische TimeZone auslesen
                    return new IsoTimestamp(value, TimeZone.getDefault().getID());
                }

            } else {
                throw new ConverterException("value not convertible");
            }
        } catch (Exception e) {
            throw new ConverterException(e.getMessage());
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException {
        if (value == null) {
            throw new ConverterException("value not specified");
        }

        if (IsoDate.class.equals(value)) {
            IsoDate isoDate = (IsoDate) value;

            if (isoDate.isDummy()) {
                return WebConst.ISO_DATE_NONE;
            } else {
                //TODO User spezifische TimeZone auslesen
                return isoDate.toString(pattern, TimeZone.getDefault().getID(), false);
            }

        } else if (IsoTime.class.equals(value)) {
            IsoTime isoTime = (IsoTime) value;

            if (isoTime.isDummy()) {
                return WebConst.ISO_TIME_NONE;
            } else {
                //TODO User spezifische TimeZone auslesen
                return isoTime.toString(pattern, TimeZone.getDefault().getID(), false);
            }

        } else if (IsoTimestamp.class.equals(value)) {
            IsoTimestamp isoTimestamp = (IsoTimestamp) value;

            if (isoTimestamp.isDummy()) {
                return WebConst.ISO_TIMESTAMP_NONE;
            } else {
                //TODO User spezifische TimeZone auslesen
                return isoTimestamp.toString(pattern, TimeZone.getDefault().getID(), false);
            }

        } else {
            throw new ConverterException("value not convertible");
        }
    }

    @Override
    public Object saveState(FacesContext context) {
        return new Object[]{type, pattern};
    }

    @Override
    public void restoreState(FacesContext context, Object state) {
        type = (Class) ((Object[]) state)[0];
        pattern = (String) ((Object[]) state)[1];
    }

    @Override
    public boolean isTransient() {
        return transientValue;
    }

    @Override
    public void setTransient(boolean transientValue) {
        this.transientValue = transientValue;
    }
}

我使用 Converter<mh:IsoDateTimeConverter>在以下 View 中:
<p:dataTable value="#{imports.list}" var="item">
    <p:column>
        <h:outputText value="#{item.balanceDate}" immediate="true">
            <mh:IsoDateTimeConverter type="#{webConst.ISO_DATE_CLASS}" pattern="#{webConst.ISO_DATE_FORMAT}"/>
        </h:outputText>
    </p:column>
</p:dataTable>

问题是,当我第一次打开这个 View 时,所有属性都设置在我的 Converter 中。类仅一次,然后数据表根据初始属性呈现和转换值。

我希望这些属性是按行设置的。我怎样才能做到这一点?

最佳答案

BalusC 的上述出色(一如既往)答案很全面,但并没有完全达到我的确切要求。就我而言,我需要绑定(bind)一个 Converterui:repeat 中的每次迭代.我需要一个不同的Converter取决于重复的每个项目。不过,答案确实为我指明了正确的方向,因此我认为值得分享我的解决方案,以防它对其他人有所帮助。
我使用 Converter将所有工作委托(delegate)给另一个 Converter属性中指定的对象,如 BalusC 的第一个答案。请注意,如果您希望使用带参数的转换器,这根本没有帮助,它针对的是您想要绑定(bind) Converter 的情况。到重复对象的属性。
这是委托(delegate)Converter .它也是一个Validator ,其工作方式完全相同。

// package and imports omitted for brevity
@FacesConverter(value="delegatingConverter")
@FacesValidator(value="delegatingValidator")
public class Delegator implements Converter, Validator {

    // Constants ---------------------------------------------------------------
    private static final String CONVERTER_ATTRIBUTE_NAME = "delegateConverter";
    private static final String VALIDATOR_ATTRIBUTE_NAME = "delegateValidator";

    // Business Methods --------------------------------------------------------
    @Override
    public Object getAsObject(FacesContext context, UIComponent component, 
            String value) throws ConverterException {
        return retrieveDelegate(component, Converter.class, CONVERTER_ATTRIBUTE_NAME)
                .getAsObject(context, component, value);
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, 
            Object value) throws ConverterException {
        return retrieveDelegate(component, Converter.class, CONVERTER_ATTRIBUTE_NAME)
                .getAsString(context, component, value);
    }

    @Override
    public void validate(FacesContext context, UIComponent component, 
            Object value) throws ValidatorException {
        retrieveDelegate(component, Validator.class, VALIDATOR_ATTRIBUTE_NAME)
                .validate(context, component, value);
    }
    
    private <T> T retrieveDelegate(UIComponent component, Class<T> clazz,
            String attributeName) {
        Object delegate = component.getAttributes().get(attributeName);
        if (delegate == null) {
            throw new UnsupportedOperationException("No delegate was specified."
                    + "  To specify, use an f:attribute tag with: name=\"" 
                    + attributeName + "\"");
        }
        if (!(clazz.isAssignableFrom(delegate.getClass()))) {
            throw new UnsupportedOperationException("The specified delegate "
                    + "was not a " + clazz.getSimpleName() + " object.  " +
                    "Delegate was: " + delegate.getClass().getName());
        }
        return (T) delegate;
    }
}
所以现在我希望在我的 ui:repeat 中使用此代码,这将不起作用:
<h:outputText value="#{item.balanceDate}">
    <f:converter binding="#{item.converter} />
    <f:validator binding="#{item.validator} />
</h:outputText>
我可以改用这段代码,它可以正常工作:
<h:outputText value="#{item.balanceDate}">
  <f:converter converterId="delegatingConverter"/>
  <f:validator validatorId="delegatingValidator"/>
  <f:attribute name="delegateConverter" value="#{item.converter}"/>
  <f:attribute name="delegateValidator" value="#{item.validator}"/>
</h:outputText>
假设重复项有 public Converter getConverter() Validator 的方法和类似方法.
这确实具有与 Converter 相同的优点。 s 或 Validator在别处使用的 s 可以在不做任何更改的情况下重复使用。

关于jsf - 如何为 h :dataTable/ui:repeat? 的每一行/项目设置转换器属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7530560/

相关文章:

datatable - 使 Wicket 口数据表的整个行都可单击

primefaces 数据表向下滚动到位置

jsf - Wildfly 11 中的 FORM 身份验证回退

jsf - 设置 JSF 转换值的格式

javascript - 通过服务器端渲染对 DataTable 进行排序

java - 通过按钮在 JSF 站点之外导航的选项

java - 如何添加按钮以在最后一个选项卡附近添加新选项卡?

java - RichFaces 4.2 转发到新页面,h :commandLink

java - ICEFaces session 自动扩展

java - 如何为Intellij IDEA创建Seam项目?