2010-12-10 41 views
1

JSF/Seam. J'ai une page qui accepte certains paramètres fournis par l'utilisateur via un formulaire, puis (lorsque l'utilisateur clique sur un bouton de la page) le serveur génère un fichier et l'envoie dans la réponse de sorte que l'utilisateur est invité avec un enregistrement comme dialogue.Navigation dans la page/La phase de réponse de rendu est ignorée lorsque la réponse contient un fichier

Voici le scénario que je vais avoir du mal avec:

  1. Si l'utilisateur entre d'abord entrée non valide et puis clique sur le bouton, traite Seam la demande, mais arrête au processus de la phase de Validations. Ma page affiche ensuite le message d'erreur de validation.
  2. Ensuite, si l'utilisateur entre ensuite l'entrée correcte et clique sur le bouton, Seam appelle mon gestionnaire d'actions, le fichier est généré et envoyé à l'utilisateur dans la réponse - mais le message d'erreur de validation est toujours affiché!

Dans un premier temps, j'ai essayé quelques hacks pour forcer le nouveau rendu de la balise <h:messages/>, mais rien n'a été satisfaisant. Je soupçonne maintenant que la cause première est que Seam n'entre pas dans la phase de réponse de rendu lorsque je place un fichier dans la réponse.

Voici mon bouton:

<h:commandButton value="#{messages.Reports_RunReportPDF}" 
       action="#{bean.generateReportPdf}"/> 

Et voici mon gestionnaire d'action:

public String generateReportPdf() throws IOException { 
    FacesContext facesContext = FacesContext.getCurrentInstance(); 
    HttpServletResponse response = (HttpServletResponse)facesContext.getExternalContext().getResponse(); 

    ServletOutputStream servletOutputStream = response.getOutputStream(); 

    // add this header to make browser prompt user with a save-as dialog 
    response.addHeader("Content-Disposition", 
        "attachment;filename=" + reportName + ".pdf"); 
    response.setContentType(exportType.contentType()); 

    try { 
    HashMap<String, Object> parameters = getReportParameters(); 
    ReportContent content = createReport(parameters); 

    servletOutputStream.write(content.getContents()); 
    servletOutputStream.flush(); 
    servletOutputStream.close(); 
    } catch (ReportingException e) { 
    e.printStackTrace(); 
    return "fail"; 
    } 

    return "success"; 
} 

Si je en commentaire le code qui ajoute le fichier (et juste revenir "success", la page ci-après règles de navigation que j'ai configurées correctement, mais avec le fichier, la page reste exactement la même qu'avant le bouton. comment puis-je à la fois renvoyer un fichier dans la réponse et provoquer la redirection de la balise <h:messages/>?

Répondre

0

Alors, comment puis-je retourner à la fois un fichier dans la réponse, et provoquer la balise à nouveau rendu?

Cela n'est pas possible avec une seule requête HTTP. Vous pouvez renvoyer une seule réponse par requête. Ce n'est pas une limitation JSF, c'est une limitation HTTP.

Vous utilisez can JavaScript pour déclencher deux requêtes HTTP en un seul clic, mais dans votre cas particulier cela ne fonctionnerait pas bien puisque la requête JSF pour le message dépend du résultat de la requête pour le téléchargement PDF. Je ne vois pas d'autres moyens que de laisser la servlet définir une propriété d'une session gérée qui représente le statut de l'export PDF et introduire un sondage ajax qui demande cette propriété à intervalles et qui s'arrête quand elle n'est plus nulle.

+0

'" Ce n'est pas possible avec une seule requête HTTP. "' Gotcha. Je peux voir comment la solution de sondage ajax pourrait fonctionner, mais ce n'est pas une solution idéale pour nous, alors il semble que je devrais penser à aborder cela sous un autre angle. À votre santé. –

0

Ajouter à votre méthode après votre écriture

//Skip the rest of JSF phases 
FacesContext.getCurrentInstance().responseComplete(); 

Vous pouvez également ajouter la fermeture dans un bloc finally afin de vous assurer que le flux est correctement fermé si exception se produit. Ou ajouter l'annotation @Cleanup de Lombok, et il le fera automatiquement pour vous

Mise à jour

Si vous êtes à l'intérieur d'une longue conversation en cours d'exécution, vous pouvez terminer la conversation avant que la redirection, ainsi le message de validation sera supprimé.

@End(beforeRedirect=true)

+0

Cette ligne était dans mon code à l'origine - je l'ai enlevé pour voir quel serait l'effet. Cela n'affecte pas la balise de rediffusion de mes messages. –