如何把javascript生成pdf(Javascript基于模板生成PDF文档)
如何把javascript生成pdf(Javascript基于模板生成PDF文档)用于npm init创建 package.json请按照以下步骤为我们设置编码游乐场。在本文中,我们将讨论如何将 eDocGen 集成到我们的 js 应用程序中,以从各种数据格式(如 JSON/XML/Database 模式)生成文档。请免费试用以开始编码。让我们潜入并编写代码。出于演示目的,我创建了一个在 nodejs 上运行的示例 js 应用程序。
在您的 js 应用程序中使用 eDocGen 从 JSON/XML/Database 创建 PDF 文档的指南。文档生成是开发人员生活中非常普遍的需求。无论是电子商务网站、管理应用程序还是其他任何东西。它可以是发票生成、保险文件准备、医生处方、人力资源报价生成、工资单生成,你可以想到大量的用例。总是需要生成文档。
从开发人员的角度来看,有几种常见的方法可以完成这项工作。
- 创建 HTML 元素并打印它们以生成文档
 - 使用一些库来生成文档
 - 让服务器处理基于静态模板的文档生成
 
这些方法对我没有帮助。客户希望自己定制他们的文件。我一直在寻找一种方法,发现eDocGen是一种单点解决方案。
与其他服务不同,eDocGen 提供了可以集成到我们应用程序中的 RestAPI。
在本文中,我们将讨论如何将 eDocGen 集成到我们的 js 应用程序中,以从各种数据格式(如 JSON/XML/Database 模式)生成文档。请免费试用以开始编码。
让我们潜入并编写代码。
项目设置出于演示目的,我创建了一个在 nodejs 上运行的示例 js 应用程序。
请按照以下步骤为我们设置编码游乐场。
步骤1:用于npm init创建 package.json
第2步:添加axios form-data request xhr2开发此应用程序所需的依赖项npm install axios form-data request xhr2
第 3 步:我们需要一个索引文件作为我们应用程序的起点。在根目录中创建一个 index.js 文件并修改 package.json 如下所示。
JSON
scripts": {
    "start": "node index.js"
 }
    
现在我们有一个基本的应用程序可以开始。这些步骤结束后,package.json 应该如下所示。
JSON
{
  "name": "nodejs-multiple-Upload-Files" 
  "version": "1.0.0" 
  "main": "index.js" 
  "scripts": {
    "start": "node index.js"
  } 
  "dependencies": {
    "axios": "^0.27.2" 
    "form-data": "^4.0.0" 
    "Request": "^2.88.2" 
    "xhr2": "^0.2.1"
  }
}
登录
    
虽然这篇文章是关于文档生成的,但我们需要登录才能获取我们的访问令牌。这是一个典型的JWT令牌,将用于授权文档生成 API。
JavaScript
var XMLHttpRequest = require("xhr2");
var xhr = new XMLHttpRequest();
module.exports.getToken = function (callback) {
  var data = JSON.stringify({
    username: "<your username>" 
    password: "<password>" 
  });
  xhr.addEventListener("readystatechange"  function () {
    if (this.readyState === 4) {
      token = JSON.parse(this.responseText).token;
      console.log("User Token"  token);
      callback(token);
    }
  });
  xhr.open("POST"  "https://app.edocgen.com/login");
  xhr.setRequestheader("content-type"  "application/json");
  xhr.setRequestHeader("cache-control"  "no-cache");
  xhr.send(data);
};
    
我们可以将令牌在应用程序中缓存一个小于过期时间的时间段,并使用它来生成文档或上传模板。到期时间过后,我们可以刷新令牌。缓存可以是 Redis 或内存缓存。这取决于您的应用程序设计。
模板设计如上所述,eDocGen 允许用户自定义和上传模板。但是如何动态映射数据呢?有一些将数据映射到文档的规则。我们将看到如何使用规则创建模板。
看看这个文件。

