zoukankan      html  css  js  c++  java
  • 一个简单 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 编程

  • 相关阅读:
    acm课程练习2--1005
    acm课程练习2--1003
    [ZJOI2010]网络扩容
    [ZJOI2009]狼和羊的故事
    [FJOI2007]轮状病毒
    [NOIP2016提高组]换教室
    [NOIP2016提高组]愤怒的小鸟
    [NOIP2009提高组]最优贸易
    [洛谷P2245]星际导航
    [NOIP2013提高组]货车运输
  • 原文地址:https://www.cnblogs.com/liuzhang/p/10026233.html
Copyright © 2011-2022 走看看