47 votes

POSTE de serveur, de recevoir PDF, fournir à l'utilisateur w/ jQuery

J'ai un lien sur lequel l'utilisateur clique pour obtenir un fichier PDF. En jQuery, j'ai créer un POST appel ajax vers le serveur pour obtenir le PDF. Le PDF vient à moi avec le contenu approprié en-têtes, etc qui serait normalement entraîner le navigateur pour ouvrir le Lecteur de plugin, ou de permettre à l'utilisateur d'enregistrer le fichier PDF.

Depuis que je suis arriver le PDF w/ un appel ajax, je ne suis pas sûr de quoi faire avec les données que j'ai dans la OnSuccess de rappel. Comment puis-je donner les données que je reçois pour le navigateur et de lui permettre de faire son défaut chose avec le PDF de réponse?

50voto

Regardez - Plugin jQuery pour la demande de l'Ajax comme les Téléchargements de Fichiers

L'ensemble de l' plugin est à peu près 30 lignes de code (y compris les commentaires).

L'appel est assez similaire à ajax de jquery appel.

$.download('/export.php','filename=myPDF&format=pdf&content=' + pdfData );

Bien sûr, vous devez définir le content-type et Content-Disposition des en-têtes sur le côté serveur, comme vous le feriez pour n'importe quel téléchargement.

En java, je voudrais faire quelque chose comme ceci

response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");

31voto

Sean Points 15363

Vous n'avez pas besoin de jQuery à tous. Il vous suffit de soumettre votre message via un formulaire normalement, et sur le côté serveur, ajouter l'en-tête HTTP

Content-Disposition: attachment; filename="whatever.pdf"

Le navigateur va faire son défaut chose.

Alternativement, si vous voulez être plus prudent au sujet de la déclaration des erreurs qui pourraient se produire lors de la génération de PDF, vous pouvez le faire. Publier vos paramètres de votre serveur avec jQuery. Sur le serveur, de générer le contenu binaire et cache quelque part pendant quelques minutes, accessible via une clé que vous mettez dans la session de l'utilisateur, et le retour d'un succès"," Ajax réponse à votre page (ou si il y a une erreur, le retour d'une "erreur", réponse). Si la page est de retour une réponse de réussite, il peut immédiatement faire quelque chose comme:

window.location = "/get/my/pdf";

Le serveur renvoie alors la mise en cache de contenu PDF. Assurez-vous d'inclure le Contenu de l'en-tête de Disposition, comme ci-dessus.

4voto

Mark Seefeldt Points 118

La réponse en mentionnant "Plugin jQuery pour la demande de l'Ajax comme les Téléchargements de Fichiers" got me dirigea vers la bonne direction, mais il ne fonctionne pas tout à fait pour ma situation depuis que j'ai un objet complexe et tableau d'objets de passer dans la que mes critères de recherche/filtre de données. J'ai pensé que je vous ferais partager mon code au cas où quelqu'un d'autre s'exécute dans cette situation aussi.

$.download = function (url, data, method) {
    if (url && data) {
        //convert the data object into input HTML fields
        var inputs = '';
        var convertToInput = function (key, keyStr, obj) {
            if (typeof obj === 'undefined') {
                return;
            } else if (typeof obj === "object") {
                for (var innerKey in obj) {
                    if (obj.hasOwnProperty(innerKey)) {
                        var innerKeyStr = '';
                        if (keyStr === '') {
                            innerKeyStr = innerKey.toString();
                        } else {
                            innerKeyStr = keyStr + "[" + innerKey.toString() + "]";
                        }
                        convertToInput(innerKey, innerKeyStr, obj[innerKey]);
                    }
                }
                return;
            } else if ($.isArray(obj)) {
                obj.forEach(function (item) {
                    convertToInput(key, keyStr + "[]", item);
                });
                return;
            }

            inputs += "<input type='hidden' name='" + keyStr + "' value='" + obj + "' />";
        };
        convertToInput(null, '', data);

        //send request
        jQuery('<form action="' + url + '" method="' + (method || 'post') + '">' + inputs + '</form>').appendTo('body').submit().remove();
    };
};
$.download('/api/search?format=csv', searchData, 'POST');

Il n'a probablement pas beaucoup de différence, mais pour vous expliquer le contexte, j'ai un javascript et knock-out de l'INTERFACE utilisateur appelant dans WebAPI, MVC4, et nHibernate. Le "format=csv" une partie de la chaîne de requête déclenche une MediaTypeFormatter pour convertir le retour des modèles dans un type de fichier CSV. Si je laisse ça de côté, puis-je obtenir les modèles de retour de l'API et peut remplir une Nappe de grille pour l'affichage.

2voto

Anti-g Points 1

J'ai eu le même problème mais en plus utiliser un RESTFUL webservice et ont un complexe d'objet de données que je dois poster.

Ma solution: comme le Plugin jQuery-je construire un temp formulaire et le soumettre. Mais je envoyer les données de l'objet en tant que paramètre avec le contenu json (j'utilise ici AngularJS , mais il devrait fonctionner avec jQuery.param() également).

