簡(jiǎn)介本次訓(xùn)練主要包括的內(nèi)容

1. 創(chuàng)建一個(gè)可以load & save的數(shù)據(jù)結(jié)構(gòu)

2. 學(xué)會(huì)利用 net/http 包去構(gòu)建一個(gè)web應(yīng)用

3. 學(xué)會(huì)利用 html/temp" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢(xún) 在線咨詢(xún)
15158846557 在線咨詢(xún)
所在位置: 首頁(yè) > 營(yíng)銷(xiāo)資訊 > 網(wǎng)站運(yùn)營(yíng) > GO實(shí)戰(zhàn)訓(xùn)練:如何快速搭建一個(gè)web應(yīng)用

GO實(shí)戰(zhàn)訓(xùn)練:如何快速搭建一個(gè)web應(yīng)用

時(shí)間:2023-06-02 02:12:01 | 來(lái)源:網(wǎng)站運(yùn)營(yíng)

時(shí)間:2023-06-02 02:12:01 來(lái)源:網(wǎng)站運(yùn)營(yíng)

GO實(shí)戰(zhàn)訓(xùn)練:如何快速搭建一個(gè)web應(yīng)用:GO實(shí)戰(zhàn)訓(xùn)練:如何快速搭建一個(gè)web應(yīng)用

簡(jiǎn)介

本次訓(xùn)練主要包括的內(nèi)容

1. 創(chuàng)建一個(gè)可以load & save的數(shù)據(jù)結(jié)構(gòu)

2. 學(xué)會(huì)利用 net/http 包去構(gòu)建一個(gè)web應(yīng)用

3. 學(xué)會(huì)利用 html/template 包去處理HTML模板

Go的安裝

具體可以參考 https://golang.org/doc/install

開(kāi)始

mkdir gowikicd gowikitouch wiki.go在wiki.go中,我們先import兩個(gè)基本的包

package mainimport ( "fmt" "io/ioutil")

數(shù)據(jù)結(jié)構(gòu)

讓我們從定義網(wǎng)頁(yè)的數(shù)據(jù)結(jié)構(gòu)開(kāi)始。一個(gè)wiki包括一系列相互連通的網(wǎng)頁(yè)每個(gè)網(wǎng)頁(yè)有title和body(網(wǎng)頁(yè)內(nèi)容)構(gòu)成。在這里,我們定義結(jié)構(gòu)體 Page,包含兩個(gè)成員變量。

type Page struct { Title string Body []byte}[]byte是一個(gè)byte的切片類(lèi)型。那為什么我們要使用切片而不是string 類(lèi)型來(lái)定義body呢?是因?yàn)槲覀兪褂玫膇o包使用的是這個(gè)切片類(lèi)型。

現(xiàn)在,有了這個(gè)Page結(jié)構(gòu)體,我們能夠暫時(shí)將網(wǎng)頁(yè)的內(nèi)容保存在內(nèi)存中了。但是在用戶(hù)對(duì)wiki頁(yè)面進(jìn)行編輯后,怎么將內(nèi)容永久的保存下來(lái)呢?解決這個(gè)問(wèn)題的話,我們需要給Page這個(gè)結(jié)構(gòu)體,定義一個(gè)save的方法

func (p *Page) save() error { filename := p.Title + ".txt" return ioutil.WriteFile(filename, p.Body, 0600)}這個(gè)save的方法,有個(gè)特殊的參數(shù),也叫做receiver,一個(gè)指向Page實(shí)例的指針p,意味著這個(gè)函數(shù)是Page這個(gè)結(jié)構(gòu)體的成員函數(shù),可以直接通過(guò)dot訪問(wèn),比如p.save(),并以error作為返回值。0600是一個(gè)八進(jìn)制的數(shù)字,作為WriteFile的參數(shù),表示創(chuàng)建一個(gè)有讀寫(xiě)權(quán)限的文件。

另外,除了保存頁(yè)面,我們還需要在用戶(hù)對(duì)一個(gè)關(guān)鍵詞進(jìn)行查詢(xún)時(shí),load本地保存好的內(nèi)容到網(wǎng)頁(yè)上進(jìn)行展示。同時(shí)我們還需要將讀取過(guò)程中產(chǎn)生的錯(cuò)誤返回出去,方便調(diào)用這個(gè)函數(shù)的地方對(duì)其進(jìn)行處理。舉個(gè)例子,如果用戶(hù)請(qǐng)求的關(guān)鍵詞不存在的話,我們可能需要將用戶(hù)指引到編輯頁(yè)面上去,讓用戶(hù)創(chuàng)建詞條。

