2012-08-31 87 views
3

我再次遇到麻煩。我的觀點是: 在我的項目中,我需要一個轉換器(顯然)將SelectOneMenu組件中的項目轉換爲相應bean中的列表屬性。在我的JSF頁面我有:SelectOneMenu中的JSF轉換器問題

<p:selectOneMenu id="ddlPublicType" value="#{publicBean.selectedPublicType}" effect="fade" converter="#{publicBean.conversor}" > 
    <f:selectItems value="#{publicoBean.lstPublicTypes}" var="pt" itemLabel="#{pt.label}" itemValue="#{pt.value}"></f:selectItems> 
</p:selectOneMenu> 

我的bean是:

@ManagedBean(name = "publicBean") 
@RequestScoped 
public class PublicBean { 

// Campos 
private String name; // Nome do evento 
private TdPublicType selectedPublicType = null; 
private List<SelectItem> lstPublicTypes = null; 
private static PublicTypeDAO publicTypeDao; // DAO 

static { 
    publicTypeDao = new PublicTypeDAO(); 
} 
// Construtor 

public PublicoBean() { 

    lstPublicTypes = new ArrayList<SelectItem>(); 
    List<TdPublicType> lst = publicTypeDao.consultarTodos(); 
    ListIterator<TdPublicType> i = lst.listIterator(); 
    lst.add(new SelectItem("-1","Select...")); 
    while (i.hasNext()) { 
     TdPublicType actual = (TdPublicType) i.next(); 
     lstPublicTypes.add(new SelectItem(actual.getIdPublicType(), actual.getNamePublicType())); 
    } 

} 

// Getters e Setters 

... 

public Converter getConversor() { 
    return new Converter() { 
     @Override 
     public Object getAsObject(FacesContext context, UIComponent component, String value) { 
      // This value parameter seems to be the value i had passed into SelectItem constructor 
      TdPublicType publicType = null; // Retrieving the PublicType from Database based on ID in value parameter 
      try { 
       if (value.compareTo("-1") == 0 || value == null) { 
        return null; 
       } 
       publicType = publicTypeDao.findById(Integer.parseInt(value)); 
      } catch (Exception e) { 
       FacesMessage msg = new FacesMessage("Error in data conversion."); 
       msg.setSeverity(FacesMessage.SEVERITY_ERROR); 
       FacesContext.getCurrentInstance().addMessage("info", msg); 
      } 
      return publicType; 
     } 

     @Override 
     public String getAsString(FacesContext context, UIComponent component, Object value) { 
      return value.toString(); // The value parameter is a TdPublicType object ? 
     } 
    }; 
} 

... 
} 

的getAsObject()方法,數值參數似乎我已經傳遞到了SelectItem構造函數的值。但在getAsString()方法中,該值也似乎是一個Id的字符串表示形式。此參數不應該是TdPublicType類型?我的代碼有什麼問題嗎?

回答

3

getAsString()應將Object(在您的情況下爲TdPublicType)轉換爲String,該String可唯一標識該實例,例如,一些ID,以便它可以用HTML代碼內聯,並作爲HTTP請求參數傳遞。 getAsObject()應該將該唯一的String表示返回到具體的Object實例,以便提交的HTTP請求參數可以轉換回原始對象實例。

基本上(瑣細預檢查和異常處理省略):

@Override 
public String getAsString(FacesContext context, UIComponent component, Object modelValue) throws ConverterException { 
    // Convert Object to unique String representation for display. 
    return String.valueOf(((TdPublicType) modelValue).getId()); 
} 

@Override 
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) throws ConverterException { 
    // Convert submitted unique String representation back to Object. 
    return tdPublicTypeService.find(Long.valueOf(submittedValue)); 
} 

更新:你還有一個問題,你指定TdPublicType類的value屬性作爲項目價值,而不是實例本身就是TdPublicType。這樣,轉換器將檢索value屬性,而不是getAsString()中的TdPublicType實例。相應地修復:

<f:selectItems value="#{publicoBean.lstPublicTypes}" var="pt" 
    itemLabel="#{pt.label}" itemValue="#{pt}"/> 
+0

我是否需要重載**的toString()** TdPublicType的?在** getAsString()**方法內部生成一個異常,說不可能從String轉換爲TdPublicType。 –

+0

然後模型值顯然不是'TdPublicType'類型。事實上,您使用'itemValue =「#{pt.value}」'而不是'itemValue =「#{pt}」'。相應地修復它。 – BalusC

+0

他仍然返回一個Integer作爲組件的支持模型,但我已經將itemValue屬性更改爲#{pt}。 –

0

現在代碼正在工作。我的錯誤是在加載方法。我這樣做:

// Loading menu 
List<TdPublicType> l = daoPublicType.retrieveAll(); 
Iterator<TdPublicType> i = l.iterator(); 
while (i.hasNext()) { 
    TdPublicType actual = (TdPublicType) i.next(); 
    lstMenuPublicType.add(new SelectItem(actual.getIdtPublicType(), actual.getNamePublicType())); 
} 

但正確的做法是:

// Loading menu 
List<TdPublicType> l = daoPublicType.retrieveAll(); 
Iterator<TdPublicType> i = l.iterator(); 
while (i.hasNext()) { 
    TdPublicType actual = (TdPublicType) i.next(); 
    lstMenuPublicType.add(new SelectItem(actual, actual.getNamePublicType())); // In the first parameter i passed the PublicType object itself not his id. 
} 
0

使用可以使用通用的轉換器,它會在後臺bean的值轉換。 你也不需要任何鑄件。

@FacesConverter(value = "GConverter") 
public class GConverter implements Converter{ 

    private static Map<Object, String> entities = new WeakHashMap<Object, String>(); 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, Object entity) { 
     synchronized (entities) { 
      if (!entities.containsKey(entity)) { 
       String uuid = UUID.randomUUID().toString(); 
       entities.put(entity, uuid); 
       return uuid; 
      } else { 
       return entities.get(entity); 
      } 
     } 
    } 

    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, String uuid) { 
     for (Entry<Object, String> entry : entities.entrySet()) { 
      if (entry.getValue().equals(uuid)) { 
       return entry.getKey(); 
      } 
     } 
     return null; 
    } 

} 

用法示例將

<p:selectOneMenu id="ddlPublicType" value="#{publicBean.selectedPublicType}" effect="fade" converter="GConverter" > 
    <f:selectItems value="#{publicoBean.lstPublicTypes}" var="pt" itemLabel="#{pt.label}" itemValue="#{pt}"></f:selectItems> 
</p:selectOneMenu> 
+0

警告:此轉換器內存效率低下,並且可能會在使用二級數據庫緩存時導致內存泄漏。不建議在生產環境中使用。另見http://stackoverflow.com/q/30186849 – BalusC

+0

到現在爲止沒有小故障,我們一直在使用這個轉換器很長一段時間。然而,謝謝你的信息。我們當然也會尋找其他一些選擇 – Anubhav