2011-08-19 15 views
12

Cercando di produrre un elenco di elementi in un DataTable, come questo:JSF convertDateTime con fuso orario in 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> 

Formatta sempre l'ora in GMT. Funziona come previsto se utilizzo una costante stringa o un bean che non è la variabile datatable (come '# {mybean.timeZone}').

risposta

22

Sfortunatamente, questa è la natura dei tag <f:xxx>. Quando la vista deve essere costruita, viene creata una singola istanza del tag in cui il convertitore viene istanziato. Tutti i suoi attributi sono stati letti e impostati una sola volta. Al momento della creazione della vista, #{item} viene risolto in null (è disponibile solo durante il rendering della vista), pertanto l'attributo timeZone sarà null e quindi verrà impostato su UTC. Quando la vista deve essere renderizzata, la stessa istanza del convertitore è stata riutilizzata per ogni riga della tabella.

Ci sono diversi modi per risolvere questo problema. Posso pensare ad un convertitore personalizzato o ad una funzione EL. Penso che un convertitore personalizzato sia dopo tutto il meglio in quanto può quindi essere riutilizzato anche nei componenti di input. L'esempio seguente calcio d'inizio dovrebbe funzionare per voi (nullchecks e omesse per brevità):

@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); 
    } 

} 

che può essere utilizzato come

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

In questo modo il fuso orario si risolve ogni volta che il convertitore viene richiamato al posto di durante la sua costruzione.


Aggiornamento: il OmniFaces <o:converter> risolve proprio questo problema senza la necessità di un convertitore personalizzato.

<h:outputText value="#{item.time}"> 
    <o:converter converterId="javax.faces.DateTime" pattern="yyyy-MM-dd HH:mm:ssZ" timeZone="#{item.timeZone}" /> 
</h:outputText>