func loadPage(title string) (*Page, error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } return &Page{Title: title, Body: body}, nil}那么到目前為止,我們已經(jīng)能夠在本地加載并且保存相關(guān)的網(wǎng)頁(yè)了,讓我們先完成簡(jiǎn)單的main函數(shù),

func main() { p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")} p1.save() p2, _ := loadPage("TestPage") fmt.Println(string(p2.Body))}簡(jiǎn)單的嘗試運(yùn)行,就可以看到下面的輸出了。

$ go build wiki.go$ ./wikiThis is a sample Page.那么,怎么將我們的代碼變成網(wǎng)站呢?Go的標(biāo)準(zhǔn)庫(kù),net/http 可以很輕松的幫我們做到這一點(diǎn)。

簡(jiǎn)單介紹一下 net/http 這個(gè)包

這里我們簡(jiǎn)單來(lái)介紹一下GO語(yǔ)言中http這個(gè)官方庫(kù),先來(lái)看一個(gè)簡(jiǎn)單的例子,

package mainimport ( "fmt" "log" "net/http")func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])}func main() { http.HandleFunc("/", handler) log.Fatal(http.ListenAndServe(":8080", nil))}main函數(shù)中聲明了http.HandleFunc這一行代碼,告訴httphandler函數(shù)將會(huì)處理web服務(wù)器根目錄下的所有請(qǐng)求。然后main函數(shù)調(diào)用了http.ListenAndServe這個(gè)函數(shù),指明我們將會(huì)一直監(jiān)聽(tīng)8080這個(gè)端口直到程序結(jié)束。

接下來(lái)我們說(shuō)明一下handler這個(gè)函數(shù),我們這里定義的handler函數(shù)其實(shí)是http.HandleFunc的一種,它將http.ResponseWriter以及http.Request作為輸入?yún)?shù)。 http.ResponseWriter會(huì)將HTTP服務(wù)器的回復(fù)組裝在一起,通過(guò)對(duì)它進(jìn)行寫(xiě)數(shù)據(jù),我們可以將服務(wù)器的數(shù)據(jù)發(fā)送給客戶(hù)端。http.Request是保存客戶(hù)端請(qǐng)求的數(shù)據(jù)結(jié)構(gòu),r.URL.Path是請(qǐng)求中的路徑數(shù)據(jù),索引[1:]獲取了/之后的所有字符。接下來(lái)我們直接運(yùn)行代碼,然后在瀏覽器中輸入以下網(wǎng)址,

http://localhost:8080/monkeys,我們可以看到以下的輸出

Hi there, I love monkeys!在初步了解了net/http這個(gè)庫(kù)以后,那么怎么將它和我們的wiki網(wǎng)站制作結(jié)合在一起呢?

net/http來(lái)搭建wiki網(wǎng)站

查看頁(yè)面

首先,我們要import這個(gè)包,

import ( "fmt" "io/ioutil" "net/http")然后我們需要?jiǎng)?chuàng)建一個(gè)handler,viewHandler主要處理用戶(hù)發(fā)來(lái)查看頁(yè)面的請(qǐng)求,這類(lèi)請(qǐng)求的URL會(huì)以/view/為開(kāi)頭。

func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/view/"):] p, _ := loadPage(title) fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)}這里我們暫時(shí)不去處理loadPage可能產(chǎn)生的錯(cuò)誤,之后會(huì)一步一步完善。簡(jiǎn)單講解一下這個(gè)函數(shù)的意思,首先viewHandler會(huì)從path中抽取出/view/之后的字符,然后加載該名字的HTML的內(nèi)容,寫(xiě)到response里面返回給客戶(hù)端。

接下來(lái),我們重寫(xiě)main函數(shù),初始化一個(gè)handler去處理view的請(qǐng)求,為了讓代碼跑起來(lái),我們需要在gowiki的目錄下新建一個(gè)test.txt的文本,并在里面寫(xiě)入任意內(nèi)容,方便加載。然后我們?cè)跒g覽器中輸入http://localhost:8080/view/test,可以再瀏覽器頁(yè)面上看到文本中的內(nèi)容。

func main() { http.HandleFunc("/view/", viewHandler) log.Fatal(http.ListenAndServe(":8080", nil))}

編輯頁(yè)面

