web-dev-qa-db-ja.com

POSTサーバーに送信、PDFを受信、jQueryでユーザーに配信/

ユーザーがPDFを取得するためにクリックするリンクがあります。 jQueryで、サーバーへのPOST ajax呼び出しを作成してPDFを取得します。PDFは、通常、ブラウザでReaderプラグインを開くか、ユーザーがPDFを保存できるようにします。

PDF w/ajax呼び出しを取得しているので、OnSuccessコールバックで取得したデータをどう処理するかわからない。ブラウザを使用して、PDF応答?

47
bryanvick

JQueryはまったく必要ありません。 POSTを通常のフォーム経由で送信し、サーバー側でHTTPヘッダーを追加します

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

ブラウザはデフォルトの処理を行います。

または、PDFの生成中に発生する可能性のあるエラーを報告することにより注意したい場合は、これを行うことができます。POSTサーバーへのパラメータサーバー上で、バイナリコンテンツを生成し、数分キャッシュして、ユーザーのセッションに入力したキーを介してアクセスし、ページに「成功」​​Ajax応答を返します(またはエラーがあった場合、「エラー」レスポンスを返します。ページが成功レスポンスを返した場合、すぐに次のようなことができます。

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

サーバーはキャッシュされたPDFコンテンツを返します。上記のように、Content-Dispositionヘッダーを必ず含めてください。

31
Sean

ご覧ください- jjakプラグインAjaxのようなファイルのダウンロードを要求するための(

plugin全体は約30行のコード(コメントを含む)です。

この呼び出しは、jquery ajax呼び出しにかなり似ています。

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

もちろん、このようなダウンロードの場合と同様に、サーバー側でcontent-typeおよびContent-Dispositionヘッダーを設定する必要があります。

Java私はこのようなことをします

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

「Ajaxに似たファイルのダウンロードを要求するjQueryプラグイン」に言及した答えは、私を正しい方向に向かわせましたが、私の検索条件として渡す複雑なオブジェクトとオブジェクトの配列があるため、私の状況では完全に機能しませんでしたデータをフィルターします。他の誰かがこのような状況に陥った場合に備えて、コードを共有すると思いました。

$.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');

おそらく大きな違いはありませんが、コンテキストを提供するために、WebAPI、MVC4、nHibernateを呼び出すjavascriptとノックアウトUIを用意しています。クエリ文字列の「format = csv」部分は、MediaTypeFormatterをトリガーして、返されたモデルをCSVファイルタイプに変換します。そのままにしておくと、APIからモデルが返され、表示用にSlickグリッドを設定できます。

4
Mark Seefeldt

私は同じ問題を抱えていましたが、これには_RESTFUL webservice_を使用し、投稿する必要がある複雑なデータオブジェクトがあります。

私の解決策:jQueryプラグインのように、私は一時式を作成して送信します。ただし、jsonコンテンツのパラメーターとしてデータオブジェクトを送信します(ここではAngularJSを使用しますが、jQuery.param()でも動作するはずです)。

Javascript:

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

サーバー側では、JACKSONプロバイダーで_CXF REST Service_を使用します。

Spring 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>
_

コントローラーでパラメーターを抽出し、Java Pojo:

_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;
    }
}
_

printServiceで、pdfバイナリと応答を作成します。

_@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();
}
_

このソリューションは、すべてのブラウザー(データurlを処理できないIE9でも)およびタブレットとスマートフォンで機能し、popupblockersに問題はありません。

2
Anti-g

AjaxのようなファイルのダウンロードをリクエストするjQueryプラグインは、基本的にフォームを作成し、投稿データを非表示フィールドとして追加し、ページの本文に追加し、送信して削除します。

私の場合、フォームはありませんでした。データのチャンクだけがそのまま投稿されます。それが次の解決策になりました。サーバー側では、リクエストから「data」パラメータを読み取り、それをURIデコードするだけでデータを取得できます。

function postAndDownload(url, data) {

    encodedData = encodeURIComponent(data);

    $("<form>")
        .attr("action", url)
        .attr("method", "post")
        .append(
            $("input")
                .attr("type", "hidden")
                .attr("name", "data")
                .attr("value", encodedData)
        )
        .appendTo("body")
        .submit()
        .remove();
};
1
MichaelK

ファイルダウンロードURLへのajaxリクエストが必要な理由を理解できません。しかし、クライアント自体がダウンロード用のコンテンツを生成するようなものであれば、データURIを使用します。 ChromeおよびFirefox 20以降。SafariおよびIE NOT!Flashが許可されている場合、downloadifierを使用できます。

ああ、コードを読んだ後、たくさんのパラメーターを送信したいのです。クエリ文字列が長くなりすぎない限り(IE8-には2083の制限があります)、適切なURLで単にアンカーを使用しないのはなぜですか?

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

上記により、デフォルトのイベント(クリック)が発生する前にURLを変更できます。

0
Ustaman Sangat