Как сделать перенаправление на странице нагрузки в JSF 1.x
Вопрос
У меня есть веб-приложение, в котором пользователи могут быть отправлены непосредственно на некоторые определенные страницы (такие как страница, в которой он может просматривать или редактировать элемент). Для достижения этого мы предоставляем конкретный URL. Эти URL-адреса расположены за пределами Текущее веб-приложение (т.е. они могут присутствовать в другом веб-приложении или в электронном письме).
URL выглядит как http://myserver/my-app/forward.jsf?action=XXX¶m=YYY
, куда:
- действие Представляет страницу, в которой пользователь будет перенаправлен. Вы можете рассмотреть это как
from-outcome
любого действия JSF вnavigation-case
вfaces-config.xml
. - ActionParam. является параметром для предыдущего действия (как правило, идентификатор элемента)
Так, например, я могу иметь такие URL-адреса:
http://myserver/my-app/forward.jsf?action=viewItem&actionParam=1234
http://myserver/my-app/forward.jsf?action=editItem&actionParam=1234
Конечно, у меня есть класс Java (Bean), который проверяет некоторые ограничения безопасности (т. Е. Пользователь, позволяющий видеть / редактировать соответствующий элемент?), А затем перенаправьте пользователя на правильную страницу (например, edit.xhtml
, view.xhtml
или access-denied.xhtml
).
Текущая реализация
В настоящее время у нас есть базовый способ достичь вперед. Когда пользователь нажимает на ссылку, называется следующая страница XHTML:
<html>
<body id="forwardForm">
<h:inputHidden id="myAction" binding="#{forwardBean.hiddenAction}"/>
<h:inputHidden id="myParam" binding="#{forwardBean.hiddenActionParam}"/>
<h:commandButton id="forwardBtn" actionListener="#{forwardBean.doForward}" style="display: none;"/>
</body>
<script type="text/javascript">
document.getElementById('forwardForm:forwardBtn').click();
</script>
</html>
Как вы можете видеть, я связываю два <h:inputHidden>
Компоненты в моей фасоле Java. Они будут использоваться для хранения ценности обоих action
а также actionParam
Параметр запроса (используя FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("actiontParam");
). Я также предоставляю doForward
Способ, который будет немедленно вызван, когда страница отображается, которая будет перенаправлять (снова) пользователю на реальную страницу. Метод:
public void doForward(ActionEvent evt) {
FacesContext facesContext = FacesContext.getCurrentInstance();
String redirect = // define the navigation rule that must be used in order to redirect the user to the adequate page...
NavigationHandler myNav = facesContext.getApplication().getNavigationHandler();
myNav.handleNavigation(facesContext, null, redirect);
}
Это решение работает, но у меня есть две проблемы с этим:
- Мне не нравится, как это реализуется. Я уверен, что у меня может быть что-то более простое (используя сервлет?).
- Это решение использует JavaScript, и я не должен использовать JavaScript (поскольку этот вперед может использоваться старыми пользователями BlackBerry, где JavaScript не поддерживается).
Так что мой вопрос Как ревертировать эту функцию перенаправления / вперед?
Техническая информация
Java 1.6, JSF 1.2, Facelets, Richfaces
Решение
Установите параметры получения запроса в виде управляемых свойств в faces-config.xml
Так что вам не нужно собирать их вручную:
<managed-bean>
<managed-bean-name>forward</managed-bean-name>
<managed-bean-class>com.example.ForwardBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>action</property-name>
<value>#{param.action}</value>
</managed-property>
<managed-property>
<property-name>actionParam</property-name>
<value>#{param.actionParam}</value>
</managed-property>
</managed-bean>
Таким образом, запрос forward.jsf?action=outcome1&actionParam=123
позволит JSF установить action
а также actionParam
параметры как action
а также actionParam
свойства ForwardBean
.
Создать небольшой вид forward.xhtml
(Настолько маленький, что он вписывается в буфер отклика по умолчанию (часто 2 КБ), чтобы его можно было пересмотрено навигация; beforePhase
принадлежащий f:view
:
<!DOCTYPE html>
<html xmlns:f="http://java.sun.com/jsf/core">
<f:view beforePhase="#{forward.navigate}" />
</html>
То ForwardBean
может выглядеть так:
public class ForwardBean {
private String action;
private String actionParam;
public void navigate(PhaseEvent event) {
FacesContext facesContext = FacesContext.getCurrentInstance();
String outcome = action; // Do your thing?
facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, outcome);
}
// Add/generate the usual boilerplate.
}
То navigation-rule
говорит о себе (обратите внимание на <redirect />
Записи, которые будут делать ExternalContext#redirect()
вместо ExternalContext#dispatch()
Под крышками):
<navigation-rule>
<navigation-case>
<from-outcome>outcome1</from-outcome>
<to-view-id>/outcome1.xhtml</to-view-id>
<redirect />
</navigation-case>
<navigation-case>
<from-outcome>outcome2</from-outcome>
<to-view-id>/outcome2.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
Альтернатива - использовать forward.xhtml
так как
<!DOCTYPE html>
<html>#{forward}</html>
и обновить navigate()
метод, который будет вызвать @PostConstruct
(который будет вызываться после строительства бобов и всех управляемых свойств):
@PostConstruct
public void navigate() {
// ...
}
Он имеет тот же эффект, однако сторона вид на самом деле не является самодоступным. Все это в основном делает печать ForwardBean#toString()
(И при этом неявно построил боб, если еще нет).
Примечание для пользователей JSF2, есть более чистый способ пропускания параметров с <f:viewParam>
и более надежный способ обработки перенаправления / навигации <f:event type="preRenderView">
. Отказ Смотрите также среди прочего:
Другие советы
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
response.sendRedirect("somePage.jsp");
Вы должны использовать действие вместо ActionListener:
<h:commandLink id="close" action="#{bean.close}" value="Close" immediate="true"
/>
И в тесном методе вы правильно что-то вроде:
public String close() {
return "index?faces-redirect=true";
}
где индекс является одним из ваших страниц (index.xhtml)
Конечно, все этот персонал должен быть написан на нашей оригинальной странице, а не в промежуточном состоянии. И внутри close()
Метод вы можете использовать параметры для динамического выбора, где перенаправить.
Редактировать 2.
Я наконец нашел решение, реализуя мою прямую действию, такую:
private void applyForward() {
FacesContext facesContext = FacesContext.getCurrentInstance();
// Find where to redirect the user.
String redirect = getTheFromOutCome();
// Change the Navigation context.
NavigationHandler myNav = facesContext.getApplication().getNavigationHandler();
myNav.handleNavigation(facesContext, null, redirect);
// Update the view root
UIViewRoot vr = facesContext.getViewRoot();
if (vr != null) {
// Get the URL where to redirect the user
String url = facesContext.getExternalContext().getRequestContextPath();
url = url + "/" + vr.getViewId().replace(".xhtml", ".jsf");
Object obj = facesContext.getExternalContext().getResponse();
if (obj instanceof HttpServletResponse) {
HttpServletResponse response = (HttpServletResponse) obj;
try {
// Redirect the user now.
response.sendRedirect(response.encodeURL(url));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Он работает (по крайней мере, относительно моих первых тестов), но мне все равно не нравится, как это реализуется ... Любая идея?
Редактировать Это решение делает нет работай. Действительно, когда doForward()
Функция называется, LifeCycle JSF уже запущен, а затем воссоздать новый запрос невозможен.
Одна идея, чтобы решить эту проблему, но мне это не так, чтобы заставить doForward()
действие во время одного из setBindedInputHidden()
Метод:
private boolean actionDefined = false;
private boolean actionParamDefined = false;
public void setHiddenActionParam(HtmlInputHidden hiddenActionParam) {
this.hiddenActionParam = hiddenActionParam;
String actionParam = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("actionParam");
this.hiddenActionParam.setValue(actionParam);
actionParamDefined = true;
forwardAction();
}
public void setHiddenAction(HtmlInputHidden hiddenAction) {
this.hiddenAction = hiddenAction;
String action = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("action");
this.hiddenAction.setValue(action);
actionDefined = true;
forwardAction();
}
private void forwardAction() {
if (!actionDefined || !actionParamDefined) {
// As one of the inputHidden was not binded yet, we do nothing...
return;
}
// Now, both action and actionParam inputHidden are binded, we can execute the forward...
doForward(null);
}
Это решение не связано с любым вызовом JavaScript, а также работает делает нет работай.
Предположим, что foo.jsp - ваш файл JSP. А следующий код - это кнопка, которую вы хотите сделать Redirect.
<h:commandButton value="Redirect" action="#{trial.enter }"/>
И теперь мы проверим метод направления в вашем классе Java (Service)
public String enter() {
if (userName.equals("xyz") && password.equals("123")) {
return "enter";
} else {
return null;
}
}
И теперь это часть файлов faces-config.xml
<managed-bean>
<managed-bean-name>'class_name'</managed-bean-name>
<managed-bean-class>'package_name'</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-case>
<from-outcome>enter</from-outcome>
<to-view-id>/foo.jsp</to-view-id>
<redirect />
</navigation-case>