使用Golang+Mongodb打造你的第一個網站

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

 

很多人推薦MEAN來開發網站。MEAN就是M:mongodb,E:expressjs、A:angular最後的N:nodejs。 但是如果你親身的體會到了js的嵌套回調的話你就會想換換別的辦法了。雖然說可以用promise等架構 破解深深的嵌套,但畢竟不是語言本身支援的。

為什麼說用Golang呢?因為Golang是一個有著動態語言的特點的靜態語言。文法簡單,文法糖就是盡量減少文法。 編譯的時候就可以把錯誤排查掉很多。不用像動態語言那樣啟動並執行時候才掉進坑裡。

在Golang眾多的Web架構中發現了Martini。 他後來覺得這個架構用了太多反射影響了效率,就有寫了另一個架構或者按照作者的說法“中介軟體”, 叫做Negroni。具體的開發原因看這裡。 可能是這個作者愛喝酒把他寫的架構都叫了個酒水的名字。Margini這個架構是作者受了Expressjs的啟發寫出來的。 所以在很多使用上的東西非常類似,比如route的綁定文法,支援類中介軟體的綁定文法等。也看過Golang的其他架構比如Revel, 有很多的酷炫的功能,和一站式的很多的支援,但是因為Martini的靈活決定選用Margini。

資料庫MongoDB

資料庫方面,對於事物和資料的一致性要求沒有那麼強的話,還是選用比較簡單的NoSQL資料庫比較合適。所以,就用MongoDB了。 也許在嚴謹的工作中不應該這麼用。但是MongoDB可以簡單到,只要把Http POST過來的json資料直接寫入資料庫中。 如果json比較簡單的話,完全不用做什麼設計!當然,實際工作的時候是不可以這樣的。我們討論的只是這樣的一個可行性。

那麼我們就開始用Martini(golang)和MongoDB來打造一個web APP。這個app的名稱就叫做navigator(領航者)。 是用來接受、儲存和分析使用者反饋以及使用者的各種問題的,比如各種客戶回函回來的使用者問題。這些問題的上下文資訊十分有限。 所以我們讓使用者通過手機用戶端來調用navigator的介面來同時提交相關的上下文資訊。 關於Golang的一些基礎的東西就不在這裡探討了。 go get擷取Martini,下載MongoDB。之後使用命令run起來MongoDB。給DB起一個名字:NDB。然後在裡面填充一個document。 MongoDB如果沒有insert一個Document的話,那麼這個資料庫其實是沒有建立的。這個Document就是一個Json。格式為:

{"feedbackcode" : "123","username" : "","phonenum" : "","deviceinfo" : {"systemtype" : "","systemver" : "","appver" : ""},"imagelist" : [ ],"desc" : "testing","feedbacktype" : "","other" : ""}

 

使用feedbackCode來標示一個唯一的feedback。資料庫的問題就徹底解決了。

網站的目錄結構

下面開始我們的網站部分。首先瞭解一下目錄結構:

navigator
|———conf
|-————–Conf.go # 配置資訊
|—————–ConfigError.go # 錯誤名稱
|———controllers
|—————–FeedbackController.go
|—————–IndexController.go
|–––models
|––––––FeedbackModel.go
server.go

這個目錄結構式典型的REST API的MVC模式體現。我們這裡不需要處理View,也就是Html的東西。但是, 還是顯示的區分了Model和Controller。view其實還是有的,只不過是最後render後的json。

RUN起來

首先,讓我們的web app跑起來。 給server.go添加如下的代碼:

package mainimport "github.com/go-martini/martini"func main() {  m := martini.Classic()  m.Get("/", func() string {    return "Hello world!"  })  m.Run()}

