获取GET请求参数到@ViewScoped bean

Kaw*_*awu 3 java javabeans cdi scopes jsf-2

我有一个(请求范围的)列表,用户可以从中选择"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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是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>
Run Code Online (Sandbox Code Playgroud)

任何时候,我选择或以其他方式刷新页面/ 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
Run Code Online (Sandbox Code Playgroud)

[第47行是em.find(...)]

这条线

<f:event type="preRenderView" listener="#{pqHome.init}" />
Run Code Online (Sandbox Code Playgroud)

不会让事情变得更好.我现在很沮丧.

你如何获得URL GET请求参数到@ViewScopedbean?

注意:我敢打赌这不是一件小事.有可能我在概念上做错了,所以欢迎任何有关如何改进的提示.我觉得我需要选择,@ViewScoped因为在该页面上会有更复杂的基于AJAX的GUI,我真的希望通过URL GET参数可以访问它.

谢谢

Bal*_*usC 6

@PostConstruct被调用直接 bean的建设和所有依赖注入之后(如@PersistenceContext,@EJB,@ManagedProperty,@Inject,etc..etc ..).

<f:viewParam>套在更新模型值阶段,这是后的豆的(后)施工远其值.所以里面@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}" />
Run Code Online (Sandbox Code Playgroud)

private Integer id;

public void init() {
    instance = em.find(PQ.class, id);       
}
Run Code Online (Sandbox Code Playgroud)

具体问题无关,我建议使用一个Converter替代.另请参见JSF 2.0中的通信 - 转换和验证GET请求参数.

此组合@Named @ViewScoped也无法按预期工作.特定@ViewScoped于JSF的工作@ManagedBean仅与JSF相关.您的CDI特定@Named行为将@RequestScoped如此.或者使用@ManagedBean替代@Named,或者使用专用CDI @ConversationScoped代替@ViewScoped.


Seb*_*nis 6

有一种更好的方法从url获取id.只需在@PostConstruct init()方法中使用它从url获取"id":

FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
Run Code Online (Sandbox Code Playgroud)

您仍然可以使用ViewScoped和@PostConstruct.