Précédent   Forum des professionnels en informatique > Webmasters - Développement Web > JavaScript
JavaScript Forum programmation JavaScript. Lire : Cours JavaScript, FAQ JavaScript, Toutes les FAQ JavaScript et Sources JavaScript
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 06/06/2011, 10h57   #1
Membre expérimenté
 
Avatar de leminipouce
 
Homme Olivier
Ingénieur développement logiciels
Inscription : janvier 2004
Messages : 604
Détails du profil
Informations personnelles :
Nom : Homme Olivier
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : janvier 2004
Messages : 604
Points : 543
Points : 543
Par défaut [JSON][Tapestry] Téléchargement de fichier

Bonjour tout le monde,

J'ai une API Java qui me renvoie un StreamResponse quand je lui demande de télécharger une archive. J'arrive bien à récupérer l'objet JSON ou XHR qui revient avec ma requête AJAX de récupération de cette archive, mais je n'arrive pas à en récupérer le flux pour lancer le téléchargement.
Est-ce que quelqu'un saurait m'aider sur le sujet et m'indiquer comment lancer ce téléchargement ?

L'idée sous-jacente liée à l'utilisation d'AJAX est que lorsque je demande la récupération de l'archive, je lui passe un ensemble de paramètres qui déterminent comment est construite l'archive. Cette construction prend évidemment du temps et j'affiche en JS sur l'action AJAX un sablier et un message invitant à patienter. Quand je reçois mon retour AJAX, avec donc mon StreamResponse, j'aimerais lancer son téléchargement. Je n'ai évidement pas accès, avec cette API (privée) à l'adresse du fichier qui a été construit et qui va être téléchargé.

Code JavaScript dans lequel je souhaiterais lancer le téléchargement du Stream --ligne en gras
Citation:
/**
* Script prototype pour masquer et afficher la sélection des logs sur un appel AJAX de récupération des logs.
*/
var ajaxLogsRetrieverDisplay = {
onCreate : function() {
Element.show('waitWhileRetrieving');
Element.fade('logZone');
},

onComplete : function(xhr, json) {
Element.show('logZone');
Element.fade('waitWhileRetrieving');

$('logsArchive').innerHTML = xhr.responseStream;
}
};

/**
* Enregistrement du script permettant "d'intercepter" les appels/retours AJAX.
*/
AjaxLogsRetrieverTracker = {
init : function() {
Ajax.Responders.register(ajaxLogsRetrieverDisplay);
}
}
Page TML d'où proviennent les appels JavaScript/AJAX
Citation:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>

<t:content>
<body t:type="layout" title="${message:page-titre}" menuCourant="41">

<t:zone id="zoneLogSelection" t:id="zoneLogSelection">
<div class="panel" t:type="zone" t:id="logZone" id="logZone"><t:form t:id="logsForm" t:zone="zoneLogSelection">
<h1>${message:panel-log-title}</h1>
<t:loop source="logSelectors" value="rootLog" formstate="ITERATION" encoder="encoder">
<fieldset style="border-color: #e0e0e0;"><span id="${rootLog.indicator}"><legend><input t:type="checkbox" value="rootChecked"
onclick="refreshChildrenCheckBox('${rootLog.indicator}')" />&nbsp;${rootLog.label}&nbsp; </legend></span> <t:loop source="rootLog.childLogSelector" value="nodeLog"
formstate="ITERATION" encoder="encoder">
<div class="champs"><label>${nodeLog.label}</label> <input t:type="checkbox" value="nodeChecked" style="width: auto"
onclick="refreshParentCheckBox('${rootLog.indicator}')" /></div>
</t:loop></fieldset>
</t:loop>

<div style="margin-left: auto; margin-right: auto; text-align: center;"><t:linkSubmit style="text-decoration: none" id="retrieveLogs"
t:id="retrieveLogs">
<img src="${asset:charte:images}/div/arrow.gif" border="0" />&nbsp;${message:telecharger-label}</t:linkSubmit>
</div>
</t:form></div>
</t:zone>

