Как сделать перенаправление при загрузке страницы в JSF 1.x - PullRequest
29 голосов
/ 27 октября 2010

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

URL выглядит как http://myserver/my-app/forward.jsf?action=XXX&param=YYY, где:

  • action представляет страницу, на которую будет перенаправлен пользователь. Вы можете рассматривать это как 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

Ответы [ 5 ]

29 голосов
/ 04 ноября 2010

Установите параметры запроса GET как управляемые свойства в 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 установить * 1006Параметры * и actionParam как action и actionParam свойств ForwardBean.

Создают небольшое представление forward.xhtml (настолько маленькое, что оно помещается в буфер ответов по умолчанию (часто 2 КБ), так чтоон может быть сброшен обработчиком навигации, в противном случае вам нужно увеличить буфер ответов в конфигурации сервлетконтейнера), который вызывает метод bean-компонента на 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 (который будет вызван после построения bean-компонента и всех управляемыхнастройка свойства):

@PostConstruct
public void navigate() {
    // ...
}    

Это имеет тот же эффект, чоднако сторона обзора не является самодокументированной.Все, что он в основном делает, это печатает ForwardBean#toString() (и тем самым неявно создает бин, если его еще нет).


Примечание для пользователей JSF2, есть более чистый способ передачи параметров с <f:viewParam> иболее надежный способ обработки перенаправления / навигации с помощью <f:event type="preRenderView">.См. Также среди прочего:

5 голосов
/ 27 октября 2010
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
response.sendRedirect("somePage.jsp");
2 голосов
/ 27 октября 2010

вы должны использовать action вместо actionListener:

<h:commandLink id="close" action="#{bean.close}" value="Close" immediate="true" 
                                   />

и в методе close вы исправляете что-то вроде:

public String close() {
   return "index?faces-redirect=true";
}

где index - это одна из ваших страниц (index.xhtml)

Конечно, весь этот персонал должен быть написан на нашей оригинальной странице, а не на промежуточном.А внутри метода close() вы можете использовать параметры для динамического выбора места перенаправления.

1 голос
/ 03 ноября 2010

Редактировать 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(), жизненный цикл 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, и работает не не работает.

0 голосов
/ 17 апреля 2019

Предположим, что foo.jsp - это ваш файл jsp.и следующий код - это кнопка, которую вы хотите сделать перенаправлением.

<h:commandButton value="Redirect" action="#{trial.enter }"/>  

А теперь мы проверим метод для направления в вашем классе Java (службы)

 public String enter() {
            if (userName.equals("xyz") && password.equals("123")) {
                return "enter";
            } else {
                return null;
            }
        } 

и теперь этоявляется частью файлаface-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>
...