ajax - Grails和pdf.js并通过ajax调用呈现pdf

标签 ajax grails pdf.js

我在我们的应用程序中添加了需要嵌入式pdf查看器的功能。用户将需要能够查看pdf,同时访问位于屏幕另一区域的某些其他表格。

出于安全原因,提供文件url是 Not Acceptable 。相反,查看请求必须转到我们的应用程序,该应用程序将提供其他安全检查。如果检查成功,则将pdf作为流返回。绝对不能通过浏览器直接访问文件目录。

根据我的阅读,似乎pdf.js应该可以很好地工作,因为PDFJS.getDocument方法将接受Uint8数组以及uri。我一直在研究其他人如何使用base64ToUint8Array函数解决此问题。

在客户端,我们使用jQuery和bootstrap,并且pdf.js和pdf.viewer.js作为页面加载的一部分被加载。

这是我当前问题的全部背景,这是服务器使用grails的,我不知道如何通过grails Controller 类发送二进制pdf数据。

这是我目前在 Controller 中拥有的:

def view = {
        SolutionFile solutionFile = SolutionFile.get(params.sfileId)
        InputStream pdfStream = fileStoreService.writeBinary( solutionFile.fileName, solutionFile.file)
pdfStream
    }

返回到浏览器的内容是根据我们的核心布局gsp文件生成的html,没有任何包含的模板。我在任何地方都看不到pdf文件数据。

调用PDFJS.getDocument时,出现“无效字符错误-字符串包含无效字符”的消息,因此我怀疑返回的响应也不在base64中。

这是html的模型:

这是调用PDFJS的ajax调用:
jQuery(document).ready(function() {

    PDFJS.disableStream = true;
    PDFJS.disableWorker = true; 

    function base64ToUint8Array(base64) {//base64 is an byte Array sent from server-side
        var raw = atob(base64); //This is a native function that decodes a base64-encoded string.
        var uint8Array = new Uint8Array(new ArrayBuffer(raw.length));
        for (var i = 0; i < raw.length; i++) {
          uint8Array[i] = raw.charCodeAt(i);
        }
         return uint8Array;
         }


    jQuery('.remote-tab').click(function(e) {
        e.preventDefault();
        var url = jQuery(this).attr("data-url");
        var dataparams = jQuery(this).attr("data-params");
        var params;
        if (dataparams != null) {
            params = JSON.parse(dataparams);
        }
       var canvasId = jQuery(this).attr("data-loadinto");

      jQuery(this.hash).find('#'+canvasId).load(url, params, function(responseTxt, statusTxt, xhr){
        console.log("about to call PDFJS");
              PDFJS.getDocument(base64ToUint8Array(responseTxt)).then(function(pdfFile) {
            PDFJS.disableWorker = true; 
            var pageNumber = 1;
            pdfFile.getPage(pageNumber).then(function(page) {
                  var scale = 1;
                  var viewport = page.getViewport(scale);
                  var canvas = document.getElementById('canvas');
                  var context = canvas.getContext('2d');

                  var renderContext = {
                      canvasContext: context,
                      viewport: viewport
                  };
                  canvas.height = viewport.height;
                  canvas.width = viewport.width;
                  console.log("rendering page");
                  page.render(renderContext);
            });
        });

        }); 
    });
});

任何帮助解释我需要做什么,以使流式PDF正确返回到ajax函数的帮助将不胜感激。

最佳答案

我的基本问题是,当服务器端处于访问状态时,如何将base64编码的二进制文件发送到浏览器?
用grails编写的方法,特别是用grails Controller 编写的方法如何绕过预期的gsp模板生成?

我相信我已经在这篇文章中找到了解决方案:
Writing binary content directly to the client bypassing the Grails view layer

关键是响应缓冲区需要作为 Controller 方法中的最后一个操作进行刷新,并且必须
用该 Controller 方法完成。

这是我的 Controller 方法中的代码现在如下所示:

def view = {
    SolutionFile solutionFile = SolutionFile.get(params.sfileId)
    response.setContentType("application/octet-stream");
    fileStoreService.writeBinary( response, solutionFile.fileName, solutionFile.file)   
    response.flushBuffer()
}

要注意的另一件事是,必须在写入响应缓冲区之前完成setContentType。我不确定我已经
设置了正确的内容类型集,但这是故事的另一部分。

返回的结果必须是base64编码的二进制文件的要求是因为我想在上使用pdf.js
客户端。具体来说,我想使用PDFJS.getDocument而不是修改提供的viewer.html
文件。 PDFJS.getDocument将仅接受pdf URI(在这种情况下 Not Acceptable )或Uint8数组(可以生成)
来自base64编码的二进制文件。 )

出于安全性要求,无法在应用程序外部直接访问存储的文件,因此
我们提供的服务将根据文件ID提取正确的文件。我创建了一个writeBinary方法
返回编码的二进制文件。 (至少我希望如此,仍在努力。)
void writeBinary( response, fileName, fileId) {  
  File f=new File(getUrl(fileId))
  FileInputStream fis = new FileInputStream(f)
  try {
     byte[] buf = FileUtils.readFileToByteArray(f)      
     response.outputStream << buf.encodeBase64()
    }
  catch (Exception e) {
    log.error(e.printStackTrace());
    }
  finally {
    if (fis != null) fis.close()
  }
}   

所以,我想我已经回答了我最初发布的问题。但是,客户端pdf.js部分仍然无法正常工作。
我将对此进行研究,一旦我清楚了这个问题,可能会问一个新问题。我也不会重复这个问题,因为我也是
很难通读。

关于ajax - Grails和pdf.js并通过ajax调用呈现pdf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41472646/

相关文章:

php - 显示两个 PHP 变量开关的更好方法 jQuery Ajax

google-app-engine - 我可以使用 intellj app-engine 插件将我的 grails 应用程序部署到 app-engine

java - Orbeon 中的 PDF 生成

javascript - 如何在pdfjs中添加onclick()

javascript - 延迟加载:How to display multiple pdf documents as one with pdf.js?

javascript - 有没有办法在 pdf.js 中合并 PDF?

javascript - AJAX 响应 XML

php - 如何在 laravel 中使用 ajax post 请求将图像插入数据库?

javascript - 运行嵌入在 AJAX 加载元素中的 JS 时等待加载?

list - 如何将HashMap传递到gsp页面,然后再返回到 Controller ?