go 导出 html 报告(使用 hero 预编译 html 模板引擎)
前言
項目需求,需要將服務器的數據進行導出,方便攜帶展示,做了一次 html 報告的導出,考慮如何實現。
這里使用的是第二種方式。
本篇主要介紹一下 go 的一個開源庫 hero 預編譯模板引擎,用于快速的渲染 html。
常見的模板引擎一般有兩種實現方式,一種是直接解析 HTML 語法樹,然后根據一定的規則動態的拼接,另外一種是把模板預先生成代碼,渲染模板時調用相關的函數即可。
go 官方內置的 template 包是第一種實現方式,本篇的主角用的是第二種。
hero 簡介
可以直接去 github 上看,這里做一個簡短的介紹。
安裝
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使用
hero [options]options:- source: 模板目錄,默認為當前目錄- dest: 生成的go代碼的目錄,如果沒有設置的話,和source一樣- pkgname: 生成的go代碼包的名稱,默認為template- extensions: source文件的后綴, 如果有多個則用英文逗號隔開, 默認為.html- watch: 是否監控模板文件改動并自動編譯example:hero -source="./"hero -source="$GOPATH/src/app/template" -watch基本語法
Hero 總共有九種語句,他們分別是:
-
函數定義語句 <%: func define %>
- 該語句定義了該模板所對應的函數,如果一個模板中沒有函數定義語句,那么最終結果不會生成對應的函數。
- 該函數最后一個參數必須為*bytes.Buffer或者io.Writer, hero會自動識別該參數的名字,并把把結果寫到該參數里。
- 例:
- <%: func UserList(userList []string, buffer *bytes.Buffer) %>
- <%: func UserList(userList []string, w io.Writer) %>
- <%: func UserList(userList []string, w io.Writer) (int, error) %>
-
模板繼承語句 <%~ "parent template" %>
- 該語句聲明要繼承的模板。
- 例: <%~ "index.html" >
-
模板include語句 <%+ "sub template" %>
- 該語句把要include的模板加載進該模板,工作原理和C++中的#include有點類似。
- 例: <%+ "user.html" >
-
包導入語句 <%! go code %>
-
該語句用來聲明所有在函數外的代碼,包括依賴包導入、全局變量、const等。
-
該語句不會被子模板所繼承
-
例:
<%!import ("fmt""strings")var a intconst 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} %>
-
-
塊語句 <%@ blockName { %> <% } %>
-
塊語句是用來在子模板中重寫父模中的同名塊,進而實現模板的繼承。
-
例:
<!DOCTYPE html> <html><head><meta charset="utf-8"></head><body><%@ body { %><% } %></body> </html>
-
-
Go代碼語句 <% go code %>
-
該語句定義了函數內部的代碼部分。
-
例:
<% for _, user := range userList { %><% if user != "Alice" { %><%= user %><% } %> <% } %><%a, b := 1, 2c := Add(a, b) %>
-
-
原生值語句 <%==[t] variable %>
-
該語句把變量轉換為string。
-
t是變量的類型,hero會自動根據t來選擇轉換函數。t的待選值有:
- b: bool
- i: int, int8, int16, int32, int64
- u: byte, uint, uint8, uint16, uint32, uint64
- f: float32, float64
- s: string
- bs: []byte
- v: interface
注意:
- 如果t沒有設置,那么t默認為s.
- 最好不要使用v,因為其對應的轉換函數為fmt.Sprintf("%v", variable),該函數很慢。
-
例:
<%== "hello" %> <%==i 34 %> <%==u Add(a, b) %> <%==s user.Name %>
-
-
轉義值語句 <%= statement %>
-
該語句把變量轉換為string后,又通過html.EscapesString記性轉義。
-
t跟上面原生值語句中的t一樣。
-
例:
<%= a %> <%= a + b %> <%= Add(a, b) %> <%= user.Name %>
-
-
注釋語句 <%# note %>
- 該語句注釋相關模板,注釋不會被生成到go代碼里邊去。
- 例: <# 這是一個注釋 >.
原理
最終生成的代碼,就是通過字符串拼接,寫入 io.Writer。下面是一個例子,生成后的代碼如下:
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())}總結
使用 go 生成 html,原理很簡單,通過字符串拼接,將數據都寫入對應的地方即可。麻煩的點就在于 html 頁面的布局和數據的插入對應。
參考
https://github.com/shiyanhui/hero
總結
以上是生活随笔為你收集整理的go 导出 html 报告(使用 hero 预编译 html 模板引擎)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: adb logcat 保存_保存的log
- 下一篇: CM3计算板读取SHT30以及I2C驱动