Das Material, dessen Übersetzung wir heute veröffentlichen, ist der Erstellung dynamischer PDF-Dateien unter Verwendung von HTML-Code als Vorlage gewidmet. Wir werden nämlich darüber sprechen, wie eine einfache Rechnung für die Zahlung bestimmter Waren oder Dienstleistungen erstellt wird. Die darin enthaltenen dynamischen Daten stammen aus dem Status der React-Anwendung. Die Basis der React-Anwendung wurde mit create-react-app erstellt, der Serverteil des Projekts basiert auf Node.js und das Express-Framework wurde bei seiner Entwicklung verwendet.

Der Autor dieses Materials stellt fest, dass er ein
Video vorbereitet hat, das die Entwicklung des Projekts demonstriert. Wenn Sie sich das Video ansehen und den Artikel lesen möchten, wird dies empfohlen. Blättern Sie zuerst durch den Artikel, schalten Sie dann das Video ein und erstellen Sie das System neu, das Sie dort in Betracht ziehen. Lesen Sie danach einfach den Artikel.
Projekterstellung
Erstellen Sie ein Projektverzeichnis und gehen Sie dorthin:
mkdir pdfGenerator && cd pdfGenerator
Erstellen Sie eine neue React-Anwendung:
create-react-app client
Wechseln Sie nach Abschluss der Anwendungserstellung in das gerade erstellte Verzeichnis und installieren Sie die Abhängigkeiten:
cd client && npm i -S axios file-saver
Erstellen Sie einen Express-Server. Erstellen Sie dazu den Serverordner im Projektverzeichnis und wechseln Sie dorthin. Erstellen Sie darin die Datei
index.js
und starten Sie die Projektinitialisierung:
mkdir server && cd server && touch index.js && npm init
package.json
zu bilden, drücken
Enter
einfach mehrmals die
Enter
. Führen Sie anschließend den folgenden Befehl aus, um dem Serverteil des Projekts die erforderlichen Abhängigkeiten hinzuzufügen:
npm i -S express body-parser cors html-pdf
client/package.json
nun in der Datei
client/package.json
über dem Abschnitt zur Beschreibung der Abhängigkeit Folgendes hinzu:
"proxy": "http://localhost:5000/"
Dies hilft bei der Arbeit mit dem lokalen Server über den Client-Code.
Jetzt müssen Sie zwei Fenster des Terminals öffnen.
Wechseln Sie im ersten Fenster in das
client
Verzeichnis und führen Sie den folgenden Befehl aus:
npm start
Wechseln Sie im zweiten Fenster zum Serverordner und führen Sie den folgenden Befehl aus:
nodemon index.js
Erstes Client-Setup
Der Client-Teil unseres Projekts wird sehr einfach aussehen.
Zunächst importieren wir in der
src/App.js
Client-Teils der Anwendung die Abhängigkeiten in den Code:
import axios from 'axios'; import { saveAs } from 'file-saver';
Initialisieren Sie anschließend oben in der Komponentenbeschreibung den Status:
state = { name: 'Adrian', receiptId: 0, price1: 0, price2: 0, }
Entfernen wir das Standard-JSX-Markup, das in der Anwendungsvorlage mithilfe der
create-react-app
und von der
render()
-Methode zurückgegeben wurde. Fügen Sie Folgendes ein:
<div className="App"> <input type="text" placeholder="Name" name="name" onChange {this.handleChange}/> <input type="number" placeholder="Receipt ID" name="receiptId" onChange={this.handleChange}/> <input type="number" placeholder="Price 1" name="price1" onChange={this.handleChange}/> <input type="number" placeholder="Price 2" name="price2" onChange={this.handleChange}/> <button onClick={this.createAndDownloadPdf}>Download PDF</button></div>
Erstellen wir die
handleChange
Methode, die für die Aktualisierung der Anwendungsstatusdaten in Bezug auf die Eingabefelder verantwortlich ist:
handleChange = ({ target: { value, name }}) => this.setState({ [name]: value })
Jetzt können wir mit der Erstellung einer PDF-Datei fortfahren. Der Teil davon, der mittels des Clients gelöst wird, besteht darin, eine POST-Anfrage an den Server zu erstellen. Die Anforderung sendet den Anwendungsstatus:
createAndDownloadPdf = () => { axios.post('/create-pdf', this.state) }
Bevor wir auf der Clientseite des Projekts weiterarbeiten können, müssen wir die Routen auf dem Server konfigurieren. Auf diese Weise kann der Server Daten vom Client empfangen, eine PDF-Datei generieren und diese Datei zurück an den Client übertragen.
Erstes Server-Setup
Der Serverteil des Projekts enthält nur zwei Routen. Eine wird benötigt, um PDFs zu erstellen. Die zweite dient zum Senden von Dateien an den Client.
Importieren Sie zunächst die Abhängigkeiten in die Datei
index.js
:
const express = require('express'); const bodyParser = require('body-parser'); const pdf = require('html-pdf'); const cors = require('cors');
Wir initialisieren die Express-Anwendung und konfigurieren den Port:
const app = express(); const port = process.env.PORT || 5000;
Richten Sie den Abfrageparser ein. Was wir brauchen, wird als
req.body
verfügbar
req.body
. Wir werden CORS auch so konfigurieren, dass unser Fehler "
Cross-Origin Request Blocked
unsere Arbeit nicht beeinträchtigt:
app.use(cors()); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json());
Starten Sie danach den Server:
app.listen(port, () => console.log(`Listening on port ${port}`));
Jetzt können wir den Code angehen, der für die Erstellung der PDFs verantwortlich ist.
Erstellen Sie eine HTML-Vorlage für PDFs
Für die Erstellung von PDF-Dateien benötigen wir eine HTML-Vorlage. Bei der Erstellung einer solchen Vorlage eröffnen sich uns endlose Möglichkeiten. Alles, was mit reinem HTML und CSS erstellt werden kann, kann als PDF-Datei dargestellt werden. Erstellen Sie das
documents
im
index.js
, gehen Sie dorthin und erstellen Sie die Datei
index.js
darin:
mkdir documents && cd documents && touch index.js
Aus dieser Datei exportieren wir eine Pfeilfunktion, die den gesamten erforderlichen HTML-Code zurückgibt. Wenn Sie diese Funktion aufrufen, können Sie die Parameter verwenden, die wir auch hier beschreiben werden.
module.exports = ({ name, price1, price2, receiptId }) => { ... }
Hier gebe ich Ihnen
ein Beispiel für eine HTML-Vorlage, und Sie kopieren sie einfach in Ihr Projekt. Aber Sie können natürlich Ihre eigene Vorlage erstellen.
Lassen Sie uns
index.js
Code
index.js
aus dem Ordner
server/documents
in das folgende Formular bringen:
module.exports = ({ name, price1, price2, receiptId }) => { const today = new Date(); return ` <!doctype html> <html> <head> <meta charset="utf-8"> <title>PDF Result Template</title> <style> .invoice-box { max-width: 800px; margin: auto; padding: 30px; border: 1px solid #eee; box-shadow: 0 0 10px rgba(0, 0, 0, .15); font-size: 16px; line-height: 24px; font-family: 'Helvetica Neue', 'Helvetica', color: #555; } .margin-top { margin-top: 50px; } .justify-center { text-align: center; } .invoice-box table { width: 100%; line-height: inherit; text-align: left; } .invoice-box table td { padding: 5px; vertical-align: top; } .invoice-box table tr td:nth-child(2) { text-align: right; } .invoice-box table tr.top table td { padding-bottom: 20px; } .invoice-box table tr.top table td.title { font-size: 45px; line-height: 45px; color: #333; } .invoice-box table tr.information table td { padding-bottom: 40px; } .invoice-box table tr.heading td { background: #eee; border-bottom: 1px solid #ddd; font-weight: bold; } .invoice-box table tr.details td { padding-bottom: 20px; } .invoice-box table tr.item td { border-bottom: 1px solid #eee; } .invoice-box table tr.item.last td { border-bottom: none; } .invoice-box table tr.total td:nth-child(2) { border-top: 2px solid #eee; font-weight: bold; } @media only screen and (max-width: 600px) { .invoice-box table tr.top table td { width: 100%; display: block; text-align: center; } .invoice-box table tr.information table td { width: 100%; display: block; text-align: center; } } </style> </head> <body> <div class="invoice-box"> <table cellpadding="0" cellspacing="0"> <tr class="top"> <td colspan="2"> <table> <tr> <td class="title"><img src="https://i2.wp.com/cleverlogos.co/wp-content/uploads/2018/05/reciepthound_1.jpg?fit=800%2C600&ssl=1" style="width:100%; max-width:156px;"></td> <td> Datum: ${`${today.getDate()}. ${today.getMonth() + 1}. ${today.getFullYear()}.`} </td> </tr> </table> </td> </tr> <tr class="information"> <td colspan="2"> <table> <tr> <td> Customer name: ${name} </td> <td> Receipt number: ${receiptId} </td> </tr> </table> </td> </tr> <tr class="heading"> <td>Bought items:</td> <td>Price</td> </tr> <tr class="item"> <td>First item:</td> <td>${price1}$</td> </tr> <tr class="item"> <td>Second item:</td> <td>${price2}$</td> </tr> </table> <br /> <h1 class="justify-center">Total price: ${parseInt(price1) + parseInt(price2)}$</h1> </div> </body> </html> `; };
server/index.js
diese Datei in die Datei
server/index.js
:
const pdfTemplate = require('./documents');
PDFs erstellen
Denken Sie daran, dass wir auf dem Server zwei Routen erstellen werden. Die POST-Route ist für den Empfang von Daten vom Client und die Erstellung einer PDF-Datei verantwortlich. Die GET-Route wird verwendet, um die fertige Datei an den Client zu senden.
▍ PDF-Route erstellen
In der POST-Route
create-pdf
wir den Befehl
pdf.create()
, der auf das aus dem
html-pdf
Modul importierte Objekt verweist.
Als erster Parameter der Methode
pdf.create()
werden eine HTML-Vorlage sowie vom Client empfangene Daten verwendet.
Um
pdf.create()
, rufen wir die Methode
toFile()
und übergeben ihr den Namen, den wir dem PDF-Dokument zuweisen möchten, sowie die Pfeilrückruffunktion. Diese Funktion führt im Fehlerfall den
res.send(Promise.reject())
. Für den Fall, dass alles gut gegangen ist, führt sie den Befehl
res.send(Promise.resolve())
.
app.post('/create-pdf', (req, res) => { pdf.create(pdfTemplate(req.body), {}).toFile('result.pdf', (err) => { if(err) { res.send(Promise.reject()); } res.send(Promise.resolve()); }); });
▍Fetch-pdf-Route
Gleichzeitig erstellen wir eine Route, die verwendet wird, nachdem auf Wunsch des Kunden eine PDF-Datei erfolgreich erstellt wurde. Hier nehmen wir einfach das fertige Dokument und senden es mit
res.sendFile()
an den Client:
app.get('/fetch-pdf', (req, res) => { res.sendFile(`${__dirname}/result.pdf`) })
Client-Funktion createAndDownloadPdf
Jetzt können wir zum Client-Code zurückkehren und weiter an der Funktion
createAndDownloadPdf
. Hier stellen wir mit dem
axios
Modul eine POST-Anfrage an den Server. Diese Funktion sieht nun folgendermaßen aus:
createAndDownloadPdf = () => { axios.post('/create-pdf', this.state) }
Wenn nach dem Ausführen einer POST-Anforderung an den Server ein PDF-Dokument erstellt wurde, müssen wir eine GET-Anforderung ausführen, auf die der Server das fertige Dokument an den Client sendet.
Um dieses Verhaltensschema zu implementieren, rufen wir nach dem Aufruf von
axios.post()
.
then()
. Auf diese Weise können wir als Antwort auf die POST-Anfrage eines Clients ein Versprechen vom Server zurückgeben, das entweder erfolgreich aufgelöst oder abgelehnt werden kann.
Wir ergänzen die Funktion mit folgendem Code:
.then(() => axios.get('/fetch-pdf', { responseType: 'blob' })) .then(( res) => {})
Hier können Sie darauf achten, dass
blob
als
responseType
. Bevor wir weiter gehen, lassen Sie uns darüber sprechen, was es ist.
Blob-Objekte
Blob ist ein unveränderliches Objekt, das einige Rohdaten darstellt. Solche Objekte werden häufig verwendet, um mit Daten zu arbeiten, die möglicherweise nicht im nativen JavaScript-Format vorliegen. Solche Objekte sind Folgen von Bytes, in denen beispielsweise Dateidaten gespeichert sind. Es scheint, dass das
Blob
Objekt einen Link zu einer Datei speichert, dies ist jedoch nicht der
Blob
. Diese Objekte speichern Daten, mit denen Sie arbeiten können. Zum Beispiel können sie in Dateien gespeichert werden.
Projektabschluss
.then()
wir nun wissen, was
Blob
Objekte sind, können wir einen anderen
.then()
,
res.data
neues
Blob
Objekt basierend auf res.data zu erstellen. Beim Erstellen dieses Objekts übergeben wir einen Parameter an seinen Konstruktor, der angibt, dass die vom Objekt gespeicherten Daten vom Typ
application/pdf
. Danach können wir die
saveAs()
-Methode verwenden, die aus dem
saveAs()
importiert wurde, und die Daten in einer Datei speichern. Infolgedessen
createAndDowndloadPdf
der Code der Methode
createAndDowndloadPdf
wie folgt aus:
createAndDownloadPdf = () => { axios.post('/create-pdf', this.state) .then(() => axios.get('fetch-pdf', { responseType: 'blob' })) .then((res) => { const pdfBlob = new Blob([res.data], { type: 'application/pdf' }); saveAs(pdfBlob, 'newPdf.pdf'); }) }
So sieht die Browser-Oberfläche aus.
Anwendung im BrowserNachdem Sie die Felder ausgefüllt und auf die Schaltfläche
Download PDF
geklickt haben, werden die Daten auf den Server übertragen und ein PDF-Dokument von diesem heruntergeladen.
PDF herunterladenUnd hier ist das PDF-Dokument selbst.
Software-generiertes PDFZusammenfassung
Wir haben uns einen Mechanismus angesehen, mit dem Sie programmgesteuert PDF-Dateien erstellen können.
Hier ist ein GitHub-Repository mit Projektcode. Wir hoffen, dass die Ideen, die Sie in diesem Material getroffen haben, in Ihrer Entwicklung Anwendung finden.
Liebe Leser! Wie würden Sie das Problem der programmgesteuerten Erstellung von PDF-Dateien mit Node.js lösen?