Как сделать перенаправление на странице нагрузки в JSF 1.x

StackOverflow https://stackoverflow.com/questions/4032825

  •  26-09-2019
  •  | 
  •  

Вопрос

У меня есть веб-приложение, в котором пользователи могут быть отправлены непосредственно на некоторые определенные страницы (такие как страница, в которой он может просматривать или редактировать элемент). Для достижения этого мы предоставляем конкретный URL. Эти URL-адреса расположены за пределами Текущее веб-приложение (т.е. они могут присутствовать в другом веб-приложении или в электронном письме).

URL выглядит как http://myserver/my-app/forward.jsf?action=XXX&param=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>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top