【问题标题】:Getting a GET request param into an @ViewScoped bean将 GET 请求参数放入 @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 参数访问它。

谢谢

【问题讨论】:

    标签: java jsf-2 javabeans cdi scopes


    【解决方案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 在stackoverflow.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。

    【讨论】:

      猜你喜欢
      • 2014-09-04
      • 2011-06-02
      • 2014-08-15
      • 2015-04-15
      • 2016-01-13
      • 1970-01-01
      • 1970-01-01
      • 2015-01-14
      相关资源
      最近更新 更多