go export html report (using hero precompiled html template engine)

Preface

According to project requirements, the server data needs to be exported to facilitate portability and display. I have exported a htmlreport and considered how to implement it.

  1. Use vueother front-end frameworks to export data into files one by one json, and then jsdynamically render htmlthe view by reading
  2. Write the data directly to htmlthe page, export more html, and iframeload the page through

The second method is used here.

This article mainly introduces goan open source library hero precompiled template engine for fast rendering html.

Common template engines generally have two implementation methods. One is to directly parse the HTML syntax tree and then dynamically splice it according to certain rules. The other is to pre-generate code for the template and call the relevant functions when rendering the template.

goThe official built-in templatepackage is the first implementation method, and the protagonist of this article uses the second method.

hero introduction

You can go directly to github to see it. Here is a brief introduction.

Install

go get github.com/shiyanhui/hero
go get github.com/shiyanhui/hero/hero

// Hero需要goimports处理生成的go代码,所以需要安装goimports.
go get golang.org/x/tools/cmd/goimports

use

hero [options]

options:
	- source:     模板目录,默认为当前目录
	- dest:       生成的go代码的目录,如果没有设置的话,和source一样
	- pkgname:    生成的go代码包的名称,默认为template
  - extensions: source文件的后缀, 如果有多个则用英文逗号隔开, 默认为.html
	- watch:      是否监控模板文件改动并自动编译

example:
	hero -source="./"
	hero -source="$GOPATH/src/app/template" -watch

basic grammar

HeroThere are nine types of statements in total, they are:

  • function definition statement<%: func define %>

    • This statement defines the function corresponding to the template. If there is no function definition statement in a template, the corresponding function will not be generated in the final result.
    • The last parameter of the function must be *bytes.Bufferor io.Writer, hero will automatically recognize the name of the parameter and write the result to the parameter.
    • example:
      • <%: func UserList(userList []string, buffer *bytes.Buffer) %>
      • <%: func UserList(userList []string, w io.Writer) %>
      • <%: func UserList(userList []string, w io.Writer) (int, error) %>
  • template inheritance statement<%~ "parent template" %>

    • This statement declares the template to be inherited.
    • example:<%~ "index.html" >
  • Template include statement<%+ "sub template" %>

    • This statement loads the template to be included into the template. The working principle is somewhat similar C++to that in #include.
    • example:<%+ "user.html" >
  • package import statement<%! go code %>

    • This statement is used to declare all code outside the function, including dependent package imports, global variables, const, etc.

    • This statement will not be inherited by child templates

    • example:

      <%!
      	import (
            	"fmt"
          	"strings"
          )
      
      	var a int
      
      	const b = "hello, world"
      
      	func Add(a, b int) int {
              
              
          	return a + b
      	}
      
      	type S struct {
              
              
          	Name string
      	}
      
      	func (s S) String() string {
              
              
          	return s.Name
      	}
      %>
      
  • block statement<%@ blockName { %> <% } %>

    • The block statement is used to rewrite the block of the same name in the parent model in the child template, thereby realizing template inheritance.

    • example:

      <!DOCTYPE html>
      <html>
          <head>
              <meta charset="utf-8">
          </head>
      
          <body>
              <%@ body { %>
              <% } %>
          </body>
      </html>
      
  • Go code statements<% go code %>

    • This statement defines the portion of code inside the function.

    • example:

      <% for _, user := range userList {
              
               %>
          <% if user != "Alice" {
              
               %>
          	<%= user %>
          <% } %>
      <% } %>
      
      <%
      	a, b := 1, 2
      	c := Add(a, b)
      %>
      
  • native value statement<%==[t] variable %>

    • This statement converts the variable to string.

    • tis the type of the variable, hero will automatically tselect the conversion function based on it. tThe candidate values ​​are:

      • b: bool
      • i: int, int8, int16, int32, int64
      • u: byte, uint, uint8, uint16, uint32, uint64
      • f: float32, float64
      • s: string
      • bs: []byte
      • v: interface

      Notice:

      • If tnot set, tthe default is s.
      • It is best not to use it vbecause the corresponding conversion function is fmt.Sprintf("%v", variable), which is very slow.
    • example:

      <%== "hello" %>
      <%==i 34  %>
      <%==u Add(a, b) %>
      <%==s user.Name %>
      
  • escape value statement<%= statement %>

    • This statement converts the variable into a string and then html.EscapesStringescapes it through memory.

    • tSame as in the native value statement above t.

    • example:

      <%= a %>
      <%= a + b %>
      <%= Add(a, b) %>
      <%= user.Name %>
      
  • comment statement<%# note %>

    • This statement annotates the relevant template, and the annotation will not be generated into the go code.
    • Example: <# 这是一个注释 >.

principle

The final generated code is written through string concatenation io.Writer. Here is an example, the generated code is as follows:

func WriteTreeNodeHtml(param *RenderTemplateParam, w io.Writer) {
    
    
	_buffer := hero.GetBuffer()
	defer hero.PutBuffer(_buffer)
	_buffer.WriteString(`

<html>
    <head>
        <meta charset="utf-8" />
        <link rel="stylesheet" href="css/build.css" />
        <link rel="stylesheet" href="css/jquery.treeview.css" />
        <link rel="stylesheet" href="css/screen.css" />

        <script src="js/jquery.min.js"></script>
        <script src="js/jquery.cookie.js"></script>
        <script src="js/jquery.treeview.js" type="text/javascript"></script>
        <script type="text/javascript">
        $(function() {
            $("#tree").treeview({
                collapsed: true,
                animated: "fast",
                control: "#sidetreecontrol",
                prerendered: true,
                persist: "location"
            });
        })
        </script>
    </head>

    <body style="margin: 10px;">
        <div>
            <h3>`)
	hero.EscapeHTML(GetAppName(), _buffer)
	_buffer.WriteString(`报告</h3>
            <div id=jstree style="font-size:14px">
            <ul class="treeview" id="tree" style="margin-top:6px;">
                <li><a class="jstree-anchor" href="page1.html#case" target="pageframe">
                <i style="margin-left: 4px;margin-right: 4px;" class="icon-file iconfont"></i>案件</a></li>
                <li><a class="jstree-anchor" href="page1.html#evidences" target="pageframe">
                <i style="margin-left: 4px;margin-right: 4px;" class="icon-evidence iconfont"></i>检材信息</a></li>
                <li><a class="jstree-anchor" href="page1.html#brief" target="pageframe">
                <i style="margin-left: 4px;margin-right: 4px;" class="icon-evidence iconfont"></i>数据统计文字概括</a></li>
                <li><a class="jstree-anchor" href="page1.html#summary" target="pageframe">
                <i style="margin-left: 4px;margin-right: 4px;" class="icon-summary iconfont"></i>数据统计清单</a></li>
                `)
	treeNodes, ok := param.Data.([]*ReportTreeNode)
	if !ok {
    
    
		return
	}
	for _, node := range treeNodes {
    
    
		GenerateTreeNode(node, _buffer)
	}
	_buffer.WriteString(`
            </ul>
            </div>
        </div>
    </body>
</html>

`)
	w.Write(_buffer.Bytes())

}

Summarize

Use goGenerate html, the principle is very simple, just write the data into the corresponding place through string splicing. The troublesome point is that htmlthe layout of the page corresponds to the insertion of data.

reference

https://github.com/shiyanhui/hero

Guess you like

Origin blog.csdn.net/DisMisPres/article/details/120998100