2011-11-03 45 views
2

我有這樣的實體,稱爲「操作」:如何在JSF 2中創建自定義轉換器?

@Entity 
@Table(name="operation") 
public class Operation implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy=GenerationType.SEQUENCE) 
    private Integer id; 

    @NotNull(message="informe um tipo de operação") 
    private String operation; 

    //bi-directional many-to-one association to Product 
    @OneToMany(mappedBy="operation") 
    private List<Product> products; 

    // getter and setters 
} 

我檢索操作是這樣的:(?這可能是通過一個EJB實例,但只是爲了保持它的地方和作爲一個例子,好不好;))

public Map<String, Object> getOperations() { 
    operations = new LinkedHashMap<String, Object>(); 
    operations.put("Select an operation", new Operation()); 
    operations.put("Donation", new Operation(new Integer(1), "donation")); 
    operations.put("Exchange", new Operation(new Integer(2), "exchange")); 

    return operations; 
} 

所以我試圖讓這個selectOneMenu所選擇的操作:

productcManagedBean具有viewScopeproductb是一個sessionScope具有product這是我的實體ManagedBean。該產品contais一個operation,所以是這樣的:

(信Ç擁有控制權,其中涉及關於我的實體產品的所有操作都應該由這個bean來處理的意思,好嗎?)

Product productc (ViewScope) 
-- ProductBean productb (SessionScope) 
---- Product product (Entity) 
-------- Operation operation (Entity) 

轉換器是一樣的@BalusC是建議前:

@ManagedBean 
@RequestScoped 
public class OperationConverter implements Converter { 

    @EJB 
    private EaoOperation operationService; 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, Object value) { 
     if (!(value instanceof Operation) || ((Operation) value).getId() == null) { 
      return null; 
     } 

     return String.valueOf(((Operation) value).getId()); 
    } 

    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, String value) { 
     if (value == null || !value.matches("\\d+")) { 
      return null; 
     } 

     Operation operation = operationService.find(Integer.valueOf(value)); 
     System.out.println("Getting the operation value = " + operation.getOperation()); 

     if (operation == null) { 
      throw new ConverterException(new FacesMessage("Unknown operation ID: " + value)); 
     } 

     return operation; 
    } 

的日誌中顯示,其中選擇檢索的操作:

FINE: SELECT ID, OPERATION FROM operation WHERE (ID = ?) 
    bind => [1 parameter bound] 
INFO: Getting the operation value = exchange 

所以,當我嘗試提交表單給出瞭如下錯誤:

form_add_product:operation: Validation error: the value is not valid 

這究竟是爲什麼?

回答

2

你試圖傳遞一個複雜的對象作爲HTTP請求參數,它可能只是一個String。 JSF/EL具有用於原語及其包裝的內置轉換器(例如int,Integer),甚至包含枚舉。但對於所有其他類型,您確實需要編寫一個自定義轉換器。在這種情況下,您需要編寫一個在StringOperation之間轉換的轉換器。然後使用String作爲選項值(瀏覽器中的打開頁面,右鍵單擊和查看源文件並注意<option value>)。然後使用Operation作爲模型值。 String應該唯一標識Operation對象。你可以使用這個操作ID。

但在這種特殊情況下,使用這種硬編碼映射和相對簡單的模型,我認爲使用enum代替它更容易。

public enum Operation { 

    DONATION("Donation"), EXCHANGE("Exchange"); 

    private String label; 

    private Operation(String label) { 
     this.label = label; 
    } 

    public string getLabel() { 
     return label; 
    } 

} 

private Operation operation; // +getter +setter 

public Operation[] getOperations() { 
    return Operation.values(); 
} 

<h:selectOneMenu value="#{bean.operation}"> 
    <f:selectItems value="#{bean.operations}" var="operation" itemValue="#{operation}" itemLabel="#{operation.label}" /> 
</h:selectOneMenu> 

但是,如果這些值有實際上從數據庫中檢索和其大小undefinied,那麼你還真需要一個定製轉換器。您可以在getAsString()返回ID,並在getAsObject()中使用操作DAO/EJB按ID獲取Operation

@ManagedBean 
@RequestScoped 
public class OperationConverter implements Converter { 

    @EJB 
    private OperationService operationService; 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, Object value) { 
     // Convert here Operation object to String value for use in HTML. 
     if (!(value instanceof Operation) || ((Operation) value).getId() == null) { 
      return null; 
     } 

     return String.valueOf(((Operation) value).getId()); 
    } 

    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, String value) { 
     // Convert here String submitted value to Operation object. 
     if (value == null || !value.matches("\\d+")) { 
      return null; 
     } 

     Operation operation = operationService.find(Long.valueOf(value)); 

     if (operation == null) { 
      throw new ConverterException(new FacesMessage("Unknown operation ID: " + value)); 
     } 

     return operation; 
    } 

} 

如下使用它:

<h:selectOneMenu ... converter="#{operationConverter}"> 

至於爲什麼它是一個@ManagedBean代替@FacesConverter,請閱讀本:Converting and validating GET request parameters


更新作爲對Validation Error: value not valid錯誤,這意味着Operation類的equals()方法損壞或丟失。在驗證期間,JSF通過Object#equals()將提交的值與可用值列表進行比較。如果沒有任何一個列表與提交的值匹配,那麼您會看到這個錯誤。因此,請確保equals()已正確實施。以下是通過數據庫技術標識進行比較的基本示例。

public boolean equals(Object other) { 
    return (other instanceof Operation) && (id != null) 
     ? id.equals(((Operation) other).id) 
     : (other == this); 
} 

不要忘記實現hashCode()還有:

public int hashCode() { 
    return (id != null) 
     ? (getClass().hashCode() + id.hashCode()) 
     : super.hashCode(); 
} 
相關問題