gin框架基本使用

一、基础环境

1.go版本

E:\code\go\gin框架学习>go version
go version go1.20.3 windows/amd64

2.go代理设置

使用vscode进行go开发. 按ctrl+~ 弹出终端,进行设置

go env -w GOPROXY=https://goproxy.cn,direct

查看设置结果,设置成功
go env |findstr /i goproxy
set GOPROXY=https://goproxy.cn,direct

3.初始化项目目录

在项目目录下执行一下命令,生成go.mod文件

E:\code\go\gin框架学习>go mod init hellogin
go: creating new go.mod: module hellogin

4.下载gin框架

go get -u github.com/gin-gonic/gin

二、初始gin框架

package main

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

func sayHello(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "hello gin",
	})
}

func main() {
	//返回一个默认的路由引擎
	r := gin.Default()
	
    //设置一个基础的get请求
	r.GET("/hello", sayHello)
	
    //运行gin框架
	r.Run()
}

访问127.0.0.1:8080/hello就能看到一串JSON字符串。

三、返回json数据

1.gin.H

package main

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

func sayHello(c *gin.Context) {
	data := gin.H{
		"name": "zhangsan",
		"age":  "20",
	}
	c.JSON(200, data)
}

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

	//设置一个基础的get请求
	r.GET("/hello", sayHello)

	//运行gin框架
	r.Run()
}

2.map

package main

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

func sayHello(c *gin.Context) {
// 这里定义了 值类型为interface的map数据类型
	data := map[string]interface{}{
		"name": "lisi",
		"age":  30,
	}
	c.JSON(200, data)
}

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

	//设置一个基础的get请求
	r.GET("/hello", sayHello)

	//运行gin框架
	r.Run()
}

3.结构体

3.1 错误示例
package main

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

//字段全部改为大写
type student struct {
	name   string
	age    int
	gender string
}

func sayHello(c *gin.Context) {
	data := student{"wangwu", 20, "boy"}
	c.JSON(200, data)
}

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

	//设置一个基础的get请求
	r.GET("/hello", sayHello)

	//运行gin框架
	r.Run()
}

此时在浏览器中返回的数据是空 {}结果。这是因为结果中的字段没有首字母大写。

3.2 正确写法
package main

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

type student struct {
	Name   string
	Age    int
	Gender string
}

func sayHello(c *gin.Context) {
	data := student{"wangwu", 20, "boy"}
	c.JSON(200, data)
}

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

	//设置一个基础的get请求
	r.GET("/hello", sayHello)

	//运行gin框架
	r.Run()
}

此时返回结果正常。

{"Name":"wangwu","Age":20,"Gender":"boy"}
3.3 使用tag

如果想要返回小写的类型名称,还是需要使用tag

package main

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

type student struct {
	Name   string `json:"name"`
	Age    int    `json:"age"`
	Gender string `json:"gender"`
}

func sayHello(c *gin.Context) {
	data := student{"wangwu", 20, "boy"}
	c.JSON(200, data)
}

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

	//设置一个基础的get请求
	r.GET("/hello", sayHello)

	//运行gin框架
	r.Run()
}

四、获取query string

http://127.0.0.1:8080/hello?name=zhangsan&age=20

获取查询参数中的name和age的值

1.Query

package main

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

func sayHello(c *gin.Context) {
	getname := c.Query("name")
	getage := c.Query("age")

	data := gin.H{
		"name": getname,
		"age":  getage,
	}
	c.JSON(200, data)
}

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

	//设置一个基础的get请求
	r.GET("/hello", sayHello)

	//运行gin框架
	r.Run()
}

2.DefaultQquery

如果没有查询到,定义一个默认的返回的结果

不传值
http://127.0.0.1:8080/hello?
或者没有对应的key值
http://127.0.0.1:8080/hello?name1=lisi
package main

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

func sayHello(c *gin.Context) {
	getname := c.DefaultQuery("name", "为获取到值")
	getage := c.DefaultQuery("age", "为获取到值")

	data := gin.H{
		"name": getname,
		"age":  getage,
	}
	c.JSON(200, data)
}

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

	//设置一个基础的get请求
	r.GET("/hello", sayHello)

	//运行gin框架
	r.Run()
}

五、获取post数据

1.获取form表达数据

package main

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

func sayHello(c *gin.Context) {
	getusername := c.PostForm("username")
	getpassword := c.PostForm("password")

	data := gin.H{
		"username": getusername,
		"password": getpassword,
		"age":      20,
	}
	c.JSON(200, data)
}

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

	//设置一个基础的get请求
	r.GET("/hello", sayHello)
	r.POST("/hello", sayHello)

	//运行gin框架
	r.Run()
}

使用postman 模拟提交form表单数据

2.shouldbind获取body数据

上边的postform函数只能获取 form格式提交过来的数据。如果不知道用户传递过来的body是什么样的数据类型(Content-Type).就可以使用此函数将数据和结构体对应上。
此函数会按照下边的顺序解析请求中的数据完成绑定:

1.如果是get请求,只使用Form绑定引擎
2.如果是post请求,默认是按照json格式绑定数据

这里就是使用json格式数据提交 username和password值,就可以绑定成功.

package main

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

type userinfo struct {
	Username string
	Password string
	Age      int
}

func sayHello(c *gin.Context) {
	var uf userinfo
	err := c.ShouldBind(&uf)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
	} else {
		data := gin.H{
			"username": uf.Username,
			"password": uf.Password,
		}
		c.JSON(200, data)
	}

}

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

	//设置一个基础的get请求
	r.POST("/hello/", sayHello)

	//运行gin框架
	r.Run()
}