一個(gè)完整的wiki網(wǎng)站,除了查看功能以外,我們還需要提供對(duì)已存在頁(yè)面的編輯功能,并且保存該編輯到服務(wù)器,以便之后加載的一個(gè)保存功能。因此,我們需要在main函數(shù)中提供兩個(gè)額外的handler,

func main() { http.HandleFunc("/view/", viewHandler) http.HandleFunc("/edit/", editHandler) http.HandleFunc("/save/", saveHandler) log.Fatal(http.ListenAndServe(":8080", nil))}editHandler函數(shù)提供了編輯功能,如果頁(yè)面不存在的話,我們這里暫時(shí)先返回一個(gè)空頁(yè)面給用戶(hù)。

func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/edit/"):] p, err := loadPage(title) if err != nil { p = &Page{Title: title} } fmt.Fprintf(w, "<h1>Editing %s</h1>"+ "<form action=/"/save/%s/" method=/"POST/">"+ "<textarea name=/"body/">%s</textarea><br>"+ "<input type=/"submit/" value=/"Save/">"+ "</form>", p.Title, p.Title, p.Body)}目前的話,我們的函數(shù)能夠正常工作,但是硬編碼的HTML還是不推薦的,在這里我們介紹一種更好的方式,利用 html/template的包來(lái)優(yōu)化這段代碼,讓我們的代碼看起來(lái)更優(yōu)雅。

簡(jiǎn)單介紹一下 htmp/template

html/template 是GO的一個(gè)標(biāo)準(zhǔn)庫(kù)。我們可以使用這個(gè)包來(lái)將HTML的模板保存在另外的文件中,這樣的話,如果我們要修改頁(yè)面布局的話,可以單純的修改HTML的模板文件,而不用修改GO代碼。

同樣,我們先import這個(gè)包

import ( "html/template" "io/ioutil" "net/http")

edit模板

接下來(lái)我們創(chuàng)建一個(gè)名為edit.html的模板文件,并在文件中添加以下內(nèi)容

<h1>Editing {{.Title}}</h1><form action="/save/{{.Title}}" method="POST"><div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea></div><div><input type="submit" value="Save"></div></form>然后對(duì)應(yīng)修改editHandler的代碼,來(lái)避免硬編碼. template.ParseFiles將會(huì)讀取保存在edit.html中的模板內(nèi)容,然后返回 *template.Template 類(lèi)型的數(shù)據(jù)。然后 t.Execute 將會(huì)執(zhí)行這個(gè)template,并將生成的HTML發(fā)送給http.ResponseWriter, 模板中 .Title.Body 將會(huì)分別持有p中對(duì)應(yīng)的內(nèi)容。

func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/edit/"):] p, err := loadPage(title) if err != nil { p = &Page{Title: title} } t, _ := template.ParseFiles("edit.html") t.Execute(w, p)}

view模板

相應(yīng)的,其實(shí)我們也可以對(duì)view的HTML進(jìn)行一個(gè)模板化處理

<h1>{{.Title}}</h1><p>[<a href="/edit/{{.Title}}">edit</a>]</p><div>{{printf "%s" .Body}}</div>同樣,我們修改viewHandler的代碼

func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/view/"):] p, _ := loadPage(title) t, _ := template.ParseFiles("view.html") t.Execute(w, p)}

使用模板后的代碼優(yōu)化

在使用模板后,其實(shí)viewHandler 以及 editHandler的代碼是由部分重復(fù)代碼的,為了防止”破窗效應(yīng)“,我們將模板這部分代碼抽象出來(lái)

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, _ := template.ParseFiles(tmpl + ".html") t.Execute(w, p)}對(duì)應(yīng)優(yōu)化handler的代碼

func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/edit/"):] p, err := loadPage(title) if err != nil { p = &Page{Title: title} } renderTemplate(w, "edit", p)}

保存頁(yè)面

在用戶(hù)對(duì)頁(yè)面進(jìn)行編輯后,我們需要對(duì)用戶(hù)在edit頁(yè)面提交的form進(jìn)行保存,因此我們實(shí)現(xiàn)以下函數(shù)

func saveHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/save/"):] body := r.FormValue("body") p := &Page{Title: title, Body: []byte(body)} p.save() http.Redirect(w, r, "/view/"+title, http.StatusFound)}這里有一點(diǎn)需要注意的是,r.FormValue返回的值是string,我們需要將它強(qiáng)制轉(zhuǎn)換成[]byte類(lèi)型。




(未完待續(xù))

關(guān)鍵詞:訓(xùn)練,實(shí)戰(zhàn)

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