golang基于JSON请求生成PDF的HTTP服务插件库pdfgen的使用

Golang基于JSON请求生成PDF的HTTP服务插件库pdfgen的使用

安装和运行

推荐使用Docker容器运行,通过挂载模板目录(这里使用提供的示例template目录):

docker run --rm -it -p 8888:8888 \
  --mount src=my_templates/,target=/etc/pdfgen/templates,type=bind \
  hyperboloide/pdfgen

如果不使用Docker,需要先安装wkhtmltopdf,然后运行:

go install github.com/hyperboloide/pdfgen
PDFGEN_TEMPLATES=./templates pdfgen

安装后可以通过以下命令测试:

curl -H "Content-Type: application/json" -X POST -d @my_json_file.json \
  http://localhost:8888/invoice > result.pdf

注意:渲染结果可能因操作系统(特别是OSX)和安装的字体而有所不同,因此建议在Docker环境中进行测试和开发,以确保生产环境中的结果一致。

模板

PDF是从HTML模板生成的。这些模板与Django模板非常相似。

例如以下模板:

<h1>Hello, {{ user }}</h1>

可以通过application/json POST请求生成:

{"user": "fred"}

响应类型为application/pdf,包含生成的PDF文件。

每个PDF模板都应该有自己的目录,位于PDFGEN_TEMPLATES环境变量定义的根目录下。

URL端点将从这些目录名称生成。例如,invoice目录中的模板将可以通过类似http://host:port/invoice的URL访问。

模板目录必须包含一个index.html文件,可选地包含一个footer.html文件。其他资源如图像和CSS也应该放在该目录中。

注意:每个PDF都是独立生成的,因此模板应该使用绝对路径。例如:

<link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css" media='screen,print'>

最后,不要忘记将PDFGEN_TEMPLATES环境变量设置为模板父目录的路径。或者,您可以将模板复制到以下任一位置: /etc/pdfgen/templates~/.templates

添加字体

您可以创建一个包含字体并重建缓存的新容器。以下是Dockerfile示例:

FROM hyperboloide/pdfgen
COPY my_fonts /usr/local/share/fonts/
RUN  fc-cache -f -v

完整示例

1. 创建模板目录结构

my_templates/
└── invoice
    ├── index.html
    └── style.css

2. 示例index.html

<!DOCTYPE html>
<html>
<head>
    <title>Invoice</title>
    <link rel="stylesheet" href="/invoice/style.css">
</head>
<body>
    <h1>Invoice #{{ .number }}</h1>
    <p>Date: {{ .date }}</p>
    <p>Customer: {{ .customer }}</p>
    <table>
        <thead>
            <tr>
                <th>Item</th>
                <th>Quantity</th>
                <th>Price</th>
            </tr>
        </thead>
        <tbody>
            {{ range .items }}
            <tr>
                <td>{{ .name }}</td>
                <td>{{ .quantity }}</td>
                <td>${{ .price }}</td>
            </tr>
            {{ end }}
        </tbody>
    </table>
    <p class="total">Total: ${{ .total }}</p>
</body>
</html>

3. 示例JSON请求

{
    "number": "INV-2023-001",
    "date": "2023-05-15",
    "customer": "John Doe",
    "items": [
        {"name": "Product A", "quantity": 2, "price": 50.00},
        {"name": "Product B", "quantity": 1, "price": 75.50},
        {"name": "Service C", "quantity": 3, "price": 20.00}
    ],
    "total": 205.50
}

4. 生成PDF的命令

curl -H "Content-Type: application/json" -X POST -d @invoice_data.json \
  http://localhost:8888/invoice > invoice.pdf

5. Go代码集成示例

package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "net/http"
    "os"
)

func main() {
    // 准备JSON数据
    invoiceData := map[string]interface{}{
        "number":   "INV-2023-001",
        "date":     "2023-05-15",
        "customer": "John Doe",
        "items": []map[string]interface{}{
            {"name": "Product A", "quantity": 2, "price": 50.00},
            {"name": "Product B", "quantity": 1, "price": 75.50},
            {"name": "Service C", "quantity": 3, "price": 20.00},
        },
        "total": 205.50,
    }

    jsonData, err := json.Marshal(invoiceData)
    if err != nil {
        panic(err)
    }

    // 发送请求到pdfgen服务
    resp, err := http.Post("http://localhost:8888/invoice", "application/json", bytes.NewBuffer(jsonData))
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    // 读取PDF响应
    pdfBytes, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }

    // 保存PDF文件
    err = ioutil.WriteFile("invoice.pdf", pdfBytes, 0644)
    if err != nil {
        panic(err)
    }
}