使用form格式进行提交,需要给结构体打tag.这样json和form格式就都可以进行绑定了

type userinfo struct {
	Username string `form:"username"`
	Password string `form:"password"`
	Age      int
}

为了稳定一般我们会把tag写全,保证不会出错

type userinfo struct {
	Username string `form:"username" json:"username"`
	Password string `form:"password" json:"password"`
	Age      int
}

六、获取url路径中的值

package main

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

func sayHello(c *gin.Context) {
    //获取url中定义的变量
	getusername := c.Param("username")
	getage := c.Param("age")

	data := gin.H{
		"username": getusername,
		"password": getage,
	}
	c.JSON(200, data)
}

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

	//讲url中的值映射位一个变量,然后在函数中获取
	r.GET("/hello/:username/:age", sayHello)

	//运行gin框架
	r.Run()
}

七、路由

1.普通路由

这些都是普通路由

r.GET()
r.POST()

2.路径匹配函数any

在上边的方法中,r.get或者r.post来区分用户的请求。而r.any只要路径匹配,不论用户是什么请求方法都匹配

r.Any("/user", getuser)

3.路由匹配失败函数

r.NoRoute

package main

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

func no_route(ctx *gin.Context) {
	ctx.JSON(404, gin.H{
		"message": "404没有配到相关路径",
	})
}
func getuser(ctx *gin.Context) {
	ctx.JSON(200, gin.H{
		"user": "zhangsan",
		"id":   3,
	})
}

func main() {
	var r = gin.Default()
	r.Any("/user", getuser)
	r.NoRoute(no_route)
	r.Run()
}

4.路由分组

package main

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

func rootfunc(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "这是根路径",
	})
}

func adduser(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "添加用户",
	})
}
func deleteuser(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "删除用户",
	})
}

func main() {
	router := gin.Default()
	router.GET("/", rootfunc)
	r1 := router.Group("/user")
	r1.Any("/add", adduser)
	r1.Any("/delete", deleteuser)

	router.Run()
}

八、中间件

定义: 其实在gin框架中 中间件就是一个普通的函数,是在用户的请求到达 请求处理函数之前经过的 “函数”

1.中间件定义

package main

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

//设置一个中间件函数
func m1(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "我是m1中间件",
	})
}

//普通函数
func rootfunc(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "这是根路径",
	})
}

func adduser(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "添加用户",
	})
}
func deleteuser(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "删除用户",
	})
}

func main() {
	router := gin.Default()
    //没有配置中间件
	router.GET("/", rootfunc)

    
	r1 := router.Group("/user")
    //配置使用中间件m1
	r1.Any("/add", m1, adduser)
	r1.Any("/delete", m1, deleteuser)

	router.Run()
}

此时发现,/add和/delete 路由都使用了 中间件。而/路由 就没有使用

2.全局注册

如果路由由很多,每个路由都需要手动配置中间件就很麻烦,这时候就用到了中间件的全局注册。
全局注册其实语法很简单,使用

路由实例.use(中间件函数1,中间件函数2,......)

实例如下:

func main() {
	router := gin.Default()
    //进行了全局注册
	router.Use(m1)

    //每个路由就不用在手动添加中间件函数了
	router.GET("/", rootfunc)
	
	r1 := router.Group("/user")
	r1.Any("/add", adduser)
	r1.Any("/delete", deleteuser)

	router.Run()
}

3.Abort函数

此函数的作用是,阻止后续的所有中间件函数,路由函数执行

package main

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

//中间函数1
func m1(c *gin.Context) {
    //这里使用了abort函数
	c.Abort()
	c.JSON(200, gin.H{
		"message": "我是m1中间件",
	})

}
//中间函数2
func m2(c *gin.Context) {

	c.JSON(200, gin.H{
		"message": "我是m2中间件",
	})

}

func rootfunc(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "这是根路径",
	})
}

func adduser(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "添加用户",
	})
}
func deleteuser(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "删除用户",
	})
}

func main() {
	router := gin.Default()
    //全局注册两个中间件函数
	router.Use(m1, m2)

	router.GET("/", rootfunc)

	r1 := router.Group("/user")
	r1.Any("/add", adduser)
	r1.Any("/delete", deleteuser)

	router.Run()
}

执行后发现,在m1中添加了c.Abort()函数后,后续的m2和路由函数都不执行了。所以此函数就是当判断用户的请求不符合要求的时候,直接拒绝掉。不执行后续的函数。

4.Next函数

4.1 正常顺序
package main

import (
	"fmt"

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

func m1(c *gin.Context) {
	fmt.Println("我是m1之前")
	fmt.Println("我是m1之后")

}
func m2(c *gin.Context) {
	fmt.Println("我是m2")

}

func rootfunc(c *gin.Context) {
	fmt.Println("我是/")
}

func main() {
	router := gin.Default()
	router.Use(m1, m2)

	router.GET("/", rootfunc)

	router.Run()
}

执行结果如下:
先把m1执行完,在执行m2执行完,在执行路由函数

我是m1之前
我是m1之后
我是m2
我是/
4.2 加入next函数
package main

import (
	"fmt"

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

func m1(c *gin.Context) {
	fmt.Println("我是m1之前")
	c.Next()
	fmt.Println("我是m1之后")

}
func m2(c *gin.Context) {
	fmt.Println("我是m2")

}

func rootfunc(c *gin.Context) {
	fmt.Println("我是/")
}

func main() {
	router := gin.Default()
	router.Use(m1, m2)

	router.GET("/", rootfunc)

	router.Run()
}

执行结果如下:

我是m1之前
我是m2
我是/
我是m1之后
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值