2011-10-11 298 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。