一個簡單 Go Web MVC 框架實現思路


 需要的知識點

   為了防止你的心里不適,需要以下知識點:

  • Go 基本知識
  • Go 反射的深入理解
  • 使用過框架

 Go Web 服務器搭建

package main

import (
    "fmt"
    "net/http"
)

func do(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!") //這個寫入到w的是輸出到客戶端的
}

func main() {
    http.HandleFunc("/", do) //設置訪問的路由
    http.ListenAndServe(":9090", nil) //設置監聽的端口
}

 上面的例子調用了http默認的DefaultServeMux來添加路由,需要提供兩個參數,第一個參數是希望用戶訪問此資源的URL路徑(保存在r.URL.Path),第二參數是即將要執行的函數,以提供用戶訪問的資源。

 Go默認的路由添加是通過函數http.Handlehttp.HandleFunc等來添加,底層都是調用了DefaultServeMux.Handle(pattern string, handler Handler),這個函數會把路由信息存儲在一個map信息中map[string]muxEntry。

 Go監聽端口,然后接收到tcp連接會扔給Handler來處理,上面的例子默認nil即為http.DefaultServeMux,通過DefaultServeMux.ServeHTTP函數來進行調度,遍歷之前存儲的map路由信息,和用戶訪問的URL進行匹配,以查詢對應注冊的處理函數。

 你可以通過文檔查看 http.ListenAndServe 的方法,第二個參數是 Handler 類型的接口,只要實現 Handler 接口,就可以實現自定義路由。

func ListenAndServe(addr string, handler Handler) error

 實現自定義路由:

package main

import (
    "fmt"
    "net/http"
)

type MyMux struct {
}

func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/" {
        sayhelloName(w, r)
        return
    }
    http.NotFound(w, r)
    return
}

func sayhelloName(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello myroute!")
}

func main() {
    mux := &MyMux{}
    http.ListenAndServe(":9090", mux)
}

  通過自定義路由,實現簡單 MVC 框架

 兩個基本結構的定義:

type controllerInfo struct {
    url         string
    controllerType reflect.Type
}

type ControllerRegistor struct {
    routers     []*controllerInfo
}

整體思路:

  •   controllerInfo url 是添加時候對應的路由, controllerType 反射類型。 
  •   通過 mux.Add("/", &DefaultController{}) 前台添加的信息,放到一個 routers []*controllerInfo 數組中
  •   每一次請求都會遍歷 routes, 判斷當前的   r.URL.Path 是否與 routes 里面一個相等,如果相等, 通過類型反射,執行相應的方法。

流程圖:

 源碼實現

package main

import (
    "fmt"
    "net/http"
    "reflect"
)

type controllerInfo struct { url string controllerType reflect.Type } type ControllerRegistor struct { routers []*controllerInfo } type ControllerInterface interface { Do() } type UserController struct { } type DefaultController struct { } func (u *UserController) Do() { fmt.Println("I`m UserController") } func (d *DefaultController) Do() { fmt.Println("I`m DefaultController") } func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) { //now create the Route t := reflect.TypeOf(c).Elem() route := &controllerInfo{} route.url = pattern route.controllerType = t p.routers = append(p.routers, route) } // AutoRoute func (p *ControllerRegistor) ServeHTTP(w http.ResponseWriter, r *http.Request) { var started bool requestPath := r.URL.Path fmt.Println(requestPath) //find a matching Route for _, route := range p.routers { if requestPath == route.url { vc := reflect.New(route.controllerType) method := vc.MethodByName("Do") method.Call(nil) started = true fmt.Fprintf(w, "Hello " + route.controllerType.Name()) break } } //if no matches to url, throw a not found exception if started == false { http.NotFound(w, r) } } func main() { mux := &ControllerRegistor{} mux.Add("/", &DefaultController{}) mux.Add("/user", &UserController{}) s := &http.Server{ Addr: ":9527", Handler: mux, } s.ListenAndServe() }

 以上只是一個簡陋的實現思路,可以優化加上具體的功能和通過參數調用方法等。

 參考鏈接:

 Go Web 編程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM