Java 使用 Ajax 下载并打开 PDF 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1999607/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:17:19  来源:igfitidea点击:

Download and open PDF file using Ajax

javascriptjavajquerypdf

提问by Nayn

I have an action class that generates a PDF. The contentTypeis set appropriately.

我有一个生成 PDF 的操作类。该contentType适当地设定。

public class MyAction extends ActionSupport 
{
   public String execute() {
    ...
    ...
    File report = signedPdfExporter.generateReport(xyzData, props);

    inputStream = new FileInputStream(report);
    contentDisposition = "attachment=\"" + report.getName() + "\"";
    contentType = "application/pdf";
    return SUCCESS;
   }
}

I call this actionthrough an Ajax call. I don't know the way to deliver this stream to browser. I tried a few things but nothing worked.

action通过 Ajax 调用来调用它。我不知道如何将此流传送到浏览器。我尝试了几件事,但没有任何效果。

$.ajax({
    type: "POST",
    url: url,
    data: wireIdList,
    cache: false,
    success: function(response)
    {
        alert('got response');
        window.open(response);
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) 
    {
        alert('Error occurred while opening fax template' 
              + getAjaxErrorString(textStatus, errorThrown));
    }
});

The above gives the error:

以上给出了错误:

Your browser sent a request that this server could not understand.

您的浏览器发送了此服务器无法理解的请求。

采纳答案by BalusC

You don't necessarily need Ajax for this. Just an <a>link is enough if you set the content-dispositionto attachmentin the server side code. This way the parent page will just stay open, if that was your major concern (why would you unnecessarily have chosen Ajax for this otherwise?). Besides, there is no way to handle this nicely acynchronously. PDF is not character data. It's binary data. You can't do stuff like $(element).load(). You want to use completely newrequest for this. For that <a href="pdfservlet/filename.pdf">pdf</a>is perfectly suitable.

为此,您不一定需要 Ajax。<a>如果您在服务器端代码中设置content-dispositionto attachment,只需一个链接就足够了。这样父页面将保持打开状态,如果这是您的主要关注点(否则您为什么会不必要地为此选择 Ajax?)。此外,没有办法很好地异步处理这个问题。PDF 不是字符数据。是二进制数据。你不能做这样的事情$(element).load()。您想为此使用全新的请求。因为那<a href="pdfservlet/filename.pdf">pdf</a>是完全合适的。

To assist you more with the server side code, you'll need to tell more about the language used and post an excerpt of the code attempts.

为了在服务器端代码方面为您提供更多帮助,您需要详细说明所使用的语言并发布代码尝试的摘录。

回答by Emil Vikstr?m

Do you have to do it with Ajax? Coouldn't it be a possibility to load it in an iframe?

你必须用 Ajax 来做吗?难道不能在 iframe 中加载它吗?

回答by qalhat

create a hidden iframe, then in your ajax code above:

创建一个隐藏的 iframe,然后在上面的 ajax 代码中:

url:document.getElementById('myiframeid').src = your_server_side_url,

网址:document.getElementById('myiframeid').src = your_server_side_url

and remove the window.open(response);

并删除 window.open(response);

回答by chiccodoro

I don't really think that any of the past answers spotted out the problem of the original poster. They all presume a GET request while the poster was trying to POST data and get a download in response.

我真的认为过去的任何答案都没有发现原始海报的问题。当发布者尝试 POST 数据并获取下载作为响应时,它们都假定一个 GET 请求。

In the course of searching for any better answer we found this jQuery Plugin for Requesting Ajax-like File Downloads.

在寻找任何更好的答案的过程中,我们找到了这个用于请求类似 Ajax 的文件下载的 jQuery 插件

In its "heart" it creates a "temporary" HTML form containing the given data as input fields. This form is appended to the document and posted to the desired URL. Right after that the form is removed again:

在其“核心”中,它创建了一个“临时”HTML 表单,其中包含作为输入字段的给定数据。此表单将附加到文档并发布到所需的 URL。紧接着,表单再次被删除:

jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
    .appendTo('body').submit().remove()

UpdateMayur's answer looks pretty promising and very simple in comparison to the jQuery plug-in I referred to.

与我提到的 jQuery 插件相比,更新Mayur 的答案看起来非常有希望并且非常简单。

回答by Ijas Ameenudeen

You could use this plugin which creates a form, and submits it, then removes it from the page.

