前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Gin简单明了的教程---上

Gin简单明了的教程---上

作者头像
大忽悠爱学习
发布2022-08-23 10:07:47
2K0
发布2022-08-23 10:07:47
举报
文章被收录于专栏:c++与qt学习

Gin简单明了的教程---上

Gin 环境搭建

1.下载并安装 gin:

代码语言:javascript
复制
go get -u github.com/gin-gonic/gin

注意: 如果直接从github拉取失败,可以尝试更换代理,重新设置GOPROXY为国内代理源,然后再次尝试

代码语言:javascript
复制
go env -w GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy,https://goproxy.io,direct

2.将 gin 引入到代码中:

代码语言:javascript
复制
import "github.com/gin-gonic/gin"

3.测试

代码语言:javascript
复制
package main

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

func main() {
	//创建一个默认的路由引擎
	router := gin.Default()
	//配置路由
	router.GET("/", func(c *gin.Context) {
		//返回JSON数据
		c.JSON(200, gin.H{
			"status": 200,
			"data":   "SUCCESS",
		})
	})
	//启动HTTP服务,默认8080端口
	router.Run()
}
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
	//改变默认启动端口--如果是localhost可以省略
	router.Run(":8000")

golang 程序的热加载

热加载就是当我们对代码进行修改时,程序能够自动重新加载并执行,这在我们开发中 是非常便利的,可以快速进行代码测试,省去了每次手动重新编译。

beego 中我们可以使用官方给我们提供的 bee 工具来热加载项目,但是 gin 中并没有官方提 供的热加载工具,这个时候我们要实现热加载就可以借助第三方的工具。

代码语言:javascript
复制
go get github.com/pilu/fresh 
D:\gin_demo>fresh

先查看GOPATH下bin目录下有无fresh.exe,没有的话,采用下面方式进行安装和下载:

代码语言:javascript
复制
git clone https://github.com/gravityblast/fresh.git
go install github.com/pilu/fresh@latest
在这里插入图片描述
在这里插入图片描述
  • 如果是linux系统,出现命令找不到的情况,需要设置软链接或者将对应可执行程序路径加入环境变量。
  • 如果是win系统,也是同理,加入环境变量。

在对应的项目文件下,打开命令行,执行fresh命令,会自动去寻找项目文件下的main文件,然后启动程序,然后一直监控当前目录下的文件是否被修改,如果是的话,就重启项目。

在这里插入图片描述
在这里插入图片描述

GoLand只有在电脑启动的时候才会去读取环境变量,因此如果不重启电脑,那么GoLand终端使用fresh命令,会报错


代码语言:javascript
复制
go get github.com/codegangsta/gin
gin run main.go

Gin 框架中的路由

看例子学习:

代码语言:javascript
复制
package main

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

func main() {
	//创建一个默认的路由引擎
	router := gin.Default()
	//配置路由--支持RestFul API

	//增
	router.POST("/", func(c *gin.Context) {
	    //?name=dhy&age=18
		name := c.Query("name")
		age := c.Query("age")
		//H类型为: map[string]interface{} 等同于Java中的Map<String,Object>
		c.JSON(200, gin.H{
			"name": name,
			"age":  age,
		})
	})

	//删
	router.DELETE("/", func(c *gin.Context) {
		c.String(200, "delete")
	})

	//改
	router.PUT("/", func(c *gin.Context) {
		c.String(200, "put")
	})

	//查
	router.GET("/", func(c *gin.Context) {
		c.String(200, "this is Get query!")
	})

	//改变默认启动端口
	router.Run(":8080")
}

动态路由

代码语言:javascript
复制
	//查
	router.GET("/:id", func(c *gin.Context) {
		id := c.Param("id")
		//可以格式化字符串
		c.String(200, "get id= %v", id)
	})

响应结果

返回一个字符串

代码语言:javascript
复制
	//查
	router.GET("/", func(c *gin.Context) {
		id := c.Query("id")
		//可以格式化字符串
		c.String(200, "get id= %v", id)
	})

返回一个 JSON 数据

代码语言:javascript
复制
package main

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

