2017-01-04 21 views
0

Я добавляю функцию в наше приложение, для которой требуется встроенный просмотрщик PDF. Пользователь должен будет иметь возможность просматривать pdf, одновременно просматривая некоторые другие формы, расположенные в другой области экрана.Grails и pdf.js и рендеринг pdf через вызов ajax

Предоставление файла url неприемлемо по соображениям безопасности. Вместо этого запрос на просмотр должен перейти в наше приложение, которое обеспечит дополнительные проверки безопасности. Если проверки успешны, то pdf возвращается как поток. Невозможно получить доступ к файловому каталогу напрямую через браузер.

Из того, что я прочитал, похоже, что pdf.js должен хорошо работать с этим, поскольку метод PDFJS.getDocument будет принимать массив Uint8, а также uri. Я искал информацию о том, как другие решили это, используя функцию base64ToUint8Array.

На стороне клиента мы используем jQuery и bootstrap, а файлы pdf.js и pdf.viewer.js загружаются как часть загрузки страницы.

Это все предпосылки для моей текущей проблемы, которая заключается в том, что сервер использует grails, и я не знаю, как отправить двоичные данные PDF через класс контроллера grails.

Вот что я в настоящее время в контроллере:

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

Что возвращается в браузер генерируется HTML на основе нашего основного макета GSP файл, без какого-либо включенного шаблона. Я не вижу данные в формате pdf в любом месте.

Я получаю сообщение «Invalid Character error-string содержит недопустимый символ», когда вызывается PDFJS.getDocument, поэтому я подозреваю, что возвращенный ответ также не находится в base64.

Вот макет в HTML:

Вот Аякса вызов, который вызывает PDFJS:

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 возвращается Аякса функция была бы очень оценена.

+0

К сожалению, HTML:

+0

«„Неверный символ error- строка содержит недопустимый символ“» является 'atob' ошибка - я не думаю, что ваш вопрос pdf.js связаны между собой. – async5

+0

Я думаю, что предоставил слишком много фоновой информации. Фактическим запросом была помощь в отправке правильно отформатированных данных из контроллера grails через ajax, который будет использоваться в PDFJS.getDocument() –

ответ

0

Мой основной вопрос: как я могу отправить двоичный файл с кодировкой base64 в браузер, когда серверная сторона - , написанная в grails, в частности, как метод, написанный в контроллере grails, обходит ожидаемое создание шаблона gsp?

Я считаю, что я нашел решение, что в этом посте: Writing binary content directly to the client bypassing the Grails view layer

Ключ в том, что буфер ответа должен быть промыт в качестве последнего действия в методе контроллера и должен быть сделано в том, что контроллер.

Вот что код в моем методе контроллера теперь выглядит следующим образом:

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 (что неприемлемо в этом случае) или массив Uint8 (который может быть сгенерирован из двоичного файла с кодировкой base64.)

Для требований безопасности хранящиеся файлы не могут напрямую обращаться за пределами приложения, поэтому у у нас есть служба, которая выберет правильный файл с идентификатором файла. Я создал метод 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 на стороне клиента все еще не работает.
Я буду работать над этим и могу задать новый вопрос, как только я получу ясность по этой проблеме. Я не буду повторно использовать этот вопрос, так как я сделал это слишком легко читать.