Question

J'ai une application web où les utilisateurs peuvent être envoyés directement à certaines pages spécifiques (comme une page où il peut afficher ou modifier un élément). Pour cela, nous fournissons une URL spécifique. Ces URL sont situés extérieur la bande d'application en cours (à savoir ils peuvent être présents dans une autre application web, ou dans un e-mail).

Les regards url comme http://myserver/my-app/forward.jsf?action=XXX&param=YYY, où:

  • Action représente la page où l'utilisateur sera redirigé. Vous pouvez considérer cela comme la from-outcome de toute action JSF dans navigation-case dans faces-config.xml.
  • actionParam est un paramètre pour l'action précédente (généralement un ID d'objet)

Ainsi, par exemple, je peux avoir ce genre de urls:

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

Bien sûr, j'ai une classe Java (haricot) qui va vérifier certaines contraintes de sécurité (autrement dit, est l'utilisateur autorisé à voir / modifier l'article? Correspondant), puis rediriger l'utilisateur vers la page correcte (comme edit.xhtml, view.xhtml ou access-denied.xhtml).


mise en œuvre actuelle

À l'heure actuelle, nous avons un moyen de base pour atteindre l'avant. Lorsque l'utilisateur clique sur le lien, la page XHTML suivante est appelée:

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

Comme vous pouvez le voir, je lie deux composants <h:inputHidden> dans mon bean Java. Ils seront utilisés pour stocker la valeur des deux paramètres de demande de action et actionParam (en utilisant FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("actiontParam");). Je fournis également la méthode de doForward ce qui sera appelé immédiatement lorsque la page est rendue, qui redirigera (à nouveau) l'utilisateur à la page réelle. La méthode est la suivante:

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

Cette solution fonctionne, mais je pose deux problèmes que:

  • Je ne suis pas comme la façon dont elle est mise en œuvre. Je suis sûr que je peux avoir quelque chose de plus simple (en utilisant un Servlet?).
  • Cette solution utilise le Javascript, et je ne dois pas utiliser Javascript (comme ce terme peut être utilisé par les anciens utilisateurs de Blackberry, où le Javascript est pas pris en charge).

Alors ma question est comment factoriser cette redirection / fonction avant?

Informations techniques

Java 1.6, JSF 1.2, Facelets, RichFaces

Était-ce utile?

La solution

Définissez les paramètres de la requête GET en tant que propriétés gérées dans faces-config.xml de sorte que vous n'avez pas besoin de les rassembler manuellement:

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

De cette façon, la forward.jsf?action=outcome1&actionParam=123 demande JSF permettra de régler les paramètres action et actionParam en tant que propriétés action et actionParam du ForwardBean.

Créer une petite vue forward.xhtml (si petit qu'il tient dans le tampon de réponse par défaut (souvent 2 Ko) afin qu'il puisse être remis à zéro par le navigationhandler, sinon vous avez d'augmenter la mémoire tampon de réponse dans la configuration du servletcontainer), qui invoque une procédé de haricot sur beforePhase du f:view:

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

Le ForwardBean peut ressembler à ceci:

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

Le navigation-rule parle pour lui-même (notez les entrées de <redirect /> qui feraient ExternalContext#redirect() au lieu de ExternalContext#dispatch() sous les couvertures):

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

Une autre solution consiste à utiliser comme forward.xhtml

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

et mettre à jour la méthode navigate() à invoquer sur @PostConstruct (qui sera appelée après la construction de haricots et de tous les paramètres de propriété gérée):

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

Il a le même effet, mais du côté de la vue est pas vraiment autodocumenté. Tout ce qu'il fait essentiellement l'impression est ForwardBean#toString() (et implicitement par la présente la construction du haricot si pas encore présent).


Note pour les utilisateurs JSF2, il existe un moyen de nettoyage passer des paramètres avec <f:viewParam> et plus robuste façon de gérer la redirection / navigation par <f:event type="preRenderView">. Voir aussi, entre autres:

Autres conseils

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

vous devez utiliser l'action au lieu de actionListener:

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

et méthode proche vous droit quelque chose comme:

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

où l'index est l'une de vos pages (index.xhtml)

Bien sûr, tout ce personnel doit être écrit dans notre page originale, pas dans l'intermédiaire. Et à l'intérieur de la méthode de close() vous pouvez utiliser les paramètres de choisir dynamiquement où rediriger.

Edit 2

J'ai finalement trouvé une solution en mettant en place mon action avant comme ça:

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

Il fonctionne (au moins en ce qui concerne mes premiers essais), mais je ne toujours pas la façon dont il est mis en œuvre ... Toute meilleure idée?


Modifier Cette solution fait pas travail. En effet, lorsque la fonction doForward() est appelée, le cycle de vie du JSF a déjà démarré, puis recréer une nouvelle demande n'est pas possible.


Une idée pour résoudre ce problème, mais je ne aime pas vraiment, est de forcer l'action doForward() au cours d'une de la méthode 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);
}

Cette solution ne nécessite aucun appel Javascript et fonctionne ne pas travail.

On suppose que foo.jsp est votre fichier jsp. et le code suivant est le bouton que vous voulez faire redirect.

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

Et maintenant, nous allons vérifier la méthode pour diriger dans votre classe java (service)

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

et maintenant cela est une partie de fichier 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>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top