<t:zone id="zoneWaitWhileRetrieving" t:id="zoneWaitWhileRetrieving">
<div id="waitWhileRetrieving" style="display: none">
<h2>${message:recuperation-info}</h2><img id="imgStatusDomain" src="${asset:charte:images}/status/check.gif"
alt="${message:recuperation-info}" title="${message:recuperation-info}" />
<br />
<i>${message:patience-info}</i></div>
</t:zone>

<div id="logsArchive">&nbsp;</div>
</body>
</t:content>
</html>
Code Java appelé --Il va de soit que le Thread.sleep n'est là que pour les tests....
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 
    /**
     * Méthode exécutée après le submit du formulaire.
     * 
     * @return le flux de l'archive des logs.
     */
    @Log
    StreamResponse onSuccess() {
        if (request.isXHR()) {
            LOGGER.info("Requete AJAX");
        } else {
            LOGGER.info("Requete non AJAX");
        }
 
        return new StreamResponse() {
            @Override
            public String getContentType() {
                return TAR_GZ_CONTENT_TYPE;
            }
 
            @Override
            public InputStream getStream() throws IOException {
                // final BeanDomaine beanDomaine = sessionManager.getDomaineProduit();
                /***************************/
                /** Paramètres du domaine **/
                /***************************/
                // final String envPrdt = beanDomaine.getEnvironnementProduit();
                // final String rds = beanDomaine.getRds();
                // final String dpt = beanDomaine.getDepartement();
                // final String envData = beanDomaine.getEnvironnementDonnees();
                try {
                    // return archiveRetriever.getLog(envPrdt, rds, dpt, envData, logSelectors);
 
                    final ByteArrayInputStream in =
                            new ByteArrayInputStream(new byte[] {'<', 'h', 't', 'm', 'l', '>', '<', 't', 'i', 't', 'l', 'e', '>', 't', 'o', 't', 'o', '<',
                                    '/', 't', 'i', 't', 'l', 'e', '>', '<', 'b', 'o', 'd', 'y', '>', 't', 'o', 't', 'o', '<', '/', 'b', 'o', 'd', 'y', '>',
                                    '<', '/', 'h', 't', 'm', 'l', '>'});
 
                    Thread.sleep(10000);
                    return in;
 
                    // } catch (final ArchiveRetrieverException e) {
                    // LOGGER.error("Erreur lors de l'obtention de l'archive de logs.", e);
                } catch (final InterruptedException e) {
                    LOGGER.error("Impossible de dormir 10s...", e);
                }
 
                return null;
            }
 
            @Override
            public void prepareResponse(final Response response) {
                LOGGER.info("Fichier renvoye : " + ConstantsUtils.VALUE_FOR_LOGGER, FILE_NAME);
                response.setHeader("Content-Disposition", "attachment; filename=" + FILE_NAME);
            }
        };
    }
Par avance, Merci pour votre aide,
__________________
Si , et la ont échoué mais pas nous, pensez à dire et cliquez sur . Merci !

Ici, c'est un forum, pas une foire. Il y a de respectables règles... à respecter !
leminipouce est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/06/2011, 08h16   #2
Membre expérimenté
 
Duke Jikel
Inscription : mai 2010
Messages : 340
Détails du profil
Informations personnelles :
Nom : Duke Jikel

Informations forums :
Inscription : mai 2010
Messages : 340
Points : 548
Points : 548
Si tu veux TELECHARGER un contenu/fichier/stream, et donc ouvrir la boite de téléchargement du navigateur de l'utilisateur, ce n'est pas par ajax qu'il faut passer mais pas un window.location.href = "url de ton fichier en ajax".
et coté serveur il faut changer le mime-type (content-type) pour être sur que l'utilisateur va télécharger le contenu. Dans la plupart des cas c'est :
application/force-download, si ça ne passe pas, dans l'ancien temps (2003/2004, j'utilisais : application/octet-stream en ASP 2 )

Mais sinon une recherche sur google avec les mots "forcer" et "telechargement" t'aurais permis de trouver une réponse à ton problème
dukej est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/06/2011, 10h50   #3
Membre expérimenté
 
