将 GET 请求参数放入 @ViewScoped bean
Posted
技术标签:
【中文标题】将 GET 请求参数放入 @ViewScoped bean【英文标题】:Getting a GET request param into an @ViewScoped bean 【发布时间】:2011-12-05 02:57:15 【问题描述】:我有一个(请求范围的)列表,用户可以从中选择“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 时,我都会从 EntityManager
获得 NullPointerException
:
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 参数访问它。
谢谢
【问题讨论】:
【参考方案1】:@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
。
【讨论】:
感谢您的回答!我发现@PostConstruct
早于 f:event,请参阅 Gaim 在***.com/questions/4988899/… 中的答案。我仍然缺少明确说明此类事情的资料/书籍。作为 Java EE 6 的新手,我面临的问题是要掌握范围以及 CDI @Named
会比 JSF @ManagedBean
获得什么,同时考虑到几乎所有 RichFaces 源都使用 @ManagedBean @ViewScoped
组合。我刚刚尝试了 CDI,现在可能正在倾销它。我没有看到我的收获(还)。
您可能会发现链接的“JSF 2.0 中的通信”文章有助于获得良好的“简而言之 JSF 2.0”概述。
哦,是的,这是很棒的东西,我真的很想念那个。谢谢。【参考方案2】:
有一种更好的方法可以从 url 获取 id。只需在@PostConstruct init() 方法中使用它即可从 url 获取“id”:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
您仍然可以使用 ViewScoped 和 @PostConstruct。
【讨论】:
以上是关于将 GET 请求参数放入 @ViewScoped bean的主要内容,如果未能解决你的问题,请参考以下文章
@ViewScoped 在每个回发请求上调用 @PostConstruct
JSF ViewScoped bean 在所有 ajax 请求中的唯一 ID?