不幸的是,这就是<f:xxx> 标签的本质。当要构建视图时,将在实例化转换器的位置构建标签的单个实例。它的所有属性只被读取和设置一次。在构建视图时,#{item} 解析为 null(它仅在视图呈现期间可用),因此 timeZone 属性将为 null,然后默认为 UTC。当要渲染视图时,表中的每一行都会重复使用相同的转换器实例。
有几种方法可以解决这个问题。我可以想到一个自定义转换器或一个 EL 函数。我认为自定义转换器毕竟是最好的,因为它也可以在输入组件中重用。以下启动示例应该适合您(为简洁起见,空检查和省略):
@FacesConverter("extendedDateTimeConverter")
public class ExtendedDateTimeConverter extends DateTimeConverter {
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
setPattern((String) component.getAttributes().get("pattern"));
setTimeZone(TimeZone.getTimeZone((String) component.getAttributes().get("timeZone")));
return super.getAsObject(context, component, value);
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
setPattern((String) component.getAttributes().get("pattern"));
setTimeZone(TimeZone.getTimeZone((String) component.getAttributes().get("timeZone")));
return super.getAsString(context, component, value);
}
}
可以用作
<h:outputText value="#{item.time}">
<f:converter converterId="extendedDateTimeConverter" />
<f:attribute name="pattern" value="yyyy-MM-dd HH:mm:ssZ" />
<f:attribute name="timeZone" value="#{item.timeZone}" />
</h:outputText>
这样,每次调用转换器而不是在构造过程中都会解析时区。
更新:OmniFaces <o:converter> 正好解决了这个问题,无需自定义转换器。
<h:outputText value="#{item.time}">
<o:converter converterId="javax.faces.DateTime" pattern="yyyy-MM-dd HH:mm:ssZ" timeZone="#{item.timeZone}" />
</h:outputText>