Avatar de leminipouce
 
Homme Olivier
Ingénieur développement logiciels
Inscription : janvier 2004
Messages : 604
Détails du profil
Informations personnelles :
Nom : Homme Olivier
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : janvier 2004
Messages : 604
Points : 543
Points : 543
Salut Duke.

Citation:
Envoyé par dukej Voir le message
Mais sinon une recherche sur google avec les mots "forcer" et "telechargement" t'aurais permis de trouver une réponse à ton problème
Le problème n'est pas de télécharger le fichier, ni même de forcer le téléchargement. En l'occurence, je télécharge une archive tar.gz et mon content-type est "application/x-gzip". Pas de soucis si je renvoie en réponse de mon formulaire le ResponseStream, mon navigateur ouvre bien la fenêtre de téléchargement du fichier.

Non, le vrai problème c'est de gérer ça en AJAX...
Le workflow de mon application est le suivant :
  1. Choix parmis n listes des fichiers de logs à récupérer. (checkboxes)
  2. Demande de récupération de ces logs via un lien sur l'interface.
  3. Affichage à l'écran, sur l'action "onClick" du lien d'un message invitant à patienter pendant la création de l'archive
  4. Le serveur récupère tous les fichiers (qui se trouvent en l'occurence sur n serveurs physiques...) et crée une archive compressée de type tar.gz.
  5. Retour depuis le serveur de l'archive de logs --> Ouverture par le navigateur de la fenêtre de téléchargement.
  6. Affichage à l'utilisateur de l'écran de choix des fichiers à récupérer
Si j'oublie l'étape 6, c'est très simple à faire. JJe fais une soumission de formulaire classique et tout se passe bien. Mais je ne mets jamais à jour mon écran une fois que l'archive de logs est prête à être téléchargée --> je n'ai qu'un seul retour depuis le serveur (logique quoi...) et comme c'est un Stream il n'y a pas de mise à jour de l'écran.
Si je veux l'étape 6, je passe par AJAX, et je peux intercepter l'appel au serveur (fonction onCreate) et le retour du serveur (fonction onComplete).

Dans ma fonction onComplete, je récupère bien le retour de mon serveur. Donc si je renvoie un 'Content-Type: text/html' je peux l'afficher par exemple dans un div de ma page, ou bien dans une popup. Aucun soucis là dessus.
Par contre, si je renvoie justement un contenu à télécharger, je n'arrive pas à lancer le téléchargement. Il suffirait que je puisse ouvrir tout le retour du serveur (header inclus) dans un popup (que je ferme par exemple aussitôt après). Malheureusement je n'arrive pas à récupérer le header qui m'est renvoyé, ni forcer un header particuliers sur un popup (window.open).


Aujourd'hui, j'ai une solution de contournement ou je renvoie un lien vers mon Stream à télécharger et j'affiche dynamiquement ce lien une fois la création de l'archive terminée. Mais j'aurais préféré automatiser un peu plus la chose et éviter que mon utilisateur est besoin de cliquer 2 fois (une pour créer l'archive, une seconde pour la télécharger).
__________________
Si , et la ont échoué mais pas nous, pensez à dire et cliquez sur . Merci !

Ici, c'est un forum, pas une foire. Il y a de respectables règles... à respecter !
leminipouce est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/06/2011, 11h24   #4
Membre expérimenté
 
Duke Jikel
Inscription : mai 2010
Messages : 340
Détails du profil
Informations personnelles :
Nom : Duke Jikel

Informations forums :
Inscription : mai 2010
Messages : 340
Points : 548
Points : 548
quand ton stream te retourne ce lien, au lieu d'afficher ce lien, tu vérifies que c'est un "fichier à télécharger", et au lieu de faire :
"J'affiche le contenu dans le innerHTML de mon joli div"
tu fais un : window.location.href = monlien récupéré
et là un téléchargement se lancera automatique.

C'est ce que je te disais depuis le début, soit tu t'attends à recevoir un "fichier à télécharger", soit un contenu à afficher. Mais si ton application te retourne l'une des deux réponses, tu traites en fonction.

