做一些文章詳情頁的時候,因為用到了富文本編輯器,因此數(shù)據(jù)庫中存儲的是HTML格式的內(nèi)容,當(dāng)從數(shù)據(jù)庫中讀取顯示到頁面時需要進行轉(zhuǎn)換,否則顯示就是實際的字符串內(nèi)容,因此需要進行轉(zhuǎn)換,轉(zhuǎn)換的代碼很簡單,就是通過關(guān)鍵函數(shù)template.HTML
示例如下:
"content": template.HTML(a.Content),
另外可以自定義模板函數(shù),在模板文件中使用:
package main
import (
"html/template"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.SetFuncMap(template.FuncMap{
"safe": func(str string) template.HTML {
return template.HTML(str)
},
})
router.LoadHTMLFiles("./index.tmpl")
router.GET("/index", func(c *gin.Context) {
c.HTML(200, "index.tmpl", "<a href='lizhouwen.com'>1232</a>")
})
router.Run(":9999")
}
html代碼如下:
tml/template包實現(xiàn)了數(shù)據(jù)驅(qū)動的模板,用于生成可對抗代碼注入的安全HTML輸出。它提供了和text/template包相同的接口,Go語言中輸出HTML的場景都應(yīng)使用text/template包。
在基于MVC的Web架構(gòu)中,我們通常需要在后端渲染一些數(shù)據(jù)到HTML文件中,從而實現(xiàn)動態(tài)的網(wǎng)頁效果。
模板示例
通過將模板應(yīng)用于一個數(shù)據(jù)結(jié)構(gòu)(即該數(shù)據(jù)結(jié)構(gòu)作為模板的參數(shù))來執(zhí)行,來獲得輸出。模板中的注釋引用數(shù)據(jù)接口的元素(一般如結(jié)構(gòu)體的字段或者字典的鍵)來控制執(zhí)行過程和獲取需要呈現(xiàn)的值。模板執(zhí)行時會遍歷結(jié)構(gòu)并將指針表示為’.‘(稱之為”dot”)指向運行過程中數(shù)據(jù)結(jié)構(gòu)的當(dāng)前位置的值。
用作模板的輸入文本必須是utf-8編碼的文本。”Action”—數(shù)據(jù)運算和控制單位—由”{{“和”}}“界定;在Action之外的所有文本都不做修改的拷貝到輸出中。Action內(nèi)部不能有換行,但注釋可以有換行。
HTML文件代碼如下:
我們的HTTP server端代碼如下:
模板語法
{{.}}
模板語法都包含在{{和}}中間,其中{{.}}中的點表示當(dāng)前對象。
當(dāng)我們傳入一個結(jié)構(gòu)體對象時,我們可以根據(jù).來訪問結(jié)構(gòu)體的對應(yīng)字段。例如:
HTML文件代碼如下:
同理,當(dāng)我們傳入的變量是map時,也可以在模板文件中通過.根據(jù)key來取值。
注釋
pipeline
pipeline是指產(chǎn)生數(shù)據(jù)的操作。比如{{.}}、{{.Name}}等。Go的模板語法中支持使用管道符號|鏈接多個命令,用法和unix下的管道類似:|前面的命令會將運算結(jié)果(或返回值)傳遞給后一個命令的最后一個位置。
注意:并不是只有使用了|才是pipeline。Go的模板語法中,pipeline的概念是傳遞數(shù)據(jù),只要能產(chǎn)生數(shù)據(jù)的,都是pipeline。
變量
Action里可以初始化一個變量來捕獲管道的執(zhí)行結(jié)果。初始化語法如下:
其中$variable是變量的名字。聲明變量的action不會產(chǎn)生任何輸出。
條件判斷
Go模板語法中的條件判斷有以下幾種:
range
Go的模板語法中使用range關(guān)鍵字進行遍歷,有以下兩種寫法,其中pipeline的值必須是數(shù)組、切片、字典或者通道。
with
預(yù)定義函數(shù)
執(zhí)行模板時,函數(shù)從兩個函數(shù)字典中查找:首先是模板函數(shù)字典,然后是全局函數(shù)字典。一般不在模板內(nèi)定義函數(shù),而是使用Funcs方法添加函數(shù)到模板里。
預(yù)定義的全局函數(shù)如下:
比較函數(shù)
布爾函數(shù)會將任何類型的零值視為假,其余視為真。
下面是定義為函數(shù)的二元比較運算的集合:
為了簡化多參數(shù)相等檢測,eq(只有eq)可以接受2個或更多個參數(shù),它會將第一個參數(shù)和其余參數(shù)依次比較,返回下式的結(jié)果:
{{eq arg1 arg2 arg3}}
比較函數(shù)只適用于基本類型(或重定義的基本類型,如”type Celsius float32”)。但是,整數(shù)和浮點數(shù)不能互相比較。
自定義函數(shù)
Go的模板支持自定義函數(shù)。
我們可以在模板文件hello.html中使用我們自定義的kua函數(shù)了。
{{kua .Name}}
嵌套template
我們可以在template中嵌套其他的template。這個template可以是單獨的文件,也可以是通過define定義的template。
舉個例子: t.html文件內(nèi)容如下:
ul.html文件內(nèi)容如下:
我們注冊一個templDemo路由處理函數(shù).
tmplDemo函數(shù)的具體內(nèi)容如下:
面我們實現(xiàn)了一個最簡單的Web服務(wù)器軟件。這個服務(wù)器軟件很傻,無論你的URL是什么,所有請求都只返回“Hello World!”字符串。而且這個字符串是寫死在代碼中的。
接下來我們繼續(xù)完善這個Web服務(wù)器軟件,今天我們增加對普通靜態(tài)文件的支持。也就是當(dāng)用戶通過瀏覽器向該服務(wù)器發(fā)送請求的時候該軟件會從磁盤上讀取相應(yīng)的文件,然后發(fā)送給瀏覽器。本次的完善也是很有限的,只對上次的代碼做了很小的改動。這里實現(xiàn)的主要功能是從磁盤讀取一個文件的內(nèi)容,然后封裝http響應(yīng)頭后發(fā)生給瀏覽器。因此,這里主要涉及到Go語言文件訪問相關(guān)的庫的使用。最后實現(xiàn)的效果就是在瀏覽器上顯示html文件渲染后的內(nèi)容:
圖1 實現(xiàn)效果圖
由于涉及到文件的訪問,因此這里先介紹一下文件相關(guān)的包。Go語言文件相關(guān)的操作在os包里面,其中os.File封裝了文件讀寫相關(guān)的操作。如下是os包及File涉及的主要函數(shù)和方法,由于篇幅問題,這里只保留的必要的內(nèi)容:
type File
File代表一個打開的文件對象。
func Open(name string) (file *File, err error)
Open打開一個文件用于讀取。如果操作成功,返回的文件對象的方法可用于讀取數(shù)據(jù);對應(yīng)的文件描述符具有O_RDONLY模式。如果出錯,錯誤底層類型是*PathError。
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
OpenFile是一個更一般性的文件打開函數(shù),大多數(shù)調(diào)用者都應(yīng)用Open或Create代替本函數(shù)。它會使用指定的選項(如O_RDONLY等)、指定的模式(如0666等)打開指定名稱的文件。如果操作成功,返回的文件對象可用于I/O。如果出錯,錯誤底層類型是*PathError。
func (f *File) Read(b []byte) (n int, err error)
Read方法從f中讀取最多l(xiāng)en(b)字節(jié)數(shù)據(jù)并寫入b。它返回讀取的字節(jié)數(shù)和可能遇到的任何錯誤。文件終止標(biāo)志是讀取0個字節(jié)且返回值err為io.EOF。
func (f *File) Write(b []byte) (n int, err error)
Write向文件中寫入len(b)字節(jié)數(shù)據(jù)。它返回寫入的字節(jié)數(shù)和可能遇到的任何錯誤。如果返回值n!=len(b),本方法會返回一個非nil的錯誤。
func (f *File) Close() error
Close關(guān)閉文件f,使文件不能用于讀寫。它返回可能出現(xiàn)的錯誤。
下面是本文實現(xiàn)的從文件讀取數(shù)據(jù)的方法,在Web服務(wù)的主程序中通過調(diào)用該方法來從磁盤讀取數(shù)據(jù)。這個方法的輸入是文件路徑,輸出是文件的內(nèi)容。
圖2 文件讀取方法實現(xiàn)
細(xì)心的同學(xué)可能已經(jīng)發(fā)現(xiàn),我們這里讀取數(shù)據(jù)并沒有用File的Read方法,而是用了另外一個包ioutil的ReadAll方法。這里使用ioutil包的方法也是作為一個引子,期望大家更多的了解Go語言提供的庫函數(shù)。該方法與File的Read方法功能是一樣的,但性能上要好一些。
ioutil包是一個io相關(guān)的包,提供了對常見io操作的性能優(yōu)化,該包提供的功能主要包括:
func ReadAll(r io.Reader) ([]byte, error)
從一個io.Reader讀取所有數(shù)據(jù),并返回一個字節(jié)數(shù)組
func ReadDir(dirname string) ([]os.FileInfo, error)
從一個目錄讀取數(shù)據(jù),并得到這個目錄里的文件對象列表
func ReadFile(filename string) ([]byte, error)
讀取指定文件的內(nèi)容,并返回一個字節(jié)數(shù)組
關(guān)于文件操作的相關(guān)介紹本文先到這里,更詳細(xì)的介紹我們后面專門另起新文介紹。
Web服務(wù)端改動的地方也很少,除了上面介紹的讀取文件內(nèi)容的方法外,在主函數(shù)中調(diào)整了數(shù)據(jù)發(fā)送方面的代碼,其它地方均沒有做改動。下面是涉及到的代碼片段。
圖3 服務(wù)端代碼修改
如圖3所示,這里一共修改了3個地方:
測試驗證
完成上述修改后,我們就可以通過瀏覽器進行驗證了。這里需要具備一個html文件,該文件保存在與服務(wù)端相同的路徑下面,名稱為index.html。該文件的內(nèi)容如下:
圖4 HTML文件內(nèi)容
如果熟悉html的同學(xué),很清楚是做什么的,就是現(xiàn)實一個紅色的“Hello World!”字符串,不了解html的同學(xué)也沒關(guān)系,了解到這里就行。
在服務(wù)端運行程序, 瀏覽器數(shù)據(jù)地址后回車,可以看到如下內(nèi)容:
圖5 最終效果圖
好了,今天先到這,后面文章我們將增加對圖片的支持。
?
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。