Всё до безобразия просто. Начнем с того, что я опишу задачу, которую мне пришлось решить.
Задача: отобразить список сущьностей с кнопочкой view, при нажатии на которой открывалась бы детальная информация о сущьности.
Зарание извиняюсь за ненормативную лексику, но, как мне кажется, без неё нет возможности показать всю гамму эмоций.
Кажется просто. А хуй там. Ни в одном примере нет нормального описания такого просто Use-Case. Единственно что мне предлагали, так это использовать сессионный бин. Но у этого способа есть свои недостатки. Например нет возможности создать репрезентативный урл, пойдя по которому, ты сразу получишь контент. ПРиходилось сначала идти на страницу с таблицей, а затем, выбрав необходимую сущьность, перходить на интересующую нас «детальку».
Вот тебе бля и «мега Технология» JSF. А хочеться всего ничего, просто написать entity.page?id=1234.
Итак. Задача разбивается на две задачи:
- Как обработать параметр на «детальке»
- Как установить этот параметр в урле.
Обработать параметр очень просто. Необходимо в faces-config у бина установить managed property примерно вот так (нет особого желания прасписывать что да как).
<managed-bean>
<managed-bean-name>customer</managed-bean-name>
<managed-bean-class>com.ebon.pgw.web.beans.Customer</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>customerId</property-name>
<value>#{param.id}</value>
</managed-property>
</managed-bean>
Скажу лишь одно, что param и обозначает параметр передаваемый в запросе.
Вторая задача оказалась по сложнее. Я лишь опишу, как я её решил, сам процесс решения я описывать не буду, дабы не засорять статью табуированной лексикой :).
Помогла мне в решении статья Vladimir Petrukhinа «JSF и ЧПУ (Человеко-понятный урл)«. Именно благодаря ней я узнал, как можно поменять возвращаемый урл. Так как я использовал MyFaces, то мой ViewHandler наследовался от JspViewHandlerImpl. Вот его код.
package test;
import java.util.Map;
import javax.faces.context.FacesContext;
import org.apache.myfaces.application.jsp.JspViewHandlerImpl;
public class GetParamViewHandler extends JspViewHandlerImpl {
private static final Log log = LogFactory.getLog(GetParamViewHandler.class);
@Override
public String getActionURL(FacesContext facesContext, String viewId) {
String actionURL = super.getActionURL(facesContext, viewId);
Map<String, Object> requestParameterMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
String id = (String) requestParameterMap.get("id");
if (id!=null) {
actionURL += "?id=" + id;
requestParameterMap.remove("id");
}
log.info("viewId[%s] actionUrl[%s]", viewId, actionURL);
return actionURL;
}
}
Соответсвенно его необходимо прописать в faces-config.xml
<application>
<view-handler>test.GetParamViewHandler</view-handler>
</application>
Для того, чтобы установить соответсвующий id необходимо использовать f:param примерно так:
<h:commandLink value="view" action="customer" immediate="true">
<f:setPropertyActionListener value="#{customer.value.merchantId}" target="#{customers.customerId}"/>
<f:param name="id" value="#{customer.value.merchantId}"/>
</h:commandLink>
Вот наверное и всё. Если у кого есть вопросы и дельные замечания, welcome to comments :)
UPD: Оказалось, что не всё так просто. Во первых, код надо немного переписать (запосчу его позже), во вторых…. А вот про во-вротрых по подробнее.
Описанный выше метод прекрасно работает при простой навигации. А если мне необходимо отредактировать бин. Вот и пришел пиздец. Оказывается, что JSF пытается после нашего клика провести восстановление состояния view (LifeCycle Phase : Restore View), и именно в этот момент у происходит всё заново. А заново не получится, т.к. у нас уже нет в запросе параметра id. Как сделать так, чтобы состояние нормально восстанавливалось я не знаю. Увы :(.