Как реализовать реакцию pdf с функцией печати - PullRequest
0 голосов
/ 30 декабря 2018

Я хотел бы использовать response-pdf для отображения PDF и разработки функции печати для прямой печати (например, с помощью window.print ());

Сервер REST разработан с использованием Jersey.

PDF будет сгенерирован с сервера и возвращен клиенту React с использованием Jersey с типом возврата - application / pdf.React клиент будет отображать PDF с помощью response-pdf.

Я не хочу объявлять URL-путь в «файле», потому что он снова будет извлекать PDF-файл с сервера, если состояние React изменилось и вызвало повторную визуализацию.Кроме того, мне нужно разработать функцию печати для печати отображаемого PDF-файла (поскольку содержимое PDF-файла может измениться, если снова извлечь PDF-файл с сервера)

Ниже показан мой код:

Сервер:

@Override
@GET
@Path("/pdf")
@Produces(MediaType.APPLICATION_PDF_VALUE)
public Response testPdf() throws Exception {

    File file = new File("C:\\Desktop\\test.pdf");
    FileInputStream fileInputStream = new FileInputStream(file);

    ResponseBuilder response = Response.ok((Object) fileInputStream);
    response.type("application/pdf");
    response.header("Content-Disposition", "filename=test.pdf");

    return response.build();
}

Клиент

import React, { Component } from 'react';
import { Document, Page } from 'react-pdf';
import axios from 'axios';

class MyApp extends Component {
    state = {
        numPages: null,
        pageNumber: 1,
        pdfContent: null
    }

    componentDidMount(){
        var that = this;

        axio.get("url\Pdf).then((response) => {
             that.setState({pdfContent:response.data});
        }).catch((error) => {
             console.warn(error);
        });
    }

    onDocumentLoadSuccess = ({ numPages }) => {
        this.setState({ numPages });
    }

   printHandler(){
       window.print();
   }

   render() {
      const { pageNumber, numPages } = this.state;

      return (
          <div>
             <Document
                file={this.state.pdfContent}
                onLoadSuccess={this.onDocumentLoadSuccess}
             >
                 <Page pageNumber={pageNumber} />
             </Document>
             <p>Page {pageNumber} of {numPages}</p>

             <button onClick={() => this.setState(prevState => ({ 
                     pageNumber: prevState.pageNumber + 1 }))}>Next page</button>
             <button onClick={() => this.setState(prevState => ({ 
                     pageNumber: prevState.pageNumber - 1 }))}>Prev Page</button>

              <button onClick={this.printHandler}/>
          </div>
      );

}}

Я хочу получить PDF-файл только один раз и отобразить PDF-файл с помощью response-pdf.Кроме того, я хочу напечатать отображаемый PDF.

Я попытался преобразовать response.data в base64, следуя этой строке, потому что не удалось: (это приведет к потере содержимого PDF) Кодирование PDF в base64 в ReactJS

Код вроде:

  componentDidMount(){
        var that = this;

        axio.get("url\Pdf).then((response) => {
             let reader = new FileReader();
            var file = new Blob([response.data], { type: 'application/pdf' });

            reader.onloadend = () => {
                that.setState({
                    base64Pdf:reader.result
                });
            }
            reader.readAsDataURL(file);
        }).catch((error) => {
             console.warn(error);
        });
    }

Кто-нибудь может дать мне какое-нибудь предложение?Или какой-нибудь лучший способ достичь моей цели?

Спасибо

Ответы [ 3 ]

0 голосов
/ 04 февраля 2019

Обновление при получении сообщения об ошибке от серверной части :

При сбое запроса мы получаем объект JSON от серверной части, который содержит сообщение об ошибке.Проблема заключается в том, что когда мы вынуждаем получить ответ в формате Blob: responseType: 'blob' - независимо от того, не выполнен запрос или нет, мы получаем объект Blob.Итак, я думал об изменении responseType в функции, предоставляемой из axios: transformResponse, но, к сожалению, у нас нет доступа к объекту responseType, только к заголовкам.Здесь: https://github.com/axios/axios/pull/1155 существует открытая проблема с преобразованием соответственно responseType, она все еще не решена.

