前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初学gin

初学gin

作者头像
是小张啊喂
发布2021-08-09 17:40:47
6820
发布2021-08-09 17:40:47
举报
文章被收录于专栏:软件软件

已经放弃goframe框架,对待新手不是很友好,社区圈子也很小。因为我自身的话是没有go语言的编程基础的,所以导致了我看不太懂那个框架,不过看很多人都说goframe封装的很好,有人吐槽有人夸,开源的框架嘛,这些都是在所难免的。

放弃goframe不代表放弃go,当前go语言还是很强的,查了一下相关的资料,大部分都推荐gin框架开始学习,抱着怀疑入坑的心态,有一次开始了学习。

自己百度找到了一个中文文档,看起来还可以,http://www.topgoer.com/gin%E6%A1%86%E6%9E%B6/,废话不多说直接上手体验一下

gin路由

首先构建一下依赖

代码语言:javascript
复制
require github.com/gin-gonic/gin v1.6.3

基本路由

代码语言:javascript
复制
func main() {
    r := gin.Default()
    r.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "hello word")
    })
    r.POST("/xxxpost",getting)
    r.PUT("/xxxput")
    //监听端口默认为8080
    r.Run(":8000")
}

从这个官方的示例中,能看出下面几个问题:

  1. r直接支持请求方式的定义
  2. 支持自定义端口

也很简洁,我觉得相对于我之前学习的框架,这个确实要好理解很多

gin还支持Restful风格的API,参照java来说,那就好理解很多

API参数

代码语言:javascript
复制
func main() {
    r := gin.Default()
    r.GET("/user/:name/*action", func(c *gin.Context) {
        name := c.Param("name")
        action := c.Param("action")
        //截取/
        action = strings.Trim(action, "/")
        c.String(http.StatusOK, name+" is "+action)
    })
    //默认为监听8080端口
    r.Run(":8000")
}

如果我们直接访问

http://127.0.0.1:8000/user/ShaoJie/learning 页面上会输出ShaoJie is learning

gin可以直接获取API中的参数,这个还挺好理解的,Java里面的话,有点类似@PathVariable()注解,很强哈,这边还注意到,gin截取string类型所用的方法,strings.Trim()

URl参数

代码语言:javascript
复制
func main() {
    r := gin.Default()
    r.GET("/user", func(c *gin.Context) {
        //指定默认值
        //http://localhost:8080/user 才会打印出来默认的值
        name := c.DefaultQuery("name", "ShaoJie")
        c.String(http.StatusOK, fmt.Sprintf("hello %s", name))
    })
    r.Run()
}

访问 http://127.0.0.1:8000/user 页面上会输出hello ShaoJie 或者

访问 http://127.0.0.1:8080/user?name=Shao-Jie 页面上是 hello Shao-Jie

那也就是说,这里是有一个默认的取值的,如果没有接收到参数的话,这里直接输出定义的默认值

表单传参

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/form" method="post" action="application/x-www-form-urlencoded">
        用户名:<input type="text" name="username" placeholder="请输入你的用户名">  <br>
        密&nbsp;&nbsp;&nbsp;码:<input type="password" name="userpassword" placeholder="请输入你的密码">  <br>
        <input type="submit" value="提交">
    </form>
</body>
</html>
代码语言:javascript
复制
func main() {
    r := gin.Default()
    r.POST("/form", func(c *gin.Context) {
        types := c.DefaultPostForm("type", "post")
        username := c.PostForm("username")
        password := c.PostForm("userpassword")
        // c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s,type:%s", username, password, types))
        c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s,type:%s", username, password, types))
    })
    r.Run()
}

表单参数可以通过PostForm()方法获取 该方法默认解析的是x-www-form-urlencodedfrom-data格式的参数 ,这个例子其实很简单,我本来想直接用模板,但是看到这里,我好像还不太好实现这个问题,菜是原罪

routes group

代码语言:javascript
复制
func main() {
   // 1.创建路由
   // 默认使用了2个中间件Logger(), Recovery()
   r := gin.Default()
   // 路由组1 ,处理GET请求
   v1 := r.Group("/v1")
   // {} 是书写规范
   {
      v1.GET("/login", login)
      v1.GET("submit", submit)
   }
   v2 := r.Group("/v2")
   {
      v2.POST("/login", login)
      v2.POST("/submit", submit)
   }
   r.Run(":8000")
}

这个可以对比goframe,相比较而言,我更喜欢现在这种(小声逼逼:那个框架差点给我心态整蹦了,初学者勿入坑)

路由拆分与注册

基本的路由注册

上面将路由写在一个main中都属于基本的路由注册

路由拆分成单独文件或包

将路由拆分,相当于在启动的时候加载这个函数

routers/routers.go

代码语言:javascript
复制
func helloHandler(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
        "message": "Hello www.topgoer.com!",
    })
}

func SetupRouter() *gin.Engine {
    r := gin.Default()
    r.GET("/topgoer", helloHandler)
    return r
}

main.go

代码语言:javascript
复制
func main() {
    r := routers.SetupRouter()
    if err := r.Run(); err != nil {
        fmt.Println("startup service failed, err:%v\n", err)
    }
}

这个涉及到go的一个小知识点,那就是方法名称大小写的问题

1、 首字母小写,代表只对当前包内文件可见 类似java中的protected

2、 首字母大写,代表只对所有文件可见 类似java中的private

路由拆分成多个文件

routers/blog.go

代码语言:javascript
复制
func LoadShop(e *gin.Engine)  {   e.GET("/helloblog", helloHandler)}

