2011-09-19 60 views
1

我有一個命名會話作用域的文件CustomerRegistration,它有一個命名生成器方法getNewCustomer,它返回一個Customer對象。也有CustomerListProducer類,它從數據庫中產生所有客戶作爲列表。在selectCustomer.xhtml頁面上,用戶可以選擇其中一個客戶,並將選擇提交給應用程序,然後只需打印出所選客戶的姓氏。引用CDI生成器方法導致h:selectOneMenu

現在只有當我通過#{customerRegistration.newCustomer}在facelets頁面上引用選定的客戶時纔有效。當我簡單地使用#{newCustomer}時,只要我提交表格,姓氏的輸出就是null

這是怎麼回事嗎?這是預期的行爲,根據第7.1章對JSR-299規範的bean實例的限制?

它說:

...但是,如果應用程序直接實例化一個bean類, 卻讓容器進行實例化,產生的 實例未通過容器管理,是不是上下文 如第6.5.2節「bean的上下文實例」所定義的實例。 此外,第2.1節「容器提供給bean的功能 」中列出的功能將不可用於該特定實例的 。在部署的應用程序中,它是容器 ,它負責實例化bean並初始化它們的依賴關係。 ...

下面的代碼:

Customer.java:

@javax.persistence.Entity 
@Veto 
public class Customer implements Serializable, Entity { 
    private static final long serialVersionUID = 122193054725297662L; 
    @Column(name = "first_name") 
    private String firstName; 
    @Column(name = "last_name") 
    private String lastName; 
    @Id 
    @GeneratedValue() 
    private Long id; 

    public String getFirstName() { 
     return firstName; 
    } 

    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
    } 

    public String getLastName() { 
     return lastName; 
    } 

    public void setLastName(String lastName) { 
     this.lastName = lastName; 
    } 

    @Override 
    public String toString() { 
     return firstName + ", " + lastName; 
    } 

    @Override 
    public Long getId() { 
     return this.id; 
    } 
} 

CustomerListProducer.java:

@SessionScoped 
public class CustomerListProducer implements Serializable { 

    @Inject 
    private EntityManager em; 

    private List<Customer> customers; 

    @Inject 
    @Category("helloworld_as7") 
    Logger log; 

    // @Named provides access the return value via the EL variable name 
    // "members" in the UI (e.g., 
    // Facelets or JSP view) 
    @Produces 
    @Named 
    public List<Customer> getCustomers() { 
     return customers; 
    } 

    public void onCustomerListChanged(
      @Observes(notifyObserver = Reception.IF_EXISTS) final Customer customer) { 
//  retrieveAllCustomersOrderedByName(); 
     log.info(customer.toString()); 
    } 

    @PostConstruct 
    public void retrieveAllCustomersOrderedByName() { 
     CriteriaBuilder cb = em.getCriteriaBuilder(); 
     CriteriaQuery<Customer> criteria = cb.createQuery(Customer.class); 
     Root<Customer> customer = criteria.from(Customer.class); 
     // Swap criteria statements if you would like to try out type-safe 
     // criteria queries, a new 
     // feature in JPA 2.0 
     // criteria.select(member).orderBy(cb.asc(member.get(Member_.name))); 
     criteria.select(customer).orderBy(cb.asc(customer.get("lastName"))); 
     customers = em.createQuery(criteria).getResultList(); 
    } 
} 

CustomerRegistration.java:

@Named 
@SessionScoped 
public class CustomerRegistration implements Serializable { 

    @Inject 
    @Category("helloworld_as7") 
    private Logger log; 

    private Customer newCustomer; 

    @Produces 
    @Named 
    public Customer getNewCustomer() { 
     return newCustomer; 
    } 

    public void selected() { 
     log.info("Customer " + newCustomer.getLastName() + " ausgewählt."); 
    } 

    @PostConstruct 
    public void initNewCustomer() { 
     newCustomer = new Customer(); 
    } 

    public void setNewCustomer(Customer newCustomer) { 
     this.newCustomer = newCustomer; 
    } 

} 

不工作selectCustomer.xhtml:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE html 
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:ui="http://java.sun.com/jsf/facelets"> 
<h:head> 
    <title>Auswahl</title> 
</h:head> 
<h:body> 
    <h:form> 
     <h:selectOneMenu value="#{newCustomer}" converter="customerConverter"> 
      <f:selectItems value="#{customers}" var="current" 
       itemLabel="#{current.firstName}, #{current.lastName}" /> 
     </h:selectOneMenu> 
     <h:panelGroup id="auswahl"> 
      <h:outputText value="#{newCustomer.lastName}" /> 
     </h:panelGroup> 
     <h:commandButton value="Klick" 
      action="#{customerRegistration.selected}" /> 
    </h:form> 
</h:body> 
</html> 

工作selectCustomer.xhtml:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE html 
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:ui="http://java.sun.com/jsf/facelets"> 
<h:head> 
    <title>Auswahl</title> 
</h:head> 
<h:body> 
    <h:form> 
     <h:selectOneMenu value="#{customerRegistration.newCustomer}" converter="customerConverter"> 
      <f:selectItems value="#{customers}" var="current" 
       itemLabel="#{current.firstName}, #{current.lastName}" /> 
     </h:selectOneMenu> 
     <h:panelGroup id="auswahl"> 
      <h:outputText value="#{newCustomer.lastName}" /> 
     </h:panelGroup> 
     <h:commandButton value="Klick" 
      action="#{customerRegistration.selected}" /> 
    </h:form> 
</h:body> 
</html> 

CustomerConverter.java:

@SessionScoped 
@FacesConverter("customerConverter") 
public class CustomerConverter implements Converter, Serializable { 
    private static final long serialVersionUID = -6093400626095413322L; 

    @Inject 
    EntityManager entityManager; 

    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, 
      String value) { 
     Long id = Long.valueOf(value); 
     return entityManager.find(Customer.class, id); 
    } 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, 
      Object value) { 
     return ((Customer) value).getId().toString(); 
    } 

} 

回答

2

@Producer s的註冊如何思考。在部署期間,容器會掃描您的類以進行註釋,並且您在@SessionScoped @Named bean中聲明瞭@Producer方法,這並不意味着您將擁有與該bean的實例一樣多的生產者,也不意味着該容器將調用您期望它被調用的實例的生產者。

這裏發生的是 - 您的生產者方法總是返回相同的實例Customer,這是在部署期間在您的@PostConstruct方法中創建的實例,即在@Producer期間註冊。

這是預期的行爲。

看來,你想要的東西,會給你一個新的Customer實體每個會話。在這種情況下,正確的方式做,這將是:

public class CustomerProducer { 

    @Produces @Named @SessionScoped 
    public Customer getNewCustomer(@New Customer customer) { 
     // do some custom init if need be 
     return customer; 
    } 

} 

然後從你的會話@Producer相關注釋作用域bean。現在,您可以使用`#{newCustomer},每次會話都會爲您提供一個新的容器管理實例。