2011-10-11 186 views
3

我有一個(請求範圍)列表,用戶可以從中選擇一個「PQ」(鏈接列表)。當點擊或以其他方式進入瀏覽器時,每個PQ的主頁面將被顯示。每個PQ的頁面形式獲取GET請求參數到@ViewScoped bean

http://localhost:8080/projectname/main.jsf?id=2

這裏的PQ豆第一:

@Named 
@ViewScoped 
public class PqHome implements Serializable 
{ 
    @PersistenceContext(unitName="...") 
    private EntityManager em; 

    private Integer id; 
    private PQ instance; 

    @PostConstruct 
    public void init() 
    { 
     System.out.println("ID is " + id); // ID from URL param 

     instance = em.find(PQ.class, id);  
    } 

    public Integer getId() 
    { 
     return id; 
    } 

    public void setId(Integer id) 
    { 
     this.id = id; 
    } 

    public PQ getInstance() 
    { 
     return instance; 
    } 
} 

這裏的main.xhtml:

<ui:composition xmlns="http://www.w3.org/1999/xhtml" 
       ...> 
    <ui:define name="metadata"> 
    <f:metadata> 
     <f:viewParam name="id" value="#{pqHome.id}"> 
     <f:convertNumber integerOnly="#{true}" /> 
     </f:viewParam> 
     <!--f:event type="preRenderView" listener="#{pqHome.init}" /--> 
    </f:metadata> 
    </ui:define> 
    <ui:define name="title"> 
    <h:outputText value="Main" /> 
    </ui:define> 
    ... 
</ui:composition> 

任我選擇或以其他方式刷新page/URL我從EntityManager獲得NullPointerException

org.jboss.weld.exceptions.WeldException: WELD-000049 Unable to invoke [method] @PostConstruct public de.mycomp.myproj.beans.PqHome.init() on [email protected] 
    at org.jboss.weld.bean.AbstractClassBean.defaultPostConstruct(AbstractClassBean.java:595) 
... 
Caused by: java.lang.IllegalArgumentException: id to load is required for loading 
at org.hibernate.event.spi.LoadEvent.<init>(LoadEvent.java:87) 
at org.hibernate.event.spi.LoadEvent.<init>(LoadEvent.java:59) 
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:961) 
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:957) 
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:787) 
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:762) 
at org.jboss.as.jpa.container.AbstractEntityManager.find(AbstractEntityManager.java:221) 
at de.mycomp.myproj.beans.PqHome.init(PqHome.java:47) 
... 56 more 

[47號線是em.find(...)]

<f:event type="preRenderView" listener="#{pqHome.init}" /> 

不會使事情變得更好。我現在非常沮喪。

如何將URL GET請求參數寫入@ViewScoped bean?

注意:我敢打賭,這不是一件微不足道的事情。有可能我在概念上做錯了一些事情,所以我們歡迎任何關於如何改進的提示。我覺得我需要選擇@ViewScoped,因爲在那個頁面上會有更復雜的基於AJAX的圖形用戶界面,我真的想通過URL GET params保持訪問。

感謝

回答

6

@PostConstruct是bean的建設和所有依賴注入之後調用直接(如@PersistenceContext@EJB@ManagedProperty@Inject,etc..etc ..)。

<f:viewParam>在更新模型值階段期間設置它的值,這個階段遠遠超過(後期)bean的構建。所以在@PostConstruct裏面<f:viewParam>的值根本就沒有設置。這一點仍然是null

您接近<f:event type="preRenderView">,但您必須刪除@PostConstruct註釋。

所以:

<f:viewParam name="pq" value="#{pqHome.id}"> 
    <f:convertNumber integerOnly="#{true}" /> 
</f:viewParam> 
<f:event type="preRenderView" listener="#{pqHome.init}" /> 

private Integer id; 

public void init() { 
    instance = em.find(PQ.class, id);  
} 

無關的具體問題,我建議使用此一Converter代替。另見Communication in JSF 2.0 - Converting and validating GET request parameters

此外組合@Named @ViewScoped將無法​​正常工作。JSF專用@ViewScoped僅與JSF專用@ManagedBean結合使用。您的CDI特定的@Named的行爲將如此@RequestScoped。請使用@ManagedBean而不是@Named或使用CDI專用@ConversationScoped代替@ViewScoped

+0

感謝您的回答!我發現'@ PostConstruct'遠在f:event之前,請參閱Gaim的答案http://stackoverflow.com/questions/4988899/trying-to-use-view-parameters-in-postconstruct。我仍然缺少明確說明這些事情的來源/書籍。作爲一名Java EE 6新手,我面臨的問題是掌握範圍以及CDI'@ Named'將通過JSF'@ ManagedBean'獲得什麼,同時也考慮到幾乎所有RichFaces源都使用'@ManagedBean @ ViewScoped'組合。我剛剛嘗試過CDI,現在可能會拋棄它。我還沒有看到我的收益。 – Kawu

+0

您可能會發現鏈接的「JSF 2.0中的通信」文章對概述「JSF 2.0」有幫助。 – BalusC

+1

噢,這是偉大的東西,我真的錯過了那一個。謝謝。 – Kawu

6

有一個更好的方法來從URL獲取ID。只是用它在@PostConstruct init()方法來從URL獲得 「身份證」:

FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id"); 

,您仍然可以使用ViewScoped和@PostConstruct。