func main() {
	//创建一个默认的路由引擎
	r := gin.Default()

	r.GET("/json", func(c *gin.Context) {
		aid := c.Query("aid")
		// 方式一:自己拼接 JSON
		c.JSON(http.StatusOK, gin.H{
			"msg": aid,
		})
	})

	r.GET("/structJson", func(c *gin.Context) {
		// 结构体方式
		//通过json备注,可以指定key名
		//未导出的字段不会被序列化(小写属性名)
		var msg struct {
			Username string
			Msg      string `json:"msg"`
			Age      string `json:"age"`
		}
		msg.Username = "name1"
		msg.Msg = "msg1"
		msg.Age = "18"
		c.JSON(200, msg)
	})

	//改变默认启动端口
	r.Run(":5200")
}

对于JSON序列化而言,在go语言中会忽略小写的属性名,并且默认key都是属性名大写的,可以通过在结构体属性名后面添加备注,指定显示的key名:

在这里插入图片描述
在这里插入图片描述

返回JSONP

代码语言:javascript
复制
package main

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

func main() {
	//创建一个默认的路由引擎
	r := gin.Default()

	r.GET("/JSONP", func(c *gin.Context) {
		data := map[string]interface{}{
			"foo": "bar",
		}
		// /JSONP?callback=x
		// 将输出:x({\"foo\":\"bar\"})
		c.JSONP(http.StatusOK, data)
	})

	//改变默认启动端口
	r.Run(":5200")
}
在这里插入图片描述
在这里插入图片描述

JSONP跨域主要用于跨域解决,具体可参考下面这篇文章:

Golang Gin 实战(九)| JSONP跨域和劫持


渲染文件

代码语言:javascript
复制
package main

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

func main() {
	//创建一个默认的路由引擎
	r := gin.Default()

	r.GET("/", func(c *gin.Context) {
		//直接将文件内容写回显示在浏览器上
		c.File("main.go")
		//将文件以附件形式进行下载,参数是是文件路径,参数二是下载时显示的文件名
		c.FileAttachment("main.go", "神秘文件.txt")
	})

	//改变默认启动端口
	r.Run(":5200")
}

渲染html模板

代码语言:javascript
复制
package main

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

func main() {
	//创建一个默认的路由引擎
	r := gin.Default()
    //需要先加载模板文件
	r.LoadHTMLGlob("templates/*")

	r.GET("/", func(c *gin.Context) {
		//渲染,然后响应渲染后的模板文件
		c.HTML(
			http.StatusOK, "index.html",
			map[string]interface{}{"title": "前台首页"})
	})

	//改变默认启动端口
	r.Run(":5200")
}
代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
 {{.title}}
</body>
</html>
在这里插入图片描述
在这里插入图片描述

Gin HTML 模板渲染

最简单的步骤就两步:

  • 加载模板文件
  • 渲染时传入模型数据,将最终渲染结果响应到浏览器
代码语言:javascript
复制
	//创建一个默认的路由引擎
	r := gin.Default()
	//template目录下面所有文件都是模板文件
	r.LoadHTMLGlob("templates/*")

	r.GET("/", func(c *gin.Context) {
		//渲染,然后响应渲染后的模板文件
		c.HTML(
			http.StatusOK, 
            //去template目录下寻找index.html模板文件
            "index.html",
			//模型数据
			map[string]interface{}{"title": "前台首页"})
	})

	//改变默认启动端口
	r.Run(":5200")

关于模板文件中的相关语法和使用,这里不展开了,如果有做单体应用需要用到模板文件支持的,可以自行查阅相关资料。


静态文件服务

当我们渲染的 HTML 文件中引用了静态文件时,我们需要配置静态 web 服务 r.Static(“/static”, “./static”) 前面的/static 表示路由 后面的./static 表示路径

代码语言:javascript
复制
	r := gin.Default()
	//将请求映射到一个静态资源目录下
	r.Static("/static", "./static")
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

路由详解

Get 请求传值

GET /user?uid=20&page=1

代码语言:javascript
复制
	r.GET("/user", func(c *gin.Context) { 
		uid := c.Query("uid")
		//如果请求参数中没有携带page参数,则返回默认值
		page := c.DefaultQuery("page", "0") 
		c.String(200, "uid=%v page=%v", uid, page)
	})

动态路由传值

get /user/20

代码语言:javascript
复制
	r.GET("/user/:id", func(c *gin.Context) {
		id := c.Param("id")
		c.JSON(200, gin.H{
			"news": id, //id 20
		})
	})

