JSF : rafraichir une page après un téléchargement

Imaginons une action disponible dans une application web, qui, dans un premier temps, modifie l'état d'objets sur le serveur et dans un second temps propose un fichier en téléchargement. Il faut donc qu'à la fin du téléchargement, la page courante soit rafraîchie pour voir les nouveaux états des objets...

Dans l'absolu, ceci est impossible en une seule action, puisque le protocole HTTP lui-même est basé sur un principe de requête-réponse unique. Il faudrait donc lancer deux requêtes successives, respectivement pour télécharger le fichier et rafraîchir ensuite la page.

Mais il est cependant possible de contourner ce problème en utilisant les headers HTTP : c'est ainsi le navigateur qui, à leur réception, prendra l'initiative de rafraîchir la page courante. Voici la méthode qui permet de faire ceci :

 public static void downloadFile(File toDL, String newName, boolean refreshAfterDownload) throws IOException {
  byte[] bbuf = new byte[1024];
  int length = 0;
  FileInputStream in = new FileInputStream(toDL);
  FacesContext context = FacesContext.getCurrentInstance();
  HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
  response.setContentType(determineContentType(toDL));
  response.setContentLength(in.available());
  response.setHeader("Content-Disposition", "attachment; filename=\"" + newName + "\"");
  if (refreshAfterDownload) {
   response.addHeader("refresh", "0.1");
  }
  ServletOutputStream sop = response.getOutputStream();
  while ((in != null) && ((length = in.read(bbuf)) != -1)) {
   sop.write(bbuf, 0, length);
  }
  in.close();
  sop.flush();
  context.responseComplete();
 }

Comme on peut le voir, c'est le header "Refresh" qui permettra d'indiquer au navigateur que la page doit être rafraîchie après réception du fichier.

Note :

Il est possible de spécifier au header Refresh, en plus du temps avant rafraîchissement, l'url vers laquelle se rediriger :

response.addHeader("refresh", "0.1;url="+newURL);

Cependant cela peut poser certains problèmes. J'ai en effet pu remarquer un comportement non expliqué sous certains navigateurs : avec Firefox par exemple, lorsque le fichier est proposé en téléchargement, si l'utilisateur choisi l'option "Ouvrir le fichier", tout se déroulera correctement, alors que s'il choisi l'option "Enregistrer", le navigateur semble perdre le FacesContext courant et n'arrive pas à accéder à la page indiquée... De la même façon, si l'utilisateur annule le téléchargement, la page ne sera pas actualisée.

Je n'ai pas assez approfondi mes recherches quant à la configuration du FacesContext ou au comportement du navigateur selon les cas, mais toute aide sera la bienvenue!


Fichier(s) joint(s) :

2 commentaires:

Capibara a dit…

Mais d'où te viennent ces idées de ticket ?

Paul-Emmanuel Faidherbe a dit…

D'un projet passionnant, qui a encore pleins d'intéressantes choses à me faire découvrir!!