Javascript:

$('<form target="_blank" action="' + appConstants.restbaseurl + '/print/pdf" method="POST">' + 
    "<input name='data' value='" + angular.toJson($scope.versicherung) + "' />" +
    '</form>').appendTo('body').submit().remove();

sur le côté serveur, nous utilisons un CXF REST Service avec un JACKSON Fournisseur de:

Printemps Config:

<jaxrs:server id="masterdataService" address="/">
    <jaxrs:serviceBeans>
        <ref bean="printRestServiceBean" />
    </jaxrs:serviceBeans>
    <jaxrs:providers>
        <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
        <bean class="de.controller.ExceptionHandler" />
    </jaxrs:providers>
</jaxrs:server>

dans le contrôleur, j'ai extrait les param et converti à un Pojo Java:

package de.controller;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;


@Path(Constants.PRINT_PATH)
@Consumes({ MediaType.APPLICATION_JSON, "application/x-www-form-urlencoded"})
@Produces("application/pdf; charset=UTF-8")
public class PrintRestController {

    @Autowired
    private PrintService printService;

    @POST
    @Produces("application/pdf")
    @Path("/pdf")
    public Response getPDF(@FormParam("data") String data) {
        return printService.getPDF(json2Versicherung(data));
    }

    private Versicherung json2Versicherung(String data) {
        Versicherung lVersicherung = null;
        try {
            ObjectMapper mapper = new ObjectMapper();
            lVersicherung = mapper.readValue(data, Versicherung.class);
        } catch(Exception e) {
            LOGGER.error("PrintRestController.json2Versicherung() error", e);
        }
        return lVersicherung;
    }
}

dans le PrintService-je construire le pdf binaire et la réponse:

@Override
public Response getPDF(Versicherung pVersicherung) {
    byte[] result = ... //build the pdf from what ever


    ResponseBuilder response = Response.ok((Object) result);
    response.header("Content-Disposition", "inline; filename=mypdf.pdf");
    return response.build();
}

Cette solution fonctionne pour tous les navigateurs (même pour IE9 qui ne peut pas gérer les données de l'url) et sur les tablettes et les smartphone et il n'ont pas de problèmes avec popupblockers

0voto

Ustaman Sangat Points 757

Je ne comprends pas pourquoi vous voulez une requête ajax vers un fichier url de téléchargement! Mais si c'est plus comme client lui-même qui génère un peu de contenu pour le téléchargement - utiliser des données uri. Fonctionne parfaitement pour Chrome et Firefox 20+. Safari et IE PAS! Si Flash est autorisé, vous pouvez utiliser downloadifier.

Ah, après lecture de votre code, je vois que vous voulez envoyer un tas de paramètres. Bien moins que la chaîne de requête est trop longue (IE8 - a une limite de 2083) pourquoi ne pas simplement utiliser un point d'ancrage avec une url correcte?

    $('a.export-csv').click( function (evt){
      linkEl.attr('href','/export?' + encodeURIComponent(formQueryString()));
      return true;
    });

Ci-dessus vous permet de changer l'URL avant l'événement par défaut (clic) qui se passe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X