你可以使用这个插件来创建一个表单,并提交它,然后从页面中删除它。

jQuery.download = function(url, data, method) {
    //url and data options required
    if (url && data) {
        //data can be string of parameters or array/object
        data = typeof data == 'string' ? data : jQuery.param(data);
        //split params into form inputs
        var inputs = '';
        jQuery.each(data.split('&'), function() {
            var pair = this.split('=');
            inputs += '<input type="hidden" name="' + pair[0] +
                '" value="' + pair[1] + '" />';
        });
        //send request
        jQuery('<form action="' + url +
                '" method="' + (method || 'post') + '">' + inputs + '</form>')
            .appendTo('body').submit().remove();
    };
};


$.download(
    '/export.php',
    'filename=mySpreadsheet&format=xls&content=' + spreadsheetData
);

This worked for me. Found this plugin here

这对我有用。在这里找到了这个插件

回答by Mayur Padshala

Here is how I got this working

这是我如何工作的

$.ajax({
  url: '<URL_TO_FILE>',
  success: function(data) {
    var blob=new Blob([data]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
    link.click();
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Updated answer using download.js

使用download.js更新答案

$.ajax({
  url: '<URL_TO_FILE>',
  success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});

回答by George Siggouroglou

This is how i solve this issue.
The answer of Jonathan Amend on this posthelped me a lot.
The example below is simplified.

这就是我解决这个问题的方法。
Jonathan Amend 在这篇文章中的回答对我帮助很大。
下面的例子是简化的。

For more details, the above source code is able to download a file using a JQuery Ajax request (GET, POST, PUT etc). It, also, helps to upload parameters as JSON and to change the content type to application/json (my default).

有关更多详细信息,上述源代码能够使用 JQuery Ajax 请求(GET、POST、PUT 等)下载文件。它还有助于将参数上传为JSON 并将内容类型更改为 application/json (my default)

The htmlsource:

HTML源:

<form method="POST">
    <input type="text" name="startDate"/>
    <input type="text" name="endDate"/>
    <input type="text" name="startDate"/>
    <select name="reportTimeDetail">
        <option value="1">1</option>
    </select>
    <button type="submit"> Submit</button>
</form>  

A simple form with two input text, one select and a button element.

一个简单的表单,有两个输入文本,一个选择和一个按钮元素。

The javascript pagesource:

JavaScript的网页来源:

<script type="text/javascript" src="JQuery 1.11.0 link"></script>
<script type="text/javascript">
    // File Download on form submition.
    $(document).on("ready", function(){
        $("form button").on("click", function (event) {
            event.stopPropagation(); // Do not propagate the event.

            // Create an object that will manage to download the file.
            new AjaxDownloadFile({
                url: "url that returns a file",
                data: JSON.stringify($("form").serializeObject())
            });

            return false; // Do not submit the form.
        });
    });
</script>  

A simple event on button click. It creates an AjaxDownloadFile object. The AjaxDownloadFile class source is below.

一个简单的按钮点击事件。它创建了一个 AjaxDownloadFile 对象。AjaxDownloadFile 类源如下。

The AjaxDownloadFile classsource:

AjaxDownloadFile类来源:

var AjaxDownloadFile = function (configurationSettings) {
    // Standard settings.
    this.settings = {
        // JQuery AJAX default attributes.
        url: "",
        type: "POST",
        headers: {
            "Content-Type": "application/json; charset=UTF-8"
        },
        data: {},
        // Custom events.
        onSuccessStart: function (response, status, xhr, self) {
        },
        onSuccessFinish: function (response, status, xhr, self, filename) {
        },
        onErrorOccured: function (response, status, xhr, self) {
        }
    };
    this.download = function () {
        var self = this;
        $.ajax({
            type: this.settings.type,
            url: this.settings.url,
            headers: this.settings.headers,
            data: this.settings.data,
            success: function (response, status, xhr) {
                // Start custom event.
                self.settings.onSuccessStart(response, status, xhr, self);

                // Check if a filename is existing on the response headers.
                var filename = "";
                var disposition = xhr.getResponseHeader("Content-Disposition");
                if (disposition && disposition.indexOf("attachment") !== -1) {
                    var filenameRegex = /filename[^;=\n]*=(([""]).*?|[^;\n]*)/;
                    var matches = filenameRegex.exec(disposition);
                    if (matches != null && matches[1])
                        filename = matches[1].replace(/[""]/g, "");
                }

                var type = xhr.getResponseHeader("Content-Type");
                var blob = new Blob([response], {type: type});

                if (typeof window.navigator.msSaveBlob !== "undefined") {
                    // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed.
                    window.navigator.msSaveBlob(blob, filename);
                } else {
                    var URL = window.URL || window.webkitURL;
                    var downloadUrl = URL.createObjectURL(blob);

                    if (filename) {
                        // Use HTML5 a[download] attribute to specify filename.
                        var a = document.createElement("a");
                        // Safari doesn"t support this yet.
                        if (typeof a.download === "undefined") {
                            window.location = downloadUrl;
                        } else {
                            a.href = downloadUrl;
                            a.download = filename;
                            document.body.appendChild(a);
                            a.click();
                        }
                    } else {
                        window.location = downloadUrl;
                    }

                    setTimeout(function () {
                        URL.revokeObjectURL(downloadUrl);
                    }, 100); // Cleanup
                }

                // Final custom event.
                self.settings.onSuccessFinish(response, status, xhr, self, filename);
            },
            error: function (response, status, xhr) {
                // Custom event to handle the error.
                self.settings.onErrorOccured(response, status, xhr, self);
            }
        });
    };
    // Constructor.
    {
        // Merge settings.
        $.extend(this.settings, configurationSettings);
        // Make the request.
        this.download();
    }
};

I created this class to added to my JS library. It is reusable. Hope that helps.

我创建了这个类来添加到我的 JS 库中。它是可重复使用的。希望有帮助。

回答by ParPar

What worked for me is the following code, as the server function is retrieving File(memoryStream.GetBuffer(), "application/pdf", "fileName.pdf");:

对我有用的是以下代码,因为服务器功能正在检索 File(memoryStream.GetBuffer(), "application/pdf", "fileName.pdf");:

$http.get( fullUrl, { responseType: 'arraybuffer' })
            .success(function (response) {
                var blob = new Blob([response], { type: 'application/pdf' });

                if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                    window.navigator.msSaveOrOpenBlob(blob); // for IE
                }
                else {
                    var fileURL = URL.createObjectURL(blob);
                    var newWin = window.open(fileURL);
                    newWin.focus();
                    newWin.reload();
                }
});

回答by POGSNET

var xhr;
var beforeSend = function(){
    $('#pleasewaitDL').modal('show');
}
$(function () {
    $('#print_brochure_link').click(function(){
        beforeSend();
        xhr = new XMLHttpRequest();
        xhr.open("GET",$('#preparedPrintModalForm').attr('action'), true); 
        xhr.responseType = "blob";
        xhr.onload = function (e) {
            if (this.status === 200) {
                var file = window.URL.createObjectURL(this.response);
                var a = document.createElement("a");
                a.href = file;
                a.download = this.response.name || "Property Brochure";
                console.log(file);
                document.body.appendChild(a);
                a.click();
                
                window.onfocus = function () {                     
                  document.body.removeChild(a)
                }
                $('#pleasewaitDL').modal('hide');
            };
        };
        xhr.send($('#preparedPrintModalForm').serialize());
    });
    $('#pleasewaitDLCancel').click(function() {
        xhr.abort();
    });
});

回答by George Maharis

If you have to work with file-stream (so no physically saved PDF) like we do and you want to download the PDF without page-reload, the following function works for us:

如果您必须像我们一样使用文件流(因此没有物理保存的 PDF),并且您想在不重新加载页面的情况下下载 PDF,以下功能对我们有用:

HTML

HTML

<div id="download-helper-hidden-container" style="display:none">
     <form id="download-helper-form" target="pdf-download-output" method="post">
            <input type="hidden" name="downloadHelperTransferData" id="downloadHelperTransferData" />
     </form>
     <iframe id="pdf-helper-output" name="pdf-download-output"></iframe>
</div>

Javascript

Javascript

var form = document.getElementById('download-helper-form');
$("#downloadHelperTransferData").val(transferData);
form.action = "ServerSideFunctionWhichWritesPdfBytesToResponse";
form.submit();

Due to the target="pdf-download-output", the response is written into the iframe and therefore no page reload is executed, but the pdf-response-stream is output in the browser as a download.

由于target="pdf-download-output",响应被写入 iframe,因此不会执行页面重新加载,但 pdf-response-stream 在浏览器中作为下载输出。