Подтвердить что ты не робот

JSF convertDateTime с часовым поясом в datatable

Попытка вывести список элементов в datatable, например:

<t:dataTable value="#{mybean.list}" var="item">
        <h:column>
            <h:outputText value="#{item.time}">
                <f:convertDateTime pattern="yyyy-MM-dd HH:mm:ssZ"  timeZone="#{item.timeZone}" />
            </h:outputText>
        </h:column>
</t:dataTable>

Он всегда форматирует время в GMT. Он работает как ожидалось, если я использую строчную константу или bean, которая не является переменной данных (например, "# {mybean.timeZone)" ).

4b9b3361

Ответ 1

К сожалению, это характер тегов <f:xxx>. Когда представление должно быть построено, создается один экземпляр тега, где создается экземпляр конвертера. Все его атрибуты читаются и устанавливаются только один раз. В настоящий момент представление построено, #{item} разрешается null (оно доступно только во время рендеринга представления), поэтому атрибут timeZone будет null, а затем по умолчанию - UTC. Когда представление должно быть отображено, тот же самый экземпляр преобразователя повторно используется для каждой строки таблицы.

Есть несколько способов решить эту проблему. Я могу думать о пользовательском конверторе или функции EL. Я думаю, что пользовательский конвертер после всего наилучшего, так как он также может быть повторно использован во входных компонентах. Для вас следует использовать следующий пример запуска (nullchecks и опущен для краткости):

@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>