一个简单 Go Web MVC 框架实现思路

2018-11-27 15:47 by 掸尘, 阅读, 评论, 收藏, 编辑

 需要的知识点

   为了防止你的心里不适,需要以下知识点:

  • 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 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!")
}


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 编程

版权声明:本文为liuzhang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/liuzhang/p/10026233.html