Получение параметра GET-запроса в bean-компонент @ViewScoped
У меня есть список (по запросу), из которого пользователь может выбрать "PQ" (список ссылок). При щелчке или ином вводе в браузер должна отображаться главная страница для каждого PQ. Страница каждого PQ имеет вид
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 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
фасоль?
Примечание: держу пари, что это не тривиальная вещь. Скорее всего, я делаю что-то не так концептуально, поэтому любые советы о том, как улучшить, приветствуются. Я чувствовал, что мне нужно было выбрать @ViewScoped
потому что на этой странице будет более сложный графический интерфейс на основе AJAX, который я действительно хотел бы сохранить доступным через параметры URL GET.
Спасибо
2 ответа
@PostConstruct
вызывается непосредственно после построения бина и внедрения всех зависимостей (таких как @PersistenceContext
, @EJB
, @ManagedProperty
, @Inject
и т. д. и т. д.)
<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);
}
Вне зависимости от конкретной проблемы, я бы предложил использовать Converter
вместо этого. См. Также Связь в JSF 2.0 - Преобразование и проверка параметров запроса GET.
Также комбинация @Named @ViewScoped
не будет работать как задумано. JSF-специфичный @ViewScoped
работает в сочетании со спецификой JSF @ManagedBean
только. Ваш CDI-специфичный @Named
будет вести себя как @RequestScoped
сюда. Либо использовать @ManagedBean
вместо @Named
или используйте CDI-специфичный @ConversationScoped
вместо @ViewScoped
,
Есть лучший способ получить идентификатор из URL. Просто используйте его в методе @PostConstruct init(), чтобы получить "id" из URL:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
Вы все еще можете использовать ViewScoped и @PostConstruct.