2011-09-23 15 views
10

我創建了一個自定義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>

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

的問題是,當我第一次打開該視圖,所有屬性只在我的Converter類中設置一次,然後數據表呈現並根據初始屬性轉換值。

我預計屬性是按行設置的。我怎樣才能做到這一點?

回答

24

至此,您預計每次渲染數據錶行時都會設置轉換器的屬性。這確實不是事實。當構建視圖時,JSF將只爲每個組件創建一個轉換器實例,每次渲染該行時都不會創建/重置轉換器。

有幾種方法可以使其工作。

  • 傳遞動態屬性作爲成分的<f:attribute>,讓上,所述Converter截距。你可以在這裏找到一個例子:JSF convertDateTime with timezone in datatable。這可以被用作

    <h:outputText value="#{item.balanceDate}"> 
        <f:converter converterId="isoDateTimeConverter" /> 
        <f:attribute name="pattern" value="#{item.pattern}" /> 
    </h:outputText> 
    

  • 使用EL函數而不是Converter。你可以在這裏找到一個例子:Facelets and JSTL (Converting a Date to a String for use in a field)。這可以被用來作爲

    <h:outputText value="#{mh:convertIsoDate(item.balanceDate, item.pattern)}" /> 
    

  • 綁定的轉換器和DataTable的DataModel爲同一託管bean的屬性。這樣,您可以在返回之前根據行數據設置轉換器的屬性。這是一個基於標準的JSF組件和標準DateTimeConverter基本開球例子(它應該工作一樣好上PrimeFaces組件,並與您的自定義轉換器):

    <h:dataTable value="#{bean.model}" var="item"> 
        <h:column> 
         <h:outputText value="#{item.date}" converter="#{bean.converter}" /> 
        </h:column> 
    </h:dataTable> 
    

    @ManagedBean 
    @ViewScoped 
    public class Bean implements Serializable { 
    
        private List<Item> items; 
        private DataModel<Item> model; 
        private DateTimeConverter converter; 
    
        @PostConstruct 
        public void init() { 
         items = Arrays.asList(
          new Item(new Date(), "dd-MM-yyyy"), 
          new Item(new Date(), "yyyy-MM-dd"), 
          new Item(new Date(), "MM/dd/yyyy")); 
         model = new ListDataModel<Item>(items); 
         converter = new DateTimeConverter(); 
        } 
    
        public DataModel<Item> getModel() { 
         return model; 
        } 
    
        public Converter getConverter() { 
         converter.setPattern(model.getRowData().getPattern()); 
         return converter; 
        } 
    
    } 
    

    (該Item類只是一個豆有兩個屬性Date dateString pattern

    此結果

    23-09-2011
    2011-09-23
    2011年9月23日


  • 使用OmniFaces<o:converter>代替。它支持屬性中EL的渲染時間評估。另見the <o:converter> showcase example

    <h:outputText value="#{item.balanceDate}"> 
        <o:converter converterId="isoDateTimeConverter" pattern="#{item.pattern}" /> 
    </h:outputText> 
    
相關問題