@TOC


前言

云时代已经逐渐到来,在工作中学习中,我们时不时会用到Go语言,那就开始学起吧,与诸君共勉。

Go(lang)提供了很好的net/http库,基于此再造框架比较简单快速,Go中常用的三个web框架【go所有的安装都是使用go get安装(类似于git-clone)】

Gin

  • 一个Gin框架的请求处理代码块固定格式:请求,处理请求的回调函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package main

    import (
    "github.com/gin-gonic/gin"
    "github.com/thinkerou/favicon"
    "net/http"
    )

    func main() {
    //创建一个gin服务,结合访问地址+端口处理咱们的请求与响应
    ginServer := gin.Default()

    ginServer.GET("/user/info", func(context *gin.Context){
    ...
    })

    }
  • 通过几行代码就可以启动一个服务
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package main

    import "github.com/gin-gonic/gin"

    func main() {
    //创建一个gin服务,结合访问地址+端口处理咱们的请求与响应
    ginServer := gin.Default()

    /**
    * 模拟一个get请求,给浏览器发送一个请求,相当于给浏览器打个招呼
    * context 代表请求的上下文对象
    */
    ginServer.GET("/myfirstgodemo", func(context *gin.Context) {
    context.JSON(200, gin.H{"MSH": "IM HHB"})
    })

    //指定服务器运行端口
    ginServer.Run(":8082")
    }

  • 新建项目后,尽量在项目中先建一个go.mod用来管理咱们的包结构【因为项目中可能包很多】,跟maven差不多
    • import导入时如果报错,去settings中的GO MUDULE配置GOPROXY=”…这里的内容去命令提示符中,输入go env,复制键值对的GOPROXY的值”,然后确定即可
    • 检查三个地方
  • GIN框架经验总结:指定服务器端口时端口前面没有加冒号,导致报错ginServer.Run(“:8082”)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    func main() {
    //创建一个gin服务,结合访问地址+端口处理咱们的请求与响应
    ginServer := gin.Default()

    /**
    * 模拟一个get请求,给浏览器发送一个请求,相当于给浏览器打个招呼
    * context 代表请求的上下文对象
    */
    ginServer.GET("/hell", func(context *gin.Context) {
    context.JSON(200, gin.H{"MSH": "IM HHB"})
    })

    //指定服务器运行端口
    ginServer.Run(":8082")
    }

给前端页面标题栏指定照片:

你得先找一个.ico或者照片啥的,放到你的项目中,这不就是前端项目的常用手段嘛。ginServer.Use(favicon.New(“./cartonPhone.jpg”))。然后就得go get “github.com/thinkerou/favicon”下载,然后再import “github.com/thinkerou/favicon”导入这个包,favicon.New这个函数才能用

restful api(GIN支持)

  • 以前写路由地址相关代码:get /user post /create_user post /update_user post /delete_user,不同的请求要对应不同的路由地址,通过URL和请求来进行请求隔离。编写起来很麻烦,没有统一的那个感觉;
    • 而用了RESTful API之后,get /user post /user put /user delete /user,通过不同的请求来执行不同的功能,通过不同的请求方式来隔离,不用频繁修改路由地址
    • 项目中集成不同的请求:GET、POST、DELETE、PUT
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      package main

      import (
      "github.com/gin-gonic/gin"
      "github.com/thinkerou/favicon"
      )

      func main() {
      //创建一个gin服务,结合访问地址+端口处理咱们的请求与响应
      ginServer := gin.Default()
      /**
      * 模拟一个get请求,给浏览器发送一个请求,相当于给浏览器打个招呼
      * context 代表请求的上下文对象
      */
      ginServer.GET("/my first go demo", func(context *gin.Context) {
      context.JSON(200, gin.H{"Min": "I fall in love with you "})
      })
      ginServer.POST("user", func(context *gin.Context) {
      context.JSON(200, gin.H{"msg:": "post type"})
      })
      ginServer.PUT("/user")
      ginServer.DELETE("/user")

      //指定服务器运行端口
      ginServer.Run(":8888")
      }

  • 可以用postman测试post请求的结果

