2011-10-11 10 views
3

У меня есть список с запросом, из которого пользователь может выбрать «PQ» (список ссылок). При щелчке или в противном случае в браузере отображается основная страница для каждого PQ. страница Каждый PQ является видПолучение параметра запроса GET в beView @ViewScoped

http://localhost:8080/projectname/main.jsf?id=2

Вот PQ боб первый:

@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 [email protected] 
    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 

[Line 47 em.find (...)]

Линия

<f:event type="preRenderView" listener="#{pqHome.init}" /> 

не делает вещи лучше. Теперь я довольно отчаянный.

Как вы получите URL-адрес запроса GET в bean-файл @ViewScoped?

Примечание: Держу пари, что это не мелочь. Скорее всего, я делаю что-то неправильно здесь концептуально, поэтому любые советы о том, как улучшить, приветствуются. Я чувствовал, что мне нужно выбрать @ViewScoped, потому что на этой странице будет более сложный графический интерфейс на основе AJAX, который мне бы очень хотелось сохранить через параметры URL GET.

Благодаря

ответ

6

The @PostConstruct вызывается непосредственно после строительства бина и все инъекции зависимостей (например, как @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}" /> 

с

private Integer id; 

public void init() { 
    instance = em.find(PQ.class, id);  
} 

Unrelated к конкретной проблеме, я бы предложил использовать 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.

+0

Спасибо за этот ответ! Я узнал, что '@ PostConstruct' доходит до события f: event, см. Ответ Gaim в http://stackoverflow.com/questions/4988899/trying-to-use-view-parameters-in-postconstruct. Мне все еще не хватает источников/книг, в которых явным образом указывал бы такие вещи. Проблема для меня как новичка Java EE 6 заключается в том, чтобы охватить области и то, что CDI '@ Named' получило бы над JSF' @ ManagedBean', также учитывая, что почти все источники RichFaces используют комбинацию '@ManagedBean @ ViewScoped'. Я только что попробовал CDI, возможно, сбросив его сейчас. Я не вижу выигрыша для меня (пока). – Kawu

+0

Вы можете найти связанную статью «Связь в JSF 2.0» полезной для обзора «JSF 2.0 в двух словах». – BalusC

+1

О да, это замечательно, я действительно пропустил это. Благодарю. – Kawu

6

Существует лучший способ получить идентификатор от url. Просто используйте его в методе @PostConstruct Init(), чтобы получить "ID" из URL:

FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id"); 

Вы все еще можете использовать ViewScoped и @PostConstruct.