Go Web下gin框架的模板渲染的實現(xiàn)
〇、前言
Gin框架是一個用于構建Web應用程序的輕量級Web框架,使用Go語言開發(fā)。它具有高性能、低內存占用和快速路由匹配的特點,旨在提供簡單、快速的方式來開發(fā)可擴展的Web應用程序。
Gin框架的設計目標是保持簡單和易于使用,同時提供足夠的靈活性和擴展性,使開發(fā)人員能夠根據項目的需求進行定制。它提供了許多有用的功能,如中間件支持、路由組、請求參數解析、模板渲染等,使開發(fā)人員能夠快速構建高效的Web應用程序。
以下是Gin框架的一些主要特性:
快速的性能:Gin框架采用了高性能的路由引擎,使請求路由匹配變得非??焖?。
中間件支持:Gin框架支持中間件機制,允許你在請求處理過程中添加自定義的中間件,用于處理認證、日志記錄、錯誤處理等功能。
路由組:Gin框架允許將路由按照邏輯組織成路由組,使代碼結構更清晰,并且可以為不同的路由組添加不同的中間件。
請求參數解析:Gin框架提供了方便的方法來解析請求中的參數,包括查詢字符串參數、表單參數、JSON參數等。
模板渲染:雖然Gin框架本身不提供模板引擎,但它與多種模板引擎庫(如html/template、pongo2等)集成,使你能夠方便地進行模板渲染。
錯誤處理:Gin框架提供了內置的錯誤處理機制,可以捕獲和處理應用程序中的錯誤,并返回適當的錯誤響應。
總體而言,Gin框架是一個簡單、輕量級但功能強大的Web框架,非常適合構建高性能、可擴展的Web應用程序。它在Go語言社區(qū)中得到廣泛的認可,并被許多開發(fā)人員用于構建各種類型的Web應用程序。
一、html/template
html/template
是Go語言標準庫中的一個包,用于生成和渲染HTML模板。它提供了一種安全且靈活的方式來生成HTML輸出,支持模板繼承、變量替換、條件語句、循環(huán)結構等功能。
html/template
包的主要目標是防止常見的Web安全漏洞,如跨站腳本攻擊(XSS)。它通過自動進行HTML轉義和編碼來確保生成的HTML是安全的,并防止惡意用戶注入惡意代碼。
使用html/template
包可以將動態(tài)數據與靜態(tài)HTML模板分離,使代碼更易于維護和重用。你可以定義模板文件,然后將數據傳遞給模板進行渲染,最后生成最終的HTML輸出。
(一)初次渲染
先創(chuàng)建一個名為 hello.tmpl
的文件:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>Hello</title> </head> <body> <p>hello, {{.}}</p> </body> </html>
這里的{{.}}
中的.
就代表了我們要填充的東東,接著創(chuàng)建我們的main.go
函數:
package main import ( "fmt" "html/template" "net/http" ) func sayHello(w http.ResponseWriter, r *http.Request) { // 請勿刻舟求劍,用絕對地址 t, err := template.ParseFiles("/Users/luliang/GoLand/gin_practice/chap1/hello.tmpl") if err != nil { fmt.Println("http server failed:%V", err) return } // 渲染模板 err = t.Execute(w, "小王子!") if err != nil { fmt.Println("http server failed:%V", err) return } } func main() { http.HandleFunc("/hello", sayHello) err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Println("http server failed:%V", err) return } }
使用html/template
進行HTML模板渲染的一般步驟如下:
定義模板:
首先,你需要定義HTML模板??梢栽诖a中直接定義模板字符串,也可以將模板保存在獨立的文件中。比如我們創(chuàng)建了模板:hello.tmpl
;創(chuàng)建模板對象:
使用template.New()函數創(chuàng)建一個模板對象。你可以選擇為模板對象指定一個名稱,以便在渲染過程中引用它。解析模板:
使用模板對象的Parse()或ParseFiles()方法解析模板內容。如果模板內容保存在單獨的文件中,可以使用ParseFiles()方法解析文件內容并關聯(lián)到模板對象。渲染模板:
創(chuàng)建一個用于存儲模板數據的數據結構,并將數據傳遞給模板對象的Execute()方法。該方法將渲染模板并將結果寫入指定的輸出位置(如os.Stdout或http.ResponseWriter)。
在瀏覽器中輸入:127.0.0.0:9000/hello
就可以看到結果:hello, 小王子!
(二)傳入其它數據進行渲染
上次渲染,我們用的是這一句:err = t.Execute(w, "小王子!")
,可以看到我們傳入了一個字符串而已。這次我們打算傳點稍微不同的其它數據。繼續(xù)編寫模板test.tmpl
:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>Hello</title> </head> <body> <p>姓名: {{.Name}}</p> <p>年齡: {{.Age}}</p> <p>性別: {{.Gander}}</p> </body> </html>
可以看到,我們的模板稍微復雜起來了!繼續(xù)編寫 main.go
:
package main import ( "fmt" "html/template" "net/http" ) type User struct { Name string Gander string // 首字母是否大小寫,作為是否對外暴露的標識 Age int } func sayHello(w http.ResponseWriter, r *http.Request) { // 定義模板 u1 := User{ Name: "小王子", Gander: "男", Age: 19, } // 解析模板 t, err := template.ParseFiles("/Users/luliang/GoLand/gin_practice/chap2/test.tmpl") if err != nil { fmt.Println("ParseFiles failed:%V", err) return } err = t.Execute(w, u1) if err != nil { return } } func main() { http.HandleFunc("/hello", sayHello) err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Println("http server failed:%V", err) return } }
可以看到我們在里面定義了一個結構類型 User,傳入了一個 User 對象 u1:err = t.Execute(w, u1)
type User struct { Name string Gander string // 首字母是否大小寫,作為是否對外暴露的標識 Age int }
趕緊看看運行結果,可以看到結果符合預期:
姓名: 小王子
年齡: 19
性別: 男
(三)定義函數參與渲染
定義我們的模板:f.tmpl
:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>hello</title> </head> <body> {{ kua . }} </body> </html>
可以看到,我們的模板里面有一個函數名字叫做 kua
,沒錯,這就是我們要的函數。
編寫main.go
:
package main import ( "fmt" "html/template" "net/http" ) func f(w http.ResponseWriter, r *http.Request) { // 定義模板 k := func(name string) (string, error) { return name + "太棒了!", nil } t := template.New("f.tmpl") t.Funcs(template.FuncMap{ "kua": k, }) // 解析模板 _, err := t.ParseFiles("/Users/luliang/GoLand/gin_practice/chap3/f.tmpl") if err != nil { return } // 渲染模板 err = t.Execute(w, "小王子") if err != nil { return } } func main() { http.HandleFunc("/hello", f) err := http.ListenAndServe(":9002", nil) if err != nil { fmt.Println("http server failed:%V", err) return } }
可以看到,我用了一個關鍵語句將函數kua 關聯(lián)到了模板:
t.Funcs(template.FuncMap{ "kua": k, })
點擊運行,可以看到結果:小王子太棒了!
(四)c.HTML() 渲染
在Gin框架中,可以使用c.HTML()方法來進行HTML模板渲染。該方法接收HTTP狀態(tài)碼、模板名稱和渲染所需的數據作為參數。
編寫模板index.tmpl
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>posts/index</title> </head> <body> {{.title}} </body> </html>
可以看到我們只需渲染傳入對象的 title 值,編寫 main.go
:
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { r := gin.Default() r.LoadHTMLFiles("/Users/luliang/GoLand/gin_practice/chap4/index.tmpl") r.GET("/index", func(c *gin.Context) { c.HTML(http.StatusOK, "index.tmpl", gin.H{ "title": "你好,前端真是太有意思了!", }) }) r.Run(":9091") }
首先,創(chuàng)建一個 gin.default()路由對象,然后給該對象載入已經寫好的模板文件,之后就可以用 GET 函數進行請求了。
先看看 GET 是什么東西:
// GET is a shortcut for router.Handle("GET", path, handlers). func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodGet, relativePath, handlers) }
它說,GET 是router.Handle("GET", path, handlers)
的一個捷徑。再看看router.Handle("GET", path, handlers)
是什么東西:
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes { absolutePath := group.calculateAbsolutePath(relativePath) handlers = group.combineHandlers(handlers) group.engine.addRoute(httpMethod, absolutePath, handlers) return group.returnObj() } // Handle registers a new request handle and middleware with the given path and method. // The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes. // See the example code in GitHub. // // For GET, POST, PUT, PATCH and DELETE requests the respective shortcut // functions can be used. // // This function is intended for bulk loading and to allow the usage of less // frequently used, non-standardized or custom methods (e.g. for internal // communication with a proxy).
原來就是做了一下中間處理,注冊了一個新的請求句柄。它還說GET, POST, PUT, PATCH、DELETE 都有類似的捷徑。之后在 handlers中放一個匿名函數:
func(c *gin.Context) { c.HTML(http.StatusOK, "index.tmpl", gin.H{ "title": "你好,前端真是太有意思了!", }) }
這個函數就是用于渲染的函數。猜測c.HTML()
依然是一個 shortcut:
// HTML renders the HTTP template specified by its file name. // It also updates the HTTP code and sets the Content-Type as "text/html". // See http://golang.org/doc/articles/wiki/ func (c *Context) HTML(code int, name string, obj any) { instance := c.engine.HTMLRender.Instance(name, obj) c.Render(code, instance) }
可以看到真正干活的還是 Render()
。
點擊運行,結果為:你好,前端真是太有意思了!
(五)從多個模板中選擇一個進行渲染
如果要渲染多個文件,該如何操作?比如我們通過輸入不同的網站,服務器這時只需要選擇不同的模板進行渲染就好。在這里創(chuàng)建了兩個模板文件,users/index.tmpl
:
{{define "users/index.tmpl"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>users/index</title> </head> <body> {{.title}} </body> </html> {{end}}
posts/index.tmpl
:
{{define "posts/index.tmpl"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>posts/index</title> </head> <body> {{.title}} </body> </html> {{end}}
這里使用了{{define "posts/index.tmpl"}}...{{end}}
結構,對模板文件進行了命名。
編寫main.go
:
package main import ( "github.com/gin-gonic/gin" "html/template" "net/http" ) func main() { r := gin.Default() r.LoadHTMLGlob("/Users/luliang/GoLand/gin_practice/chap5/templates/**/*") r.GET("/posts/index", func(c *gin.Context) { c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ "title": "posts/index.tmpl", }) }) r.GET("/users/index", func(c *gin.Context) { c.HTML(http.StatusOK, "users/index.tmpl", gin.H{ "title": "送你到百度!", }) }) r.Run(":9091") }
我們在在瀏覽器地址欄輸入http://127.0.0.1:9091/users/index
可以得到:送你到百度!;而輸入http://127.0.0.1:9091/posts/index
可以得到:posts/index.tmpl。
(六)加點東西,使得事情朝著有意思的方向進行!
我們?yōu)榱耸沟镁W頁畫面更有趣,這里使用了多個文件,分別是index.css、index.js。編寫:index.css
:
body { background-color: #00a7d0; }
沒錯只有一句話。接下來編寫 index.js
:
alert("Hello, Web!")
沒錯,也只有一句話。然后,我們把 css、js 文件引入到 index.tmpl
中:
{{define "users/index.tmpl"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="/xxx/index.css" rel="external nofollow" > <title>users/index</title> </head> <body> {{.title}} <script src="/xxx/index.js"></script> </body> </html> {{end}}
接下來寫main.go
:
package main import ( "github.com/gin-gonic/gin" "html/template" "net/http" ) func main() { r := gin.Default() // 加載靜態(tài)文件 r.Static("/xxx", "/Users/luliang/GoLand/gin_practice/chap5/statics") r.LoadHTMLGlob("/Users/luliang/GoLand/gin_practice/chap5/templates/**/*") r.GET("/posts/index", func(c *gin.Context) { c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ "title": "posts/index.tmpl", }) }) r.GET("/users/index", func(c *gin.Context) { c.HTML(http.StatusOK, "users/index.tmpl", gin.H{ "title": "送你到百度!", }) }) r.Run(":9091") }
因為我們要把 css、js 文件加載進去,因此要用 r.Static()
函數把放置靜態(tài)文件的目錄加入進去。為了復用,第一個參數“/xxx”的意思是,只要index.tmpl文件中存在“/xxx”字段就直接指到我們設置的目錄。
運行結果:首先 js 文件會首先渲染:
之后,css 文件會渲染:
可以看到這里出現(xiàn)了一個超鏈接,那是因為我們在這個字符后面插入了一個函數:
// 添加自定義函數 r.SetFuncMap(template.FuncMap{ "safe": func(str string) template.HTML { return template.HTML(str) }, })
配合 index.tmpl
,就可以了。
二、利用已有模板進行部署
通過以上的例子,終于學會了在模板中插入大量的css、js 進行渲染了!
首先找到某個網站,比如站長之家,下載一個模板:
選擇第一個,下載之后解壓:
static 外面的 index.html
有用,其它都可以忽略。把 static 里面的文件夾復制到我們的工作目錄:
同時,把 index.html
文件復制到 posts
(無所謂,強迫癥而已),就可以使用了。
r.GET("/home", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", nil) })
這樣,在地址欄輸入:http://127.0.0.1:9091/home
,就可以看到效果了:
渲染的相當完美!這里會存在一些小細節(jié),比如在 index.html文件中需要把 css、js文件的地址進行變更,變更到你放置這些文件的地址:
代碼附上main.go
:
package main import ( "github.com/gin-gonic/gin" "html/template" "net/http" ) func main() { r := gin.Default() // 加載靜態(tài)文件 r.Static("/xxx", "/Users/luliang/GoLand/gin_practice/chap5/statics") // 添加自定義函數 r.SetFuncMap(template.FuncMap{ "safe": func(str string) template.HTML { return template.HTML(str) }, }) r.LoadHTMLGlob("/Users/luliang/GoLand/gin_practice/chap5/templates/**/*") r.GET("/posts/index", func(c *gin.Context) { c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ "title": "posts/index.tmpl", }) }) r.GET("/users/index", func(c *gin.Context) { c.HTML(http.StatusOK, "users/index.tmpl", gin.H{ "title": "<a , }) }) r.GET("/home", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", nil) }) r.Run(":9091") }
這意味著,我們以后要想寫網頁,根本不需要進行大量的無意義的編程,利用 ChatGPT,我們可以寫出大量的優(yōu)秀的css、js 網頁,我們要做的只是進行適量的改動,這將極大地豐富我們的創(chuàng)造力!
三、總結
本文從簡單到難,對Go Web中 gin 框架下的模板渲染進行了簡單的闡述。
到此這篇關于Go Web下gin框架的模板渲染的實現(xiàn)的文章就介紹到這了,更多相關Go gin 模板渲染內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
golang 實現(xiàn)tcp server端和client端,并計算RTT時間操作
這篇文章主要介紹了golang 實現(xiàn)tcp server端和client端,并計算RTT時間操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12golang定時器Timer的用法和實現(xiàn)原理解析
這篇文章主要介紹了golang定時器Ticker,本文主要來看一下Timer的用法和實現(xiàn)原理,需要的朋友可以參考以下內容2023-04-04