eDocGen{}对动态字段使用由 括起来的标签。我们可以动态添加文字、logo、表格、条件语句、数学计算等。
例如,在上图中,
字符串字段: {Invoice_number}并{Invoice_Date}配置为替换为模板中的文本。模板中 {} 内的任何内容都将与输入数据匹配并替换。
动态表: 当表中存在需要循环和替换的数据数组时,动态表将是一个不错的选择。表中的行以 开头{#tablename}和结尾{/tablename}。在上面的示例中,发票表中的一行在第一列以 {#IT} 开头,在最后一列以 {/IT} 结尾。行中的列可以有字符串字段。在我们的示例中,{Item_description}并且{Amount}
图片: eDocGen 提供动态添加图片到模板的功能。请按照以下步骤操作。
- 将图像上传到应以 image_id 响应的 eDogGen。
 - {%image_id}是用于填充图像的标签。图像image_id将从 eDocGen 存储中获取并替换为{%image_id}. 预计image_id将出现在输入数据中。
 
基于条件的动态字段(If-Else):可以使用条件标签有条件地显示内容。例如,当语言为英语时,文档中会显示{#language == "english"} 英语内容。同样,单个文档模板可以支持多种语言。
数学计算: eDocGen 支持基于模板中定义的公式的数学计算。可以使用以下公式计算发票中项目金额的总和。
JSON
{
    IT // array of items
    | Summation:'Amount' // value that needs to be used for calculation 
    | format_number: " ” // format of the value
}
    
请前往JSON-to-pdf了解更多详情。
模板上传准备好模板后,就可以将其上传以供使用。有两种方法。
- eDocGen 的交互式 UI - 与 Dropbox、驱动器、Evernote 集成
 - eDocGen 的 RestAPI - 可以集成到客户端代码中以上传模板。
 
对于演示,我使用 UI 来上传模板。成功上传后,我们会得到一个 ID 作为响应。这是将用于生成文档的 ID。

如果您希望使用 API,请在此处留下 Upload API 结构供您参考。
JSON
"/api/v1/document": {
  "post": {
    "tags": [
      "Document"
    ] 
    "description": "Upload template to eDocGen" 
    "produces": [
      "application/json"
    ] 
    "consumes": [
      "multipart/form-data"
    ] 
    "parameters": [
      {
        "name": "documentFile" 
        "description": "file to upload" 
        "required": true 
        "type": "file" 
        "in": "formData"
      } 
      {
        "name": "x-access-token" 
        "in": "header" 
        "description": "JWT auth token from login" 
        "required": true 
        "type": "string"
      }
    ] 
    "responses": {
      "200": {
        "description": "Successfully uploaded document file"
      } 
      "other": {
        "description": "Operation failed"
      }
    }
  }
}
JSON 到文档生成
现在我们准备好了模板。让我们生成文档。
文档生成有两个阶段。
- 请求生成文档
 - 下载文件
 
我们要求生成包含所需详细信息的文档,并得到确认。该过程异步发生在屏幕后面。
文档生成所需的参数应用程序接口:POST-/api/v1/document/generate/bulk
请求正文表格数据
| 
     文档 ID  | 
     模板的id  | 
| 
     格式  | 
     pdf/docx(模板应支持格式)  | 
| 
     输出文件名  | 
     输出文件的文件名。  | 
| 
     输入文件  | 
     该文件包含标记值。支持 json、xlsx 和 xml。  | 
| 
     内容类型  | 
     多部分/表单数据  | 
| 
     x-访问令牌  | 
     来自登录的 JWT 身份验证令牌  | 
inputFile 中的数据应该是模板定义的结构。例如,对于上面的模板映射将如下所示。
- Invoice_Number在 JSON 中应该与{Invoice_Number}模板中的匹配。
 - 对于表数据,它应该是一个对象数组,带有Item_Description和Amount.
 - 金额应该是一个用于求和计算的数字。
 

可以使用从上述步骤中获得的输出 ID 和输出文件的名称下载生成的文档。
我们将在这里使用两个 API。
- 了解文件存在的 API:/api/v1/output/name/${fileName}
 - 下载文件的API:/api/v1/output/download/${outputId}
 
由于文档生成是异步发生的,要知道文档是否生成,我们将使用/api/v1/output/nameapi。
来自 API 的成功响应/api/v1/output/name将下载文件。
我将这两个步骤组合在一个 js 文件中,如下所示。
爪哇
let login = require("../edocgen_login");
const fs = require("fs");
const uuid = require("uuid");
const FormData = require("form-data");
let axios = require("axios");
let fileName = uuid.v4();
const headers = {
  "Content-Type": "multipart/form-data" 
  "x-access-token": "null" 
};
const hostName = "https://app.edocgen.com/api/v1/document/generate/bulk";
const outputFormat = "<format>";// pdf / docx
const documentId = "<template_id>";    // id of the template we want to use
module.exports.generateFiles =  function () {
  let authToken = login.getToken(function handleUsersList(token) {
    headers["x-access-token"] = token;
    var formBody = new FormData();
    formBody.append("documentId"  documentId);
    formBody.append("format"  outputFormat);
    formBody.append("outputFileName"  fileName);
    // json data for the template
    formBody.append("inputFile"  fs.createReadStream("./JSON_Data_Single.json"));   // local path forjson file
    let config = {
      method: "post" 
      url: hostName 
      headers: headers 
      data: formBody 
    };
    console.log(`https://app.edocgen.com/api/v1/output/name/${fileName}.${outputFormat}`);
    let config_output = {
      method: "get" 
      url:`https://app.edocgen.com/api/v1/output/name/${fileName}.${outputFormat}` 
      headers: headers 
    };
    const MAX_RETRY = 50;
    let currentRetry = 0;
    // max retry for 50 times
    function errorHandler() {
      if (currentRetry < MAX_RETRY) {
        currentRetry  ;
        console.log("Document is not prepared yet! Retrying...");
        sendWithRetry(processResponse);
      } else {
        console.log("No luck. Document is not generated. Retried multiple times.");
      }
    }
    
    // sendWithRetry checks for file existence
    // on success  it proceeds to download the file
    // on failure  it retries 
    // todo: introduce spin lock
    function sendWithRetry(callback) {
      axios(config_output)
        .then(function (response) {
          if (response.data.output.length !== 1) {
            throw new axios.Cancel("Document is not found. Throw error.");
          } else {
            callback(response);
          }
        })
        .catch(errorHandler);
    }
    axios(config)
      .then(function (response) {
        sendWithRetry(processResponse);
      })
      .catch(function (error) {
        console.log(error);
      });
  });
};
function processResponse(response) {
  const outputId = response.data.output[0]._id;
  console.log(
    "Output Document is Generated. Id = " 
    response.data.output[0]._id
  );
  let config_download = {
    method: "get" 
    url: `https://app.edocgen.com/api/v1/output/download/${outputId}` 
    headers: headers 
    responseType: "arraybuffer" 
  };
  axios(config_download)
    .then(function (response) {
      console.log("Output file is downloaded "   `${fileName}.${outputFormat}`);
      fs.writeFileSync(`./${fileName}.${outputFormat}`  response.data);
    })
    .catch(function (error) {
      console.log("Error while downloading");
      console.log(error);
    });
}
单个与多个文档
    
当数据为单个 JSON 时,将生成给定格式的单个文档。
当数据是对象数组时,将生成每个数组元素的文档并将其压缩到文件中。
XML 到文档生成XML 数据的过程很简单。我们需要做的就是传递 XML 文件来代替 JSON 数据。
就像JSON to document,XML to Document 我们也需要documentId outputFileName format and inputFile。除输入文件外,与 JSON 相同的所有内容都将是 XML 文件。
示例 XML 数据如下所示
XML
<?xml version="1.0" encoding="UTF-8" ?>
<marker>
  <values>
    <Invoice_Number>SBU-2053501</Invoice_Number>
    <Invoice_Date>31-07-2020</Invoice_Date>
    <Terms_Payment>Net 15</Terms_Payment>
    <Company_Name>ABC company</Company_Name>
    <Billing_Contact>ABC-Contact1</Billing_Contact>
    <Address>New york  United State</Address>
    <Email>support@edocgen.com</Email>
	<Logo>621cd2b783a6095d7b15a443</Logo> 
     <Sum1>6 751</Sum1>
	 <para>61b334ee7c00363e11da3439</para>
    <ITH>
      <Heading1>Item Description</Heading1>
      <Heading2>Amount</Heading2>
    </ITH>
    <IT>
      <Item_Description>Product Fees: X</Item_Description>
      <Amount>5 000</Amount>
    </IT>
  </values>
<marker>
    
我为 XML 作为数据源所做的代码更改很简单,如下所示
JavaScript
var formBody = new FormData();
formBody.append("documentId"  documentId);
formBody.append("format"  outputFormat);
formBody.append("outputFileName"  fileName);
formBody.append("inputFile"  fs.createReadStream("./XML_Invoice.xml"));数据库到文档生成
    
从数据库生成文档几乎与其他数据源相同。但在这种情况下,我们需要提供连接详细信息和 SQL 查询,而不是上传 inputFile。
SQL 查询的输出列应与文档模板中的标签匹配。
让我们看看如何在代码中进行配置。
JavaScript
const templateId = "<template id>";
const dbVendor = "mysql";
const dbUrl = "<jdbc connection URL>";
const dbLimit = "100";
const dbPassword = "<database password>";
const dbQuery = "SELECT JSON_ARRAY(first  last) FROM customers;";
const outputFormat = "pdf";
// form data prepareation
let formBody = new FormData();
formBody.append("documentId"  templateId);
formBody.append("format"  outputFormat);
formBody.append("dbVendor"  dbVendor);
formBody.append("dbUrl"  dbUrl);
formBody.append("dbLimit"  dbLimit);
formBody.append("dbPassword"  dbPassword);
formBody.append("dbQuery"  dbQuery);
formBody.append("outputFileName"  fileName);
    
其他一切都将保持不变。
通过电子邮件发送文档eDocGen 提供了通过电子邮件发送生成的文档的功能。
文档生成所需的参数应用程序接口:POST-/api/v1/output/email
请求正文JSON| 
     出局  | 
     将需要通过电子邮件发送的输出 ID 放在这里  | 
| 
     电子邮件ID  | 
     将用户电子邮件放在这里  | 
| 
     内容类型  | 
     多部分/表单数据  | 
| 
     x-访问令牌  | 
     来自登录的 JWT 身份验证令牌  | 
let login = require("../edocgen_login");
let axios = require("axios");
const hostName = "https://app.edocgen.com/api/v1/output/email";
const headers = {
  "Content-Type": "application/json" 
  "x-access-token": "null" 
};
const outId = "<output ID>"; // Put output ID here which need to be sent via email
const emailId = "<user email>"; // Put user email here
module.exports.generateFiles = function () {
  let authToken = login.getToken(function handleUsersList(token) {
    headers["x-access-token"] = token;
    let payload = { outId: outId  emailId: emailId };
    let config = {
      method: "post" 
      url: hostName 
      headers: headers 
      data: payload 
    };
    axios(config)
      .then(function (response) {
        console.log("Mail sent");
      })
      .catch(function (error) {
        console.log(error);
      });
  });
};
    
来自 eDocGen 的电子邮件如下所示

还有很多其他的功能我在这里无法涵盖。但我希望这篇文章可以为您提供一个从哪里开始的想法。