Post 请求传值 获取 form 表单数据

  • 通过 c.PostForm 接收表单传过来的数据
代码语言:javascript
复制
	r.POST("/doAddUser", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.PostForm("password")
		age := c.DefaultPostForm("age", "20")
		c.JSON(200, gin.H{
			"usernmae": username, "password": password, "age": age,
		})
	})
  • postman进行数据提交
在这里插入图片描述
在这里插入图片描述

Get 传值绑定到结构体

/?username=zhangsan&password=123456

代码语言:javascript
复制
package main

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

//注意首字母大写,以及暴露给表单和json时的属性名
type Userinfo struct {
	Username string `form:"username" json:"user"`
	Password string `form:"password" json:"pwd"`
}

func main() {
	// 创建一个默认的路由引擎
	r := gin.Default()
	// 配置路由
	r.GET("/", func(c *gin.Context) {
		var userinfo Userinfo
		if err := c.ShouldBind(&userinfo); err == nil {
			c.JSON(http.StatusOK, userinfo)
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})
	r.Run()
}
在这里插入图片描述
在这里插入图片描述

Post 传值绑定到结构体

代码语言:javascript
复制
	r.POST("/", func(c *gin.Context) {
		var userinfo Userinfo
		if err := c.ShouldBind(&userinfo); err == nil {
			c.JSON(http.StatusOK, userinfo)
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

和get数据绑定一样。


Xml数据绑定

如果请求提交的是xml形式的数据,该怎么完成数据绑定呢?

代码语言:javascript
复制
	type Article struct {
		Title   string `json:"title" xml:"title"`
		Content string `json:"content" xml:"content"`
	}

	r.POST("/xml", func(ctx *gin.Context) {
		var article Article
		if err := ctx.ShouldBindXML(&article); err == nil {
			ctx.JSON(http.StatusOK, article)
		}else {
			ctx.JSON(http.StatusBadRequest, gin.H {
				"err": err.Error()})
		}
	})

关于xml数据绑定,还有一种原始方式,如下:

代码语言:javascript
复制
	r.POST("/xml", func(ctx *gin.Context) {
		//获取请求体中原始的字节流
		data, _ := ctx.GetRawData()
		var article Article
		 //使用go官方提供的xml反序列化方式
		if err := xml.Unmarshal(data, &article); err == nil {
			ctx.JSON(http.StatusOK, article)
		} else {
			ctx.JSON(http.StatusBadRequest, gin.H{
				"err": err.Error()})
		}
	})
在这里插入图片描述
在这里插入图片描述

还有JSON数据绑定,YML数据绑定等,都是一样的套路,这里不多展开,大家自行探索


路由分组

代码语言:javascript
复制
package main

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

func main() {
	r := gin.Default()

	userRouter := r.Group("/user")
	{
		userRouter.GET("/id", func(ctx *gin.Context) {
			ctx.String(200, "getUserById")
		})

		userRouter.POST("/", func(ctx *gin.Context) {
			ctx.String(200, "post one user")
		})
	}

	adminRouter := r.Group("/admin")
	{
		adminRouter.GET("/id", func(ctx *gin.Context) {
			ctx.String(200, "getAdminById")
		})

		adminRouter.POST("/", func(ctx *gin.Context) {
			ctx.String(200, "post one admin")
		})
	}

	r.Run()
}

这里的路由分组和java中spring框架在controller类上面标注@RequestMapping注解的请求域隔离功能类似


路由分离

如何将不同的路由放入不同的文件进行管理,就像spring不同的请求域由不同的controller处理类似。

  • 在项目新建文件夹router,然后在router目录下创建userRouter.go 和adminRouter.go,内容如下:
代码语言:javascript
复制
package router

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

func UserRouter(r *gin.Engine) {
	userRouter := r.Group("/user")
	{
		userRouter.GET("/id", func(ctx *gin.Context) {
			ctx.String(200, "getUserById")
		})

		userRouter.POST("/", func(ctx *gin.Context) {
			ctx.String(200, "post one user")
		})
	}
}
代码语言:javascript
复制
package router

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

func AdminRouter(r *gin.Engine) {
	adminRouter := r.Group("/admin")
	{
		adminRouter.GET("/id", func(ctx *gin.Context) {
			ctx.String(200, "getAdminById")
		})

		adminRouter.POST("/", func(ctx *gin.Context) {
			ctx.String(200, "post one admin")
		})
	}
}

在main.go中引入路由模块

代码语言:javascript
复制
package main

import (
	"socket/router"

	"github.com/gin-gonic/gin"
)
func main() {
	// 创建一个默认的路由引擎
	r := gin.Default()
	// 引入路由模块
	router.AdminRouter(r)
	router.ApiRouter(r)
	// 启动 HTTP 服务,默认在 0.0.0.0:8080 启动服务
	r.Run()
}

Gin 中自定义控制器

控制器分组

当我们的项目比较大的时候有必要对我们的控制器进行分组 , 业务逻辑放在控制器中

在项目文件夹下面新建controller文件夹,创建userController.go

代码语言:javascript
复制
package controller

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

func UserGet(c *gin.Context) {
	c.String(200, "get user")
}

func UserPost(c *gin.Context) {
	c.String(200, "post user")
}

func UserPut(c *gin.Context) {
	c.String(200, "put user")
}

func UserDelete(c *gin.Context) {
	c.String(200, "delete user")
}

在UserRouter.go中调用userController.go 的函数

代码语言:javascript
复制
package router

import (
	"GinStudy/controller"
	"github.com/gin-gonic/gin"
)

func UserRouter(r *gin.Engine) {
	userRouter := r.Group("/user")
	{
		userRouter.GET("/", controller.UserGet)
		userRouter.POST("/", controller.UserPost)
		userRouter.DELETE("/", controller.UserDelete)
		userRouter.PUT("/", controller.UserPut)
	}
}

为了使方法能够继承,我们修改userController.go 内容

代码语言:javascript
复制
package controller

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

type UserController struct {

}

func (u *UserController) UserGet(c *gin.Context) {
	c.String(200, "get user")
}

func  (u *UserController) UserPost(c *gin.Context) {
	c.String(200, "post user")
}

func  (u *UserController) UserPut(c *gin.Context) {
	c.String(200, "put user")
}

func  (u *UserController) UserDelete(c *gin.Context) {
	c.String(200, "delete user")
}

继续修改UserRouter.go

代码语言:javascript
复制
package router

import (
	"GinStudy/controller"
	"github.com/gin-gonic/gin"
)

func UserRouter(r *gin.Engine) {
	userRouter := r.Group("/user")
	{
		u := new(controller.UserController)
		userRouter.GET("/", u.UserGet)
		userRouter.POST("/", u.UserPost)
		userRouter.DELETE("/", u.UserDelete)
		userRouter.PUT("/", u.UserPut)
	}
}

控制器的继承

在controller目录下新建baseController.go,内容如下:

代码语言:javascript
复制
package controller

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

type BaseController struct{}

func (con BaseController) success(c *gin.Context) {
	c.String(200, "success")
}

func (con BaseController) error(c *gin.Context) {
	c.String(200, "failed")
}

继续修改userController.go

代码语言:javascript
复制
package controller

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

type UserController struct {
	// 继承BaseController
	BaseController
}

func (u *UserController) UserGet(c *gin.Context) {
	c.String(200, "get user")
}

func (u *UserController) UserPost(c *gin.Context) {
	c.String(200, "post user")
}

func (u *UserController) UserPut(c *gin.Context) {
	c.String(200, "put user")
}

func (u *UserController) UserDelete(c *gin.Context) {
	c.String(200, "delete user")
}

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Gin简单明了的教程---上
  • Gin 环境搭建
  • golang 程序的热加载
  • Gin 框架中的路由
    • 动态路由
      • 响应结果
        • 返回一个字符串
        • 返回一个 JSON 数据
        • 返回JSONP
        • 渲染文件
      • 渲染html模板
      • Gin HTML 模板渲染
        • 静态文件服务
        • 路由详解
          • Get 请求传值
            • 动态路由传值
              • Post 请求传值 获取 form 表单数据
                • Get 传值绑定到结构体
                  • Post 传值绑定到结构体
                    • Xml数据绑定
                      • 路由分组
                        • 路由分离
                          • Gin 中自定义控制器
                            • 控制器分组
                            • 控制器的继承
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档