如何在创建pdf时使用渲染的模板

时间:2019-03-11 10:46:00

标签: pdf go

好,所以我是Echo框架的Go Lang,尝试构建pdf,它将从数据库源中加载数据-稍后再介绍。

这就是我渲染pdf html布局的方式,

func (c *Controller) DataTest(ec echo.Context) error {
  return ec.Render(http.StatusOK, "pdf.html", map[string]interface{}{
    "name": "TEST",
    "msg":  "Hello, XXXX!",
  })
}

上面的函数工作正常,并呈现html(我为该函数构建了一个临时路径)。现在,我想使用该函数作为html模板来构建pdf。

所以我正在使用wkhtmltopdf和lib "github.com/SebastiaanKlippert/go-wkhtmltopdf"

这就是我在pdf中呈现html的方式,

html, err := ioutil.ReadFile("./assets/pdf.html")

if err != nil {
    return err
}

但是我需要能够更新模板,所以这就是为什么我尝试呈现页面并将其带入pdf的原因。

但是,Echo框架返回一个错误类型,而不是字节或字符串类型,我不确定如何更新它,以便将渲染的内容作为字节返回。

谢谢

更新

page := wkhtmltopdf.NewPageReader(bytes.NewReader(c.DataTest(data)))

这是我当前的工作方式,数据只是一个html字符串,然后将其转换为NewReader的一个字节片。

这很好,但是我想通过Echo将DataTest函数转换为完全呈现的html页面。这样做的问题是,当您返回呈现的页面时,该页面将作为错误类型返回。

所以我试图找出更新原因,所以我可以将数据作为html字符串返回,然后将其作为字节片放入。

2 个答案:

答案 0 :(得分:0)

据我所知,您想要做

  1. 从模板渲染HTML
  2. 将HTML转换为PDF
  3. 将其发送为HTTP响应吗?您的问题尚不清楚这部分,但实际上并不重要。

因此,Echo返回error的原因是实际上它不仅完成模板渲染,而且还向客户端发送响应。如果要在两者之间做其他事情,则不能从echo中使用该方法。

幸运的是,echo并没有做任何神奇的事情。您可以只使用具有相同结果的标准模板包。

func GetHtml(filename string, data interface{}) (string, error) {
    filedata, err := ioutil.ReadFile(filename)
    if err != nil {
        return "", err
    }

    asString := string(filedata)
    t, err := template.New("any-name").Parse(asString)
    if err != nil {
        return "", err
    }

    var buffer bytes.Buffer
    err = t.Execute(&buffer, data)
    if err != nil {
        return "", err
    }

    return buffer.String(), nil
}

您有返回string的函数。如果可以的话,可以使用buffer.Bytes()来拥有字节数组。

此后,您可以做任何事情,例如转换为PDF并使用echoCtx.Response().Writer()写回客户端。

希望有帮助,但是将来尝试提出更精确的问题,那么您更有可能收到准确的答复。

答案 1 :(得分:0)

如果要呈现html,请使用echo的自定义中间件。希望对您有帮助。

main.go

package main

import (
    "bufio"
    "bytes"
    "errors"
    "fmt"
    "html/template"
    "io"
    "net"

    "net/http"

    "github.com/labstack/echo"
)

type TemplateRegistry struct {
    templates map[string]*template.Template
}

func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    tmpl, ok := t.templates[name]
    if !ok {
        err := errors.New("Template not found -> " + name)
        return err
    }
    return tmpl.ExecuteTemplate(w, "base.html", data)
}

func main() {
    e := echo.New()

    templates := make(map[string]*template.Template)
    templates["about.html"] = template.Must(template.ParseFiles("view/about.html", "view/base.html"))
    e.Renderer = &TemplateRegistry{
        templates: templates,
    }

    // add custom middleware
    // e.Use(PdfMiddleware)

    // only AboutHandler for Pdf
    e.GET("/about", PdfMiddleware(AboutHandler))

    // Start the Echo server
    e.Logger.Fatal(e.Start(":8080"))
}

// custom middleware
func PdfMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) (err error) {
        resBody := new(bytes.Buffer)
        mw := io.MultiWriter(c.Response().Writer, resBody)
        writer := &bodyDumpResponseWriter{Writer: mw, ResponseWriter: c.Response().Writer}
        c.Response().Writer = writer

        if err = next(c); err != nil {
            c.Error(err)
        }

        // or use resBody.Bytes()
        fmt.Println(resBody.String())
        return
    }
}

type bodyDumpResponseWriter struct {
    io.Writer
    http.ResponseWriter
}

func (w *bodyDumpResponseWriter) WriteHeader(code int) {
    w.ResponseWriter.WriteHeader(code)
}

func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
    return w.Writer.Write(b)
}

func (w *bodyDumpResponseWriter) Flush() {
    w.ResponseWriter.(http.Flusher).Flush()
}

func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
    return w.ResponseWriter.(http.Hijacker).Hijack()
}

func AboutHandler(c echo.Context) error {
    return c.Render(http.StatusOK, "about.html", map[string]interface{}{
        "name": "About",
        "msg":  "All about Boatswain!",
    })
}

view / about.html

{{define "title"}}
  Boatswain Blog | {{index . "name"}}
{{end}}

{{define "body"}}
  <h1>{{index . "msg"}}</h1>
  <h2>This is the about page.</h2>
{{end}}

view / base.html

{{define "base.html"}}
<!DOCTYPE html>
  <html>
    <head>
      <title>{{template "title" .}}</title>
    </head>
    <body>
      {{template "body" .}}
    </body>
  </html>
{{end}}