webentwicklung-frage-antwort-db.com.de

So führen Sie eine Umleitung beim Laden von Seiten in JSF 1.x durch

Ich habe eine Webanwendung, mit der die Benutzer direkt zu bestimmten Seiten weitergeleitet werden können (z. B. zu einer Seite, auf der sie ein Element anzeigen oder bearbeiten können). Um dies zu erreichen, geben wir eine spezifische URL an. Diese URLs befinden sich außerhalb der aktuellen Webanwendung (d. H. Sie können in einer anderen Webanwendung oder in einer E-Mail vorhanden sein).

Die URL sieht aus wie http://myserver/my-app/forward.jsf?action=XXX&param=YYY, Wobei:

  • Aktion repräsentiert die Seite, auf die der Benutzer umgeleitet wird. Sie können dies als from-outcome Einer JSF-Aktion in navigation-case In faces-config.xml Betrachten.
  • actionParam ist ein Parameter für die vorherige Aktion (im Allgemeinen eine Artikel-ID)

So kann ich zum Beispiel diese Art von URLs haben:

  • http://myserver/my-app/forward.jsf?action=viewItem&actionParam=1234
  • http://myserver/my-app/forward.jsf?action=editItem&actionParam=1234

Natürlich habe ich eine Java class (bean)), die einige Sicherheitsbeschränkungen überprüft (dh darf der Benutzer das entsprechende Element sehen/bearbeiten?) Und den Benutzer dann auf die richtige Seite umleitet (wie edit.xhtml, view.xhtml oder access-denied.xhtml).


Aktuelle Implementierung

Derzeit haben wir einen grundlegenden Weg, um den Fortschritt zu erreichen. Wenn der Benutzer auf den Link klickt, wird die folgende XHTML-Seite aufgerufen:

<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>

Wie Sie sehen, binde ich zwei <h:inputHidden> - Komponenten in meine Java= Bean. Sie werden verwendet, um den Wert von action und actionParam request parameter (using FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("actiontParam");). Ich biete auch die doForward -Methode an, die beim Rendern der Seite sofort aufgerufen wird und den Benutzer (wieder) auf die reale Seite umleitet Die Methode ist:

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);
}

Diese Lösung funktioniert, aber ich habe zwei Probleme damit:

  • Mir gefällt die Umsetzung nicht. Ich bin sicher, dass ich etwas einfacheres haben kann (mit einem Servlet?).
  • Diese Lösung verwendet Javascript und ich darf kein Javascript verwenden (da diese Weiterleitung möglicherweise von alten Blackberry-Benutzern verwendet wird, bei denen Javascript nicht unterstützt wird).

Meine Frage lautet also wie kann ich diese Umleitungs-/Weiterleitungsfunktion umgestalten?

Technische Informationen

Java 1.6, JSF 1.2, Facelets, Richfaces

30
Romain Linsolas

Legen Sie die GET-Abfrageparameter in faces-config.xml Als verwaltete Eigenschaften fest, damit Sie sie nicht manuell erfassen müssen:

<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>

Auf diese Weise kann JSF mit der Anforderung forward.jsf?action=outcome1&actionParam=123 Die Parameter action und actionParam als action und actionParam -Eigenschaften von ForwardBean.

Erstellen Sie eine kleine Ansicht forward.xhtml (So klein, dass sie in den Standardantwortpuffer (häufig 2 KB) passt, damit sie vom Navigationshandler zurückgesetzt werden kann. Andernfalls müssen Sie den Antwortpuffer in der Konfiguration des Servletcontainers erhöhen.) ruft eine Bean-Methode für beforePhase des f:view auf:

<!DOCTYPE html>
<html xmlns:f="http://Java.Sun.com/jsf/core">
    <f:view beforePhase="#{forward.navigate}" />
</html>

Das ForwardBean kann so aussehen:

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.
}

Das navigation-rule Spricht für sich selbst (beachten Sie die <redirect /> - Einträge, die ExternalContext#redirect() anstelle von ExternalContext#dispatch() unter der Decke ausführen würden):

<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>

Eine Alternative ist die Verwendung von forward.xhtml Als

<!DOCTYPE html>
<html>#{forward}</html>

und aktualisiere die navigate() -Methode, die für @PostConstruct aufgerufen werden soll (die nach der Konstruktion von Bean und der Einstellung aller verwalteten Eigenschaften aufgerufen wird):

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

Dies hat den gleichen Effekt, jedoch ist die Ansichtsseite nicht wirklich selbstdokumentierend. Alles, was es im Grunde tut, ist das Drucken von ForwardBean#toString() (und dabei implizit die Bean zu konstruieren, falls sie noch nicht vorhanden ist).


Beachten Sie für die JSF2-Benutzer, dass es eine sauberere Methode für die Übergabe von Parametern mit <f:viewParam> Und eine robustere Methode für die Behandlung der Umleitung/Navigation mit <f:event type="preRenderView"> Gibt. Siehe auch unter anderem:

30
BalusC
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
response.sendRedirect("somePage.jsp");
5
jnr

sie sollten action anstelle von actionListener verwenden:

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

und in enger methode berichtigst du so etwas wie:

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

wobei index eine Ihrer Seiten ist (index.xhtml)

Natürlich sollten all diese Mitarbeiter auf unserer Originalseite und nicht in der Zwischenzeit geschrieben sein. Innerhalb der close() -Methode können Sie mithilfe der Parameter dynamisch auswählen, wohin umgeleitet werden soll.

2
Vladimir Ivanov

Edit 2

Endlich habe ich eine Lösung gefunden, indem ich meine Forward-Aktion folgendermaßen implementiert habe:

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();
            }
        }
    }
}

Es funktioniert (zumindest in Bezug auf meine ersten Tests), aber mir gefällt immer noch nicht, wie es implementiert wird ... Irgendeine bessere Idee?


Bearbeiten Diese Lösung funktioniert nicht. Wenn die Funktion doForward() aufgerufen wird, wurde der JSF-Lebenszyklus bereits gestartet, und eine erneute Erstellung einer neuen Anforderung ist nicht möglich.


Eine Idee, um dieses Problem zu lösen, aber ich mag es nicht wirklich, ist, die Aktion doForward() während einer der Methoden setBindedInputHidden() zu erzwingen:

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);
}

Diese Lösung beinhaltet keinen Javascript-Aufruf und funktioniert funktioniert nicht.

1
Romain Linsolas

Angenommen, foo.jsp ist Ihre JSP-Datei. Der folgende Code ist die Schaltfläche, die Sie umleiten möchten.

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

Und jetzt prüfen wir die Methode für die Weiterleitung in Ihrer Java (service) -Klasse

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

und jetzt ist dies ein Teil der Datei 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>
0
berkancetin