将 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 等..等等。) .

&lt;f:viewParam&gt; 在更新模型值阶段设置其值,该阶段远在 bean 构建(后)之后。所以在@PostConstruct 内部,&lt;f:viewParam&gt; 的值还没有被设置。那时它仍然是null

您与&lt;f:event type="preRenderView"&gt; 关系密切,但您必须删除 @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?

android get/post如何实现多参数请求

如何正确地将身份验证令牌放在 GET 请求的标头中

使用 JSF 2.2 时在每个回发请求上重新创建 @ViewScoped bean

JSF 2.x @ViewScoped 托管 bean 线程安全吗?