go run server.go命令就可以讓這個web app運行起來了。預設的是運行在3000連接埠上的。 在頁面上也只能看到光禿禿的幾個字Hello world! martini.Classic()調用之後,Martini會為你預設提供一些工具。其中最重要的一個就是路由。 在這之後就可以使用m.Get("/", func()string{return "Hello, world!"}來指定什麼路徑映射到什麼處理方法上。 最後調用m.Run()方法在3000連接埠上運行整個app。

現在開始要真正的開發這個app了。首先我們需要有一個簡單的需求分析,我們到底是要做什麼。 如前所述,使用者可以用這個API發送feedback上來,然後在另外一個介面裡把這些內容以列表的形式展示出來。 需求就是這麼簡單。我們下面來一步一步實現這些功能。

Controllers

由於insert一個feedback,需要的資訊量還是很大的。我們用POST得方法發送所需要的feedback資料。 所以,我們需要一個POST的路徑和處理函數Handler(以後都叫做Handler)。

m.Post("/", func(req *http.Request) string{    // 從req中取出參數,插入到資料庫})

現實feedback的列表的介面只需要響應一個GET請求。所以是一個GET的路徑和Handler。 看起來應該是這樣的:

m.Get("/", func() string {// 假設最後的字典會被轉換成Json串return []map[string]string{map[string]string{"feedbackcode": "1", "username": "John"},    map[string]string{"feedbackcode": "2", "username": "Tony"}}}

以上列出的Handler都是對於API添加資料和資料列表的一些類比。下面開始開始正式寫Controller。

列表Controller

先看代碼,然後再來詳細說明:

package controllersimport (// "fmt""fmt""github.com/martini-contrib/render""navigator/conf""navigator/models""net/http")type FeedbackController struct {}func (c *FeedbackController) FeedbackList(req *http.Request, r render.Render) {f := new(models.FeedbackModel)r.JSON(200, map[string]interface{}{"data": f.ModelList(nil)})}

引入github.com/martini-contrib/renderrender是一個渲染的包。 如果有html的視圖的話,可以把資料轉換成html模板可用的資料。我們這裡用這個包來把字典轉換成json資料。 r.JSON(200, map[string]interface{}{"data": f.ModelList(nil)})中200,是狀態代碼。 需要轉換的字典是一個string為key,Model列表為值的字典。

這裡可以先瞭解一部分feedback的Model類:

type DeviceInfo struct {SystemType string `json: "systemType"`    // ios or androidSystemVer  string `json: "systemVersion"` // system version eg, ios 9.1AppVer     string `json: "appVersion"`    // app version eg, 2.9.0}type FeedbackModel struct {FeedbackCode string     `json: "feedbackCode"`UserName     string     `json: "userName"`PhoneNum     string     `json: "phoneNum"`DeviceInfo   DeviceInfo `json: "deviceInfo"`ImageList    []string   `json: "imageList"`Desc         string     `json: "description"`FeedbackType string     `json: "feedbackType"` // normal feedback or a problem in useOther        string     `json: "other"`        // other infomation}

在最開始的json資料定義,在Golang的Model類定義中可以定義為上面的代碼。 用"``"標示出來的,是在Model轉換為json字串的過程中Model欄位和json串的key值得對應關係。 最後Controller的功能是需要處理請求過來的資料的, 也就是Controller的方法會作為Get或者Post的Handler的。這兩者之間需要關聯起來:

package main import (    // other packages    "navigator/controllers")func main() {    var m = martini.Classic()    var r = martini.NewRouter()        feedbackController := new(controllers.FeedbackController)        r.Get("/nav/feedback", feedbackController.FeedbackList)    r.Post("/nav/feedback", feedbackController.Feedback)    m.Action(r.Handle)        m.RunOnAddr(":9090")}

這裡r.Get("/nav/feedback", feedbackController.FeedbackList),修改了之前的訪問路徑。/nav/feedback是在路徑上加了一個項目的名稱簡寫作為限定。因為直接叫做feedback有可能會和其他的同名介面混了。 也就是介面的汙染。所以加一個項目名稱來避免這個問題。feedbackController := new(controllers.FeedbackController)初始化FeedbackController。 把feedbackController的方法FeedbackList和訪問的路徑綁定到一起。 GET的Http訪問和FeedbackList方法綁定,POST的Http訪問和Feedback方法綁定。 最後m.RunOnAddr(":9090")代替了之前使用的m.Run()。之前app是運行在3000連接埠上的。 現在通過m.RunOnAddr(":9090")則app將運行在9090連接埠上。也就是可以用這一語句來制定app的運行連接埠。

Models和MongoDB

處理MongoDB我們用mgo這個庫。Golang雖然這麼多年了已經。還出了這麼多的明星產品。 但是,處理MongoDB的成熟的庫還是可以說沒有。完全沒有想python、nodejs等語言的庫那麼豐富。 有標準的,還有很多github上的其他開發人員開發的庫。Golang裡也就是mgo相對來說這個庫比較可用的了。

當POST請求的feedback的json字串傳上來的時候,會被轉換為一個FeedbackModel的對象。 Golang的json庫會協助我們做到這一點。 json.Unmarshal([]byte(dict), &f)這裡的Unmarshal方法會把一個json字串轉化為FeedbackModel對象。 這裡需要用到一個Factory 方法。產生一個Model對象,並且這個對象應該是一個富Model對象。 後面這個Model對象將具有可以操作操作資料庫,增、刪、改、查的方法。代碼:

func NewFeedbackModel(dict string) *FeedbackModel {    var f FeedbackModel    err := json.Unmarshal([]byte(dict), &f)    if err != nil {        return nil    }    return &f}

以上代碼會用到庫"encoding/json"。當收到feedback的json串的時候就用這個方法將其轉換為FeedbackModel對象。 上文說過,會給這個Model增加資料庫操作的方法。那麼我們就可以通過json串得到的Model來執行資料的操作。 代碼:

func (m *FeedbackModel) ModelList(conditions map[string]string) []FeedbackModel {    confInstance := conf.ConfigInstance()    mgoUri := conf.ConfigInstance().MongoDBConnectionString()    // var f FeedbackModel    session, err := mgo.Dial(mgoUri)    if err != nil {        fmt.Printf("can not connect to server %v\n", err)        panic(err)    }    defer session.Close()    var feedbackModelList []FeedbackModel    collection := session.DB(confInstance.DBName).C("feedback")    err = collection.Find(conditions).All(&feedbackModelList)    return feedbackModelList}func (m *FeedbackModel) GetModel(modelId string) (*FeedbackModel, error) {    //此處省略一部分代碼    collection := session.DB(confInstance.DBName).C("feedback")    err = collection.Find(bson.M{"feedbackcode": modelId}).One(&f)        return &f, nil}func (m *FeedbackModel) InsertModel(model *FeedbackModel) error {    //此處省略一部分代碼    f := session.DB(confInstance.DBName).C("feedback")    err = f.Insert(model)    return err}

這裡需要稍微的提到一部分MongoDB的知識。在MongoDB中,庫還是庫,但是表不叫做表,叫做Collection。 關鍵字不翻譯。翻譯出來的看著太爛,還不能清楚表達意思。每一條記錄也不叫記錄,叫做Document。 一個Document的大小不能超過2M。

在MongoDB裡尋找是這樣的:

db.feedback.find({"feedbackCode": "1"}) //尋找條件就是{"feedbackCode":"1"}) //尋找條件就是

如果在find裡什麼都不寫,那麼就是無條件的全部尋找。插入是這樣的:

db.feedback.insert({"feedbackCode": "2"})

Golang的mgo當然在具體操作資料庫方面和MongoDB本身是不會差太多了,除了這是Go文法的封裝。

collection := session.DB(confInstance.DBName).C("feedback")

這樣就得到了一個Collection。尋找、插入、修改等動作都是在Collection上執行的。所以,尋找就是這樣的:

collection.Find(conditions).All(&feedbackModelList)

尋找到的列表會存放在一個事先聲明好的feedback的Model列表裡。尋找一個可以這樣:

collection.Find(bson.M{"feedbackcode": modelId}).One(&f)

插入:

collection.Insert(model)

insert的時候,這個model需要是指標類型的,也就是:var model *FeedbackModel

到這裡就可以把整個的feedback從請求到返回的過程都串聯起來了。

全部串聯起來

在整個的app入口處。請求的路徑和具體的Controller處理函數綁定在了一起。每一個請求來了之後 ,如果路徑和綁定的路徑是對應好了的。就會被發送給Controller的某個綁定好的函數裡處理。

這個負責處理http請求的Controller方法會把http請求發送上來的json字串發送給Model模組處理。 Model模組會把json字串轉換為一個Model執行個體。這個Model是一個富Model, 可以調用其函數把Model本身的資料插入到Mongo資料庫中,當然也可以從資料庫中查詢這些資料。

到這裡

到這裡你已經熟悉了如何用Martini這個Golang架構開發一個簡單地網站,好吧,其實是一個REST Api。 使用我們文中提到的Render架構,你可以非常非常容易的把Model資料轉換之後並顯示在html的template中。 而且你已經熟悉了MongoDB資料庫。一個非常簡單易用的資料庫。無論你是要開發一個REST Api還是要開發一個html的網站。 需要儲存的東西都可以存如MongoDB資料庫中。到這裡你已經可以順利的繼續下面的功能的開發了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.