【问题标题】:How to implement react-pdf with print function如何实现带有打印功能的react-pdf
【发布时间】:2018-12-30 12:15:54
【问题描述】:

我想使用react-pdf来显示PDF并开发一个直接打印的打印功能(比如使用window.print());

REST 服务器是使用 Jersey 开发的。

PDF 将从服务器生成并使用 Jersey 返回到 React 客户端,返回类型为 application/pdf。 React 客户端将使用 react-pdf 显示 PDF。

我不想在“文件”中声明 URL 路径,因为如果 React 状态更改并触发重新渲染,这将再次从服务器检索 PDF。另外,我需要开发一个打印功能来打印显示的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;

        axios.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 并使用 react-pdf 显示 PDF。另外,我想打印显示的 PDF。

我尝试将 response.data 转换为 base64,因为没有成功:(这将丢失 pdf 内容) Encode PDF to base64 in ReactJS

代码如下:

    componentDidMount(){
        var that = this;

        axios.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);
        });
    }

谁能给我一些建议? 或者有什么更好的方法来实现我的目标?

谢谢

【问题讨论】:

  • 到目前为止你有什么尝试?
  • @Mikkel 我已经尝试使用 FileReader 来对 base64 做出响应。但是,仍然没有成功(也许我对此并不熟悉......)我已经更新了一些代码到我的帖子。

标签: reactjs pdf jersey state react-pdf


【解决方案1】:

从后端收到错误消息时更新

当请求失败时,我们会从后端收到一个 JSON 对象,其中包含错误消息。问题是当我们强制接收 Blob 格式的响应时: responseType: 'blob' - 无论请求是否失败,我们都会收到一个 Blob 对象。因此,我正在考虑更改 axios 提供的函数中的 responseType: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
        });
    });

我希望这会有所帮助!

【讨论】:

    【解决方案2】:

    最近我得到了一个与pdf部分类似的用例,我的请求是Post,但你可以毫无问题地获取它。那么,发生了什么:

    1) - 我正在使用 axios 向后端发出请求:

    2) - request 是我要发送的对象,但你不会有这样的对象,因为你可能只会发送 id,例如:axios.get('here.is.your /endpoint/id');

    3) - 我正在使用:file-saver 来保存我收到的文件。

    其余代码应该是不言自明的,我还添加了一些 cmets。

    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"
            });
       });
    

    我仍然无法从后端收到错误消息,如果我在这方面取得一些进展,我会回信 - 现在,我显示一条自定义消息。

    希望对你有帮助!

    祝你好运!

    【讨论】:

      【解决方案3】:

      很高兴我能帮上忙!

      我还有一个收到错误消息的更新

      仅当您收到文本消息而不是 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() 很重要,因为此时 Promise 已解决,我们会收到 Promise 值。然后我们简单地抛出一个错误,因为我们无权访问状态对象。

      这就是您从响应中获取文本的方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多