我有一个(请求范围)列表,用户可以从中选择一个“PQ”(链接列表)。当单击或以其他方式进入浏览器时,应显示每个PQ的主页。每个PQ的页面格式为http://localhost:8080/projectname/main.jsf?id=2
首先是PQ bean:
@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>
每当我选择或刷新页面/ URL时,我都会从
NullPointerException
中得到一个EntityManager
:org.jboss.weld.exceptions.WeldException: WELD-000049 Unable to invoke [method] @PostConstruct public de.mycomp.myproj.beans.PqHome.init() on de.mycomp.myproj.beans.PqHome@4f0ea68f
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的GUI,我真的很想通过URL GET参数进行访问。谢谢
最佳答案
@PostConstruct
在bean的构造和所有依赖项注入(例如@PersistenceContext
,@EJB
,@ManagedProperty
,@Inject
等)之后直接调用。<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
。