咱们写好的前端动态静态页面,现在就可以试着用go调用呼应了

  • 加载静态页面:【有全局的和单个html页面,你单个的要一个文件一个文件写出来,太多了。全局的好用一点】ginServer.LoadHTMLGlob(“templates/*”)
  • 返回或者响应:
    • 返回JSON数据:咱们ginServer.GET(…)回调函数中写的是context.JSON…
    • 返回HTML页面:那就是ginServer.GET(…)回调函数中写的是context.HTML…
      • 当然,templates中的*.html文件、static中的*.js、*.css文件都可以响应

获取请求中的参数

  • 传统的url中用?拼接的分数:url?userid=xxx&username=hhb…
  • RESTful风格的请求参数:/usr/info/1/hhb

重定向、路由组等就是context.xxx

自定义go中间件:拦截器

  • 浏览器前端发了一个请求,比如/user/delete,这个请求到后端来处理,此时,此时就可以加一个拦截器进行预处理【登陆授权、验证、分页、各种特征信息统计】
    • step1:先定义一个中间件或者叫中间逻辑func myHandlerDemo() gin.HandlerFunc {…}
    • step2:注册中间件或者中间逻辑:在main函数中ginServer := gin.Default() ginServer.Use(myHandlerDemo())
    • step3:在响应的地方调用ginServer.GET(“/…访问路由”, myHandlerDemo(), func(context *gin.Context){…}…)
      • 你在某个ginServer.GET(“/…访问路由”,中使用myHandlerDemo()就是说明给某一个请求使用,要是光注册进来没给具体的哪个ginServer.GET(“/…访问路由”,中放myHandlerDemo(),说明是全局使用这个myHandlerDemo()
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        package main

        import (
        "encoding/json"
        "github.com/gin-gonic/gin"
        "github.com/thinkerou/favicon"
        "net/http"
        )

        //自定义go中间件 拦截器
        func myHandlerDemo() gin.HandlerFunc {
        return func(context *gin.Context) {
        //通过自定义的中间件,设置的值,在后续处理只要调用了这个中间件的都可以拿到这里的参数
        context.Set("usersession", "userid-1")

        /**
        * 加个if判断
        * if xxx.xxx{
        * context.Next() //放行
        * }
        * context.Abort() //阻止通过
        */
        }
        }

        func main() {
        //创建一个gin服务,结合访问地址+端口处理咱们的请求与响应
        ginServer := gin.Default()
        ginServer.Use(favicon.New("./cartonPhone.jpg"))

        //呼应前端玩法一:在这里就可以加载前端的静态页面
        ginServer.LoadHTMLGlob("templates/*")
        //呼应前端玩法三:加载资源文件
        ginServer.Static("/static", "./static")

        /**
        * 模拟一个get请求,给浏览器发送一个请求,相当于给浏览器打个招呼
        * context 代表请求的上下文对象
        */
        ginServer.GET("/my first go demo", func(context *gin.Context) {
        context.JSON(200, gin.H{"Min": "I fall in love with you "})
        })

        //呼应前端玩法二:呼应或者叫返回一个页面给前端。跟返回JSON一样,无非就是回调函数context.点的东西不一样而已
        ginServer.GET("/staticView", func(context *gin.Context) {
        context.HTML(http.StatusOK, "index.html", gin.H{
        "msg": "minmin,i fall in love with you minmin in static view",
        })
        })

        //接收前段传递过来的参数,比如例子:url?userid=xxx&username=hhb
        ginServer.GET("/learnParam", func(context *gin.Context) {
        userid := context.Query("userid")
        username := context.Query("username")
        context.JSON(http.StatusOK, gin.H{
        "userid": userid,
        "username": username,
        })
        })

        //接收前段传递过来的RESTful风格的参数,比如例子:url?userid=xxx&username=hhb
        ginServer.GET("/learnRestfulApi/:userid/:username", func(context *gin.Context) {
        userid := context.Param("userid")
        username := context.Param("username")
        context.JSON(http.StatusOK, gin.H{
        "userid": userid,
        "username": username,
        })
        })

        //前端传JSON格式的数据到后端
        ginServer.POST("/sendJsonData", func(context *gin.Context) {
        //从请求体中获取数据
        b, _ := context.GetRawData()

        var m map[string]interface{}
        //通过json序列化包装为json数据 []byte
        _ = json.Unmarshal(b, &m)
        context.JSON(http.StatusOK, m)
        })

        ginServer.POST("/learnForm/demo", func(context *gin.Context) {
        username := context.PostForm("username")
        password := context.PostForm("password")
        context.JSON(http.StatusOK, gin.H{
        "msg": "ok",
        "username": username,
        "password": password,
        })

        })
        //指定服务器运行端口
        ginServer.Run(":8888")
        }

Beego:快速开发go应用,提供了很多现成的组件

Iris

  • 最快的Go语言Web框架,支持MVC三层架构

Go语言ORM库:xorm,使得数据库操作非常简便

  • sqlx这个包就可以连接数据库
  • 官网:https://xorm.io/
  • 同步结构体到数据库:https://gitea.com/xorm/xorm/src/branch/master/README_CN.md#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B
    • java中是实体中的成员变量或者叫成员属性对应数据库中字段,而go中用的是结构体,结构体中的属性对应数据库中的字段属性,而且你想要增加或者减少数据库中字段时直接在结构体中增加减少字段,然后err = engine.Sync(new(User)),然后执行代码即可
    • 注意,确定有可能出现err的地方可以加if判断
  • CRUD:https://gitea.com/xorm/xorm/src/branch/master/README_CN.md#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B
    • engine.Insert(&user) //像这种engine.Insert(user)只填入这个对象也行。但是有时候这个CRUD方法有时候会给这个对象回填一些信息啥的,这时候要保证CRUD里面用的user和外面的user是同一个,所以用指针对象去保证是同一个对象
    • engine.UPDATE:更新数据,默认只更新非空和非0的字段
    • engine.DELETE:删除记录,删除必须至少有一个条件,否则会报错
    • engine.Exec:执行一个SQL语句
  • 数据查询:
    • Query:最原始的支持SQL查询,返回类型为[]map[string][]byte
    • QueryString返回[]map[string]string
    • QueryInterface返回[]map[string]interface{}
    • Get查询单条记录
    • Find查询多条记录
    • Count获取记录条数
    • Iterate和Rows根据条件遍历数据

Go的经典应用:gRPC


巨人的肩膀