更多关于golang基于JSON请求生成PDF的HTTP服务插件库pdfgen的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于JSON请求生成PDF的HTTP服务插件库pdfgen的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用pdfgen库基于JSON请求生成PDF的HTTP服务

pdfgen是一个Go语言库,用于基于JSON请求生成PDF文档。下面我将详细介绍如何使用这个库创建一个HTTP服务来生成PDF。

安装pdfgen

首先,确保你已经安装了Go环境(1.13+),然后使用以下命令安装pdfgen:

go get github.com/pdfgen-dev/pdfgen

基本HTTP服务示例

下面是一个完整的HTTP服务示例,它接收JSON请求并返回生成的PDF:

package main

import (
	"log"
	"net/http"
	"os"

	"github.com/pdfgen-dev/pdfgen/pkg/pdf"
)

func main() {
	// 创建HTTP处理器
	http.HandleFunc("/generate-pdf", generatePDFHandler)

	// 启动HTTP服务器
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Printf("Server starting on port %s...", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

func generatePDFHandler(w http.ResponseWriter, r *http.Request) {
	// 只接受POST请求
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 解析JSON请求体
	var request pdf.GenerateRequest
	if err := pdf.ParseGenerateRequest(r, &request); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// 生成PDF
	pdfBytes, err := pdf.Generate(&request)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 设置响应头
	w.Header().Set("Content-Type", "application/pdf")
	w.Header().Set("Content-Disposition", "attachment; filename=generated.pdf")

	// 写入PDF内容
	if _, err := w.Write(pdfBytes); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

JSON请求格式

pdfgen接受的JSON请求通常包含以下字段:

{
  "html": "<html><body><h1>Hello World</h1></body></html>",
  "options": {
    "margin": {
      "top": "10mm",
      "right": "10mm",
      "bottom": "10mm",
      "left": "10mm"
    },
    "format": "A4",
    "orientation": "portrait"
  }
}

高级配置

1. 自定义PDF选项

options := pdf.Options{
    Margin: pdf.Margin{
        Top:    "20mm",
        Right:  "20mm",
        Bottom: "20mm",
        Left:   "20mm",
    },
    Format:      "Letter",
    Orientation: "landscape",
    Header: &pdf.HeaderFooter{
        HTML: "<div style='text-align: center;'>Page Header</div>",
    },
    Footer: &pdf.HeaderFooter{
        HTML: "<div style='text-align: center;'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>",
    },
}

2. 使用模板

pdfgen支持使用Go模板来动态生成HTML:

request := pdf.GenerateRequest{
    Template: pdf.Template{
        Name: "invoice",
        Data: map[string]interface{}{
            "invoiceNumber": "INV-2023-001",
            "date":          "2023-01-01",
            "items": []map[string]interface{}{
                {"name": "Item 1", "price": 100},
                {"name": "Item 2", "price": 200},
            },
        },
    },
    Options: options,
}

3. 添加自定义字体

options := pdf.Options{
    Fonts: []pdf.Font{
        {
            Family: "Roboto",
            Style:  "normal",
            Weight: "400",
            Src: []pdf.FontSrc{
                {URL: "https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu4mxK.woff2"},
            },
        },
    },
}

部署建议

  1. Docker部署:可以将服务打包为Docker容器方便部署
  2. 性能优化:对于高并发场景,考虑添加缓存或限流机制
  3. 安全性:添加API密钥验证或JWT认证

错误处理

pdfgen会返回详细的错误信息,建议在生产环境中记录这些错误:

pdfBytes, err := pdf.Generate(&request)
if err != nil {
    log.Printf("PDF生成失败: %v", err)
    http.Error(w, "PDF生成失败", http.StatusInternalServerError)
    return
}

总结

pdfgen库提供了一个简单而强大的方式来基于JSON请求生成PDF。通过上面的示例,你可以快速搭建一个PDF生成服务,并根据需要进行扩展。记得根据你的具体需求调整PDF选项和错误处理逻辑。

回到顶部