Итак, мой способ решения этой проблемы - использовать fetch вместо axios.Вот пример:

fetch('here.is.your/endpoint', {
            method: 'POST', // specifying the method request
            body: JSON.stringify(request), // specifying the body
            headers: {
                "Content-Type": "application/json"
            }
        }
    ).then((response) => {
        if (response.ok) { // checks if the response is with status 200 (successful)
            return response.blob().then(blob => {
                const name = 'Report.pdf';
                saveAs(blob, name);
            });
        } else {
            return response.json().then((jsonError) => {
                this.setState({
                    modalMessage: jsonError.message // access the error message returned from the back-end
                });
            });
        }
    }).catch(function (error) {
        this.setState({
            modalMessage: "Error in data type received." // general handler
        });
    });

Надеюсь, это поможет!

0 голосов
/ 21 марта 2019

Я рад, что помог!

У меня есть еще ОБНОВЛЕНИЕ ДЛЯ ПОЛУЧЕНИЯ СООБЩЕНИЯ ОБ ОШИБКЕ

ЭТО ТОЛЬКО ТОЛЬКО ЕСЛИ ВЫ ПОЛУЧАЕТЕ СООБЩЕНИЕ О ТЕКСТЕНЕ JSON

fetch('here.is.your/endpoint', {
        method: 'POST', // specifying the method request
        body: JSON.stringify(request), // specifying the body
        headers: {
            "Content-Type": "application/json"
        }
    }
).then((response) => {
    if (response.ok) { // checks if the response is with status 200 (successful)
        return response.blob().then(blob => {
            const name = 'Report.pdf';
            saveAs(blob, name);
        });
    } else {
         return response.text().then(function (error) {
                    throw new Error(error); // we should throw an Error with the received error
                }
            );
    }
}).catch(function (error) {
    this.setState({
        modalMessage: error.message // that way we access the error message
    });
});

Мы используем response.text (). Then (), так как нам удается преобразовать его из Promise в текст.И важно использовать .then (), потому что Обещание в этот момент разрешено, и мы получаем значение Обещания.Затем мы просто выдаем ошибку, потому что у нас нет доступа к объекту состояния.

Именно так вы получаете текст из ответа.

0 голосов
/ 04 февраля 2019

Недавно у меня был похожий вариант использования с pdf-частью, мой запрос - Post, но вы можете сделать это Get без проблем.Итак, что происходит:

1) - я использую axios для отправки запроса на сервер:

2) - запрос это объект, который я отправляю, но у вас его не будет, так как вы, вероятно, отправите только идентификатор, например: axios.get ('here.is.your / endpoint / id');

3) - Я использую: file-saver для сохранения файла, который я получаю.

Остальная часть кода должна быть понятна, и я также добавил несколько комментариев.

import {saveAs} from "file-saver";
...

axios.post('here.is.your/endpoint', qs.parse(request), {
       headers: {
          'Content-Type': 'application/json'
       },   
       responseType: 'blob' // here I am forcing to receive data in a Blob Format
    })
    .then(response => {
        if (response.data) {
            //Create a Blob from the PDF Stream
            const file = new Blob(
                [response.data],
                {type: 'application/pdf'});
            const name = 'Report.pdf';
            saveAs(file, name);
        } else {
            throw new Error("Error in data type received.");
        }
    })
    .catch(error => {
        this.setState({
            modalMessage: "Here Add Custom Message"
        });
   });

IЯ не могу получить сообщение об ошибке от серверной части, я отправлю текстовое сообщение, если получу какой-то прогресс - пока я показываю пользовательское сообщение.

Надеюсь, это поможет!

Желаю тебе удачи!

...