J'ai une action Struts2 du côté serveur pour le téléchargement de fichiers.
<action name="download" class="com.xxx.DownAction">
<result name="success" type="stream">
<param name="contentType">text/plain</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">attachment;filename={fileName}</param>
<param name="bufferSize">1024</param>
</result>
</action>
Cependant, lorsque j'appelle l'action à l'aide de jQuery :
$.post(
"/download.action",{
para1:value1,
para2:value2
....
},function(data){
console.info(data);
}
);
dans Firebug, je vois que les données sont récupérées avec le flux binaire. Je me demande comment ouvrir la fitre de téléchargement de fichier avec laquelle l'utilisateur peut enregistrer le fichier localement ?
Mise à jour des navigateurs modernes de 2019
C'est l'approche que je recommande maintenant, avec quelques réserves :
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(resp => resp.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
// the filename you want
a.download = 'todo-1.json';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
alert('your file has downloaded!'); // or you know, something with better UX...
})
.catch(() => alert('oh no!'));
2012 Approche originale basée sur jQuery/iframe/Cookie.
Bluish a tout à fait raison sur ce point, vous ne pouvez pas le faire via Ajax car JavaScript ne peut pas enregistrer des fichiers directement sur l'ordinateur d'un utilisateur (pour des raisons de sécurité). Malheureusement, en faisant pointer l'URL de la fenêtre principale vers votre fichier à télécharger, vous avez peu de contrôle sur l'expérience de l'utilisateur lorsqu'un fichier est téléchargé.
J'ai créé [jQuery File Download][2] qui permet une expérience de type "Ajax" pour les téléchargements de fichiers, avec des rappels OnSuccess et OnFailure pour offrir une meilleure expérience utilisateur. Jetez un coup d'œil à mon [article de blog][3] sur le problème courant que le plugin résout et sur quelques façons de l'utiliser, ainsi qu'à une [démo de jQuery File Download en action][4]. Voici la [source][5]
Voici une démonstration d'un cas d'utilisation simple utilisant le plugin [source][6] avec des promesses. La [page de démonstration][7] contient également de nombreux autres exemples d'amélioration de l'interface utilisateur.
$.fileDownload('some/file.pdf')
.done(function () { alert('File download a success!'); })
.fail(function () { alert('File download failed!'); });
Selon les navigateurs que vous devez prendre en charge, vous pouvez utiliser https://github.com/eligrey/FileSaver.js/ qui permet un contrôle plus explicite que la méthode IFRAME utilisée par jQuery File Download.
[2] : http://johnculviner.com/post/2012/03/22/Ajax-like-feature-rich-file-downloads-with-jQuery-File-Download.aspx [3] : http://johnculviner.com/post/2012/03/22/Ajax-like-feature-rich-file-downloads-with-jQuery-File-Download.aspx [4] : http://jqueryfiledownload.apphb.com/ [5] : http://github.com/johnculviner/jquery.fileDownload/blob/master/src/Scripts/jquery.fileDownload.js [6] : http://github.com/johnculviner/jquery.fileDownload/blob/master/src/Scripts/jquery.fileDownload.js [7] : http://jqueryfiledownload.apphb.com/
*Personne n'a publié cette solution de @Pekka... alors je vais la publier. Elle peut aider quelqu'un.
Vous n'avez pas besoin d'utiliser Ajax pour faire cela. Utilisez simplement
window.location="download.action?para1=value1...."
1. Agnostique : Servlet téléchargeant un fichier en pièce jointe.
<!-- with JS -->
<a href="javascript:window.location='downloadServlet?param1=value1'">
download
</a>
<!-- without JS -->
<a href="downloadServlet?param1=value1" >download</a>
2. Struts2 Framework : Action téléchargeant le fichier en pièce jointe
<!-- with JS -->
<a href="javascript:window.location='downloadAction.action?param1=value1'">
download
</a>
<!-- without JS -->
<a href="downloadAction.action?param1=value1" >download</a>
Il serait préférable d'utiliser la balise <s:a>
pointant avec OGNL vers un URL créé avec la balise <s:url>
:
<!-- without JS, with Struts tags: THE RIGHT WAY -->
<s:url action="downloadAction.action" var="url">
<s:param name="param1">value1</s:param>
</s:ulr>
<s:a href="%{url}" >download</s:a>
Dans les cas ci-dessus, vous devez écrire l'en-tête Content-Disposition dans la réponse, en spécifiant que le fichier doit être téléchargé (attachment
) et non ouvert par le navigateur (inline
). Vous devez également spécifier le Type de contenu, et vous pouvez ajouter le nom et la longueur du fichier (pour aider le navigateur à dessiner une barre de progression réaliste).
Par exemple, lors du téléchargement d'un ZIP :
response.setContentType("application/zip");
response.addHeader("Content-Disposition",
"attachment; filename=\"name of my file.zip\"");
response.setHeader("Content-Length", myFile.length()); // or myByte[].length...
Avec Struts2 (à moins que vous n'utilisiez l'action en tant que servlet, un hack [pour le streaming direct] (https://stackoverflow.com/a/16654313/1654265), par exemple), vous n'avez pas besoin d'écrire directement quoi que ce soit dans la réponse ; il suffit d'utiliser le [type de résultat de streaming] (http://struts.apache.org/release/2.3.x/struts2-core/apidocs/org/apache/struts2/dispatcher/StreamResult.html) et de le configurer dans struts.xml : EXEMPLE
<result name="success" type="stream">
<param name="contentType">application/zip</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
<param name="contentLength">${fileLength}</param>
</result>
3. Cadre agnostique (/ cadre Struts2) : Servlet(/Action) ouvrant le fichier à l'intérieur du navigateur
Si vous voulez ouvrir le fichier dans le navigateur, au lieu de le télécharger, le Contenu-disposition doit être défini sur inline, mais la cible ne peut pas être l'emplacement actuel de la fenêtre ; vous devez cibler une nouvelle fenêtre créée par javascript, un lt;iframe>
dans la page, ou une nouvelle fenêtre créée à la volée avec le "discussed" ; target="_blank" :
<!-- From a parent page into an IFrame without javascript -->
<a href="downloadServlet?param1=value1" target="iFrameName">
download
</a>
<!-- In a new window without javascript -->
<a href="downloadServlet?param1=value1" target="_blank">
download
</a>
<!-- In a new window with javascript -->
<a href="javascript:window.open('downloadServlet?param1=value1');" >
download
</a>