Qu'est ce que tu ne comprends pas dans mon explication ?
dukej est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/06/2011, 16h57   #5
Membre expérimenté
 
Avatar de leminipouce
 
Homme Olivier
Ingénieur développement logiciels
Inscription : janvier 2004
Messages : 604
Détails du profil
Informations personnelles :
Nom : Homme Olivier
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : janvier 2004
Messages : 604
Points : 543
Points : 543
Euh... à dire vrai c'est la partie redirection qui m'échappe.

Aujourd'hui, quand j'ai mon retour AJAX, je me contente d'afficher un lien (au lieu de chercher à récupérer quelque chose dans mon innerHTML...).
Ce lien c'est celui en gras ci-dessous. Et ce lien il me soumet le formulaire qui renvoie le StreamResponse :
Citation:
<t:zone id="zoneLogSelection" t:id="zoneLogSelection">
<div class="panel" t:type="zone" t:id="logZone" id="logZone">
<t:form t:id="logsForm" t:zone="zoneLogSelection">
<h1>${message:panel-log-title}</h1>
<t:loop source="logSelectors" value="rootLog" formstate="ITERATION" encoder="encoder">
<fieldset style="border-color: #e0e0e0;" id="${rootLog.indicator}">
<legend><input t:type="checkbox" value="rootChecked" onclick="refreshChildrenCheckBox('${rootLog.indicator}', this)" />&nbsp;${rootLog.label}&nbsp; </legend>
<t:loop source="rootLog.childLogSelector" value="nodeLog" formstate="ITERATION" encoder="encoder">
<div class="champs">
<label>${nodeLog.label}</label><input t:type="checkbox" value="nodeChecked" style="width: auto" onclick="refreshParentCheckBox('${rootLog.indicator}')" />
</div>
</t:loop></fieldset>
</t:loop>

<div id="buildArchive" style="margin-left: auto; margin-right: auto; text-align: center;">
<t:linkSubmit style="text-decoration: none" id="retrieveLogs" t:id="retrieveLogs" ><img src="${asset:charte:images}/div/arrow.gif" border="0" />&nbsp;${message:recuperer-label}</t:linkSubmit>
<div id="downloadArchive" style="display: none">
<a id="downloadLogs" t:type="actionlink" t:id="downloadLogs" href="#" onclick="Element.fade(this);">
<img src="${asset:charte:images}/div/arrow.gif" border="0" />&nbsp;${message:telecharger-label}
</a>

</div>
</div>
</t:form>
</div>
</t:zone>
Comme j'ai une soumission de formulaire, je vois pas bien comment m'en sortir avec ta solution à dire vrai...

En tout cas, merci pour l'intérêt que tu me portes !
__________________
Si , et la ont échoué mais pas nous, pensez à dire et cliquez sur . Merci !

Ici, c'est un forum, pas une foire. Il y a de respectables règles... à respecter !
leminipouce est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/06/2011, 17h04   #6
Membre expérimenté
 
Avatar de leminipouce
 
Homme Olivier
Ingénieur développement logiciels
Inscription : janvier 2004
Messages : 604
Détails du profil
Informations personnelles :
Nom : Homme Olivier
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : janvier 2004
Messages : 604
Points : 543
Points : 543
Je clos le sujet vu que mon contournement en affichant un lien pour le téléchargement fonctionne.
Manque de temps, je peux pas consommer plus sur une solution plus automatisé, à mon grand regret.

Concrètement, l'ouverture et la soumission de mon formulaire (ce que fait mon lien quand il est cliqué...) en JavaScript dans une pop-up est problématique vu que derrière j'ai Tapestry. J'arrive pas (manque de maîtrise sur le sujet) à générer un click sur ce lien... et que ça fonctionne.

Merci encore en tout cas.
Pouce
__________________
Si , et la ont échoué mais pas nous, pensez à dire et cliquez sur . Merci !

Ici, c'est un forum, pas une foire. Il y a de respectables règles... à respecter !
leminipouce est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 18h54.


 
 
 
 
Partenaires

Hébergement Web