web-dev-qa-db-fra.com

télécharger le fichier avec ajax () POST Demande via Spring MVC

J'essaie de télécharger un fichier. L'action est déclenchée par ajax () Post Request. La demande envoie des données au format JSON au contrôleur. Le contrôleur génère le fichier (octets) et le renvoie.

Script Java:

function getLicenseFile() {
    $.ajax({
        type: 'POST',
        url: '<%=request.getContextPath()%>/licenses/rest/downloadLicenseFile',
        dataType: 'json',
        contentType: 'application/json;charset=UTF-8',
        data: ko.mapping.toJSON(licenseModel),
        success: function (data) {
            console.log("in sucess")
        },
        error:function (xhr, ajaxOptions, thrownError){
            console.log("in error")
        } 
    });
}  

Manette:

@RequestMapping(value = "/licenses/rest/downloadLicenseFile", method = RequestMethod.POST)
    @ResponseStatus(value=HttpStatus.OK)
    @ResponseBody
    public void createLicenseFile(@Valid @RequestBody License license, HttpServletResponse response) throws Exception {

        logger.debug("Contoller License in: "+ license);

        byte[] licensedata = licenseEncodeDefaultService.createLicenseFile(license);
        logger.debug("licenseData: " + new String(licensedata));

        response.setHeader("Content-Disposition", "attachment; filename=\"" + license.getCustomer() + ".license\"");
        response.getOutputStream().write(licensedata);
        response.flushBuffer();
    }

Problème:
* Le navigateur devrait ouvrir une boîte de téléchargement, mais cela ne se produira pas
* La réponse est gérée dans l'erreur: section de la fonction ajax (mais l'état http est OK)

Alors qu'est-ce que je fais mal ou quelle est la bonne façon de faire cela?

9
derlinuxer

Envoyez simplement une URL du fichier en réponse, puis "visitez" celle-ci dans votre rappel success.

function getLicenseFile() {
    $.ajax({
        type: 'POST',
        url: '<%=request.getContextPath()%>/licenses/rest/downloadLicenseFile',
        dataType: 'json',
        contentType: 'application/json;charset=UTF-8',
        data: ko.mapping.toJSON(licenseModel),
        success: function (data) {
            window.open(data.fileUrl);
            // or window.location.href = data.fileUrl;
        },
        error:function (xhr, ajaxOptions, thrownError) {
            console.log("in error");
        } 
    });
}

data.fileUrl doit être défini en réponse par le serveur pour indiquer au client où obtenir le fichier.

Donc, votre serveur enverra une réponse avec JSON comme

{
    "fileUrl": "http://mysite.com/files/0123456789"
}
15
Eugene Naydenov

@ will824 Si vous le demandez, je vais poster ma propre solution.

J'ai utilisé une solution de contournement dans le contrôleur et enregistrer temporairement le fichier dans le système de fichiers (/ tmp). Je sépare la fonction en 2 étapes. Créer et télécharger ... Ceci n’est pas très gentil mais me convient assez bien.

Contrôleur (créer un fichier, sera sauvegardé sur le système de fichiers du serveur):

@RequestMapping(value = "/licenses/rest", method = RequestMethod.PUT)
@ResponseStatus(value=HttpStatus.OK)
@ResponseBody
public String createLicenseFile(@Valid @RequestBody License license) throws Exception {

    // create encrypted license file and send the name back to view
    String fileName =  licenseEncodeDefaultService.createLicenseFile(license);
    return fileName;

}

Contrôleur (fichier à télécharger):

@RequestMapping(value = "/licenses/downloadFile/{file}", method = RequestMethod.GET)
public void downloadLicenseFile(@PathVariable("file") String file, HttpServletResponse response) throws Exception {

    // create full filename and get input stream
    File licenseFile = new File ("/tmp/" + file);
    InputStream is = new FileInputStream(licenseFile);

    // set file as attached data and copy file data to response output stream
    response.setHeader("Content-Disposition", "attachment; filename=\"" + file + ".license\"");
    FileCopyUtils.copy(is, response.getOutputStream());

    // delete file on server file system
    licenseFile.delete();

    // close stream and return to view
    response.flushBuffer();
}

javascript:

function getLicenseFile() {
    //console.log(ko.mapping.toJSON(licenseModel));
    $.ajax({
        type : 'PUT',
        url : '${pageContext.request.contextPath}/licenses/rest',
        dataType : 'text',
        contentType : 'application/json;charset=UTF-8',
        data : ko.mapping.toJSON(licenseModel),
        success : function(data) {
            window.location.href = '${pageContext.request.contextPath}/licenses/downloadFile/'
                    + data;
        },
        error : function(xhr, ajaxOptions, thrownError) {
            // error handling
        }
    });
}
6
derlinuxer

Si vous souhaitez télécharger le fichier sans modifier l'URL, vous pouvez appeler form.submit () par programme à la place en utilisant ajax.

Javascript:



    function downloadFileUsingForm(url) { 
        var form = document.createElement("form");
        form.method = "post";
        form.action = url;
        document.body.appendChild(form);
        form.submit();
        document.body.removeChild(form);
    }
    downloadFileUsingForm("/YourController/DownloadFile");

Manette:



    [HttpPost]
    public ActionResult DownloadFile()
    {
        string content = "Some Values";
        byte[] bytes = System.Text.UTF8Encoding.UTF8.GetBytes(content);
        return File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, "file.txt");
    }

3
user4532418

Comme les commentaires l'ont dit, vous ne pouvez pas le faire avec un appel ajax, mais vous pouvez le faire avec Javascript.

function getLicenseFile() {
    var downloadUrl = "${pageContext.request.contextPath}/licenses/rest/downloadLicenseFile";
    // (optionally) provide the user with a message that the download is starting
    window.location.href = downloadUrl;
}

Notez l'utilisation de ${pageContext.request.contextPath}, qui est préférable à <%=request.getContextPath()%>.

2
nickdos

Ajax ne va pas vous aider à essayer avec l'approche de la forme cachée

<form action='../servletname' method='POST' id='formid'>
                <input type='hidden' value='' name='name' id='id'/>
                <input type='hidden' value=' ' name='name'  id='id' />
            </form>

passez votre mot de passe via le champ de formulaire en cliquant sur votre bouton de téléchargement 

$ ('# formidable'). submit (); 

puis côté serveur 

response.setContentType("application/vnd.ms-Excel");
            response.setHeader("Content-Disposition", "attachment; filename=filnemae.fileformat");

 ServletOutputStream out = res.getOutputStream();

écrire sur le flux de sortie puis fermer ou rincer

si vous envoyez des données volumineuses via post update postsize dans server.xml

0
abhinavxeon