routers/shop.go

代码语言:javascript
复制
func LoadBlog(e *gin.Engine)  {   e.GET("/helloshop", helloHandler)}

main.go

代码语言:javascript
复制
func main() {
	r := gin.Default()
	routers.LoadBlog(r)
	routers.LoadShop(r)
	if err := r.Run(); err != nil {
		fmt.Println("startup service failed, err:%v\n", err)
	}
}

路由拆分到不同的APP

blog.goshop.go移动到app/blogapp/shop中,修改 routers/routers.go

代码语言:javascript
复制
// 注册app的路由配置
func Include(opts ...Option) {
    options = append(options, opts...)
}

// 初始化
func Init() *gin.Engine {
    r := gin.New()
    for _, opt := range options {
        opt(r)
    }
    return r
}

main.go

代码语言:javascript
复制
func main() {
    // 加载多个APP的路由配置
    routers.Include(shop.Routers, blog.Routers)
    // 初始化路由
    r := routers.Init()
    if err := r.Run(); err != nil {
        fmt.Println("startup service failed, err:%v\n", err)
    }
}

gin数据解析和绑定

Json数据解析和绑定

文档示例

代码语言:javascript
复制
// 定义接收数据的结构体
type Login struct {
   // binding:"required"修饰的字段,若接收为空值,则报错,是必须字段
   User    string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
   Pssword string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
}

func main() {
   // 1.创建路由
   // 默认使用了2个中间件Logger(), Recovery()
   r := gin.Default()
   // JSON绑定
   r.POST("loginJSON", func(c *gin.Context) {
      // 声明接收的变量
      var json Login
      // 将request的body中的数据,自动按照json格式解析到结构体
      if err := c.ShouldBindJSON(&json); err != nil {
         // 返回错误信息
         // gin.H封装了生成json数据的工具
         c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
         return
      }
      // 判断用户名密码是否正确
      if json.User != "root" || json.Pssword != "admin" {
         c.JSON(http.StatusBadRequest, gin.H{"status": "304"})
         return
      }
      c.JSON(http.StatusOK, gin.H{"status": "200"})
   })
   r.Run(":8000")
}

Postman测试一下 地址:http://127.0.0.1:8000/loginJSON Post请求

代码语言:javascript
复制
{
    "user":"root",
    "password":"admin"
}

表单的数据解析和绑定

文档示例

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8000/loginForm" method="post" enctype="application/x-www-form-urlencoded">
        用户名<input type="text" name="username"><br>
        密码<input type="password" name="password">
        <input type="submit" value="提交">
    </form>
</body>
</html>
代码语言:javascript
复制
// 定义接收数据的结构体
type Login struct {
    // binding:"required"修饰的字段,若接收为空值,则报错,是必须字段
    User    string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
    Pssword string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
}

func main() {
    // 1.创建路由
    // 默认使用了2个中间件Logger(), Recovery()
    r := gin.Default()
    // JSON绑定
    r.POST("/loginForm", func(c *gin.Context) {
        // 声明接收的变量
        var form Login
        // Bind()默认解析并绑定form格式
        // 根据请求头中content-type自动推断
        if err := c.Bind(&form); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        // 判断用户名密码是否正确
        if form.User != "root" || form.Pssword != "admin" {
            c.JSON(http.StatusBadRequest, gin.H{"status": "304"})
            return
        }
        c.JSON(http.StatusOK, gin.H{"status": "200"})
    })
    r.Run(":8000")
}

URl数据解析和绑定

文档示例

代码语言:javascript
复制
// 定义接收数据的结构体
type Login struct {
    // binding:"required"修饰的字段,若接收为空值,则报错,是必须字段
    User    string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
    Pssword string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
}

func main() {
    // 1.创建路由
    // 默认使用了2个中间件Logger(), Recovery()
    r := gin.Default()
    // JSON绑定
    r.GET("/:user/:password", func(c *gin.Context) {
        // 声明接收的变量
        var login Login
        // Bind()默认解析并绑定form格式
        // 根据请求头中content-type自动推断
        if err := c.ShouldBindUri(&login); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        // 判断用户名密码是否正确
        if login.User != "root" || login.Pssword != "admin" {
            c.JSON(http.StatusBadRequest, gin.H{"status": "304"})
            return
        }
        c.JSON(http.StatusOK, gin.H{"status": "200"})
    })
    r.Run(":8000")
}

总结一下这三种解析和绑定

  1. json解析和绑定对应了body传参
  2. 表单解析对应了我们一般的表单请求,一般在html里面会更多一点,现在大部分前端都是vue了,所以有些东西自然而然的会慢慢忘记
  3. URL解析对应了Restful API请求

那更新这一期的话,很明显能看出来,其实gin还是很简单的,基本上现在就可以写一点接口了,后面的话就不多叙述了,直接进入到这个深入学习了。

学习是一个漫长且煎熬的过程,但是我们还能在其中寻找乐趣的话,那肯定非常有意思。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-10-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • gin路由
    • 基本路由
      • API参数
        • URl参数
          • 表单传参
            • routes group
              • 路由拆分与注册
                • 基本的路由注册
                • 路由拆分成单独文件或包
                • 路由拆分成多个文件
                • 路由拆分到不同的APP
            • gin数据解析和绑定
              • Json数据解析和绑定
                • 表单的数据解析和绑定
                  • URl数据解析和绑定
                  相关产品与服务
                  消息队列 TDMQ
                  消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档