我创建了一个自定义 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)一个 Converter
到 ui: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/