GIN框架使用

hello word

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

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

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

    // 注册一个路由规则 路径为/helloword http请求方法为 post 后边的函数用于写该接口的处理逻辑
	r.POST("/helloword", func(c *gin.Context) {
		c.JSON(200, gin.H{"status": "hello word"})
	})

    // 启动监听端口为 8080
	r.Run(":8080")
}

gin热加载

每次使用gin框架开发过程中修改代码都要手动重启,开发极为不便

推荐使用热加载技术

热加载就是当我们对代码进行修改时,程序能够自动重新加载并执行

安装

go get github.com/pilu/fresh

使用 fresh 替代 go run xxx

fresh

这样修改项目代码就会自动重启服务器

四大请求方式

get

获取资源

post

新建数据

put

修改数据

delete

删除数据

package main

import (
	"net/http"

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

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

    // get请求
	r.GET("/get", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"msg": "get"})
	})

    // post请求
	r.POST("/post", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"msg": "post"})
	})

    // put 请求
	r.PUT("/put", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"msg": "put"})
	})

    // delete 请求
	r.DELETE("/del", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"msg": "del"})
	})

	r.Run(":8080")
}

响应数据

用结构体响应json数据

package main

import (
	"net/http"

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

type Params struct {
	UserName string `json:"username"`
	Age      int    `json:"age"`
	PassWord string `json:"-"` // 忽略转换为json
}

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

	r.GET("/json", func(c *gin.Context) {
		p := &Params{
			UserName: "姓名",
			Age:      16,
			PassWord: "123456",
		}
		c.JSON(http.StatusOK, p)
	})

	r.Run(":8080")
}

用map响应json数据

package main

import (
	"net/http"

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

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

	r.GET("/json", func(c *gin.Context) {

		userMap := map[string]string{
			"username": "姓名",
			"age":      "23",
			"password": "12344",
		}
		c.JSON(http.StatusOK, userMap)
	})

	r.Run(":8080")
}

直接响应json数据

package main

import (
	"net/http"

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

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

	r.GET("/json", func(c *gin.Context) {

		c.JSON(http.StatusOK, gin.H{"key": "value", "key2": "value2"})
	})

	r.Run(":8080")
}

响应文件

重定向

301表示永久重定向

package main

import (
	"net/http"

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

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

	r.GET("/redirect", func(c *gin.Context) {
		// 301表示永久重定向 302表示临时重定向
		c.Redirect(http.StatusMovedPermanently, "https://www.baidu.com/") // 301
	})

	r.Run(":8080")
}

302 表示临时重定向

package main

import (
	"net/http"

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

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

	r.GET("/redirect", func(c *gin.Context) {
		// 301表示永久重定向 302表示临时重定向
		c.Redirect(http.StatusFound, "https://www.baidu.com/") // 301
	})

	r.Run(":8080")
}

获取请求参数

获取query参数

c.Query

发送

localhost:8080/query?id=1223 [get]

获取

package main

import (
	"net/http"

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

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

	r.GET("/query", func(c *gin.Context) {
		id := c.Query("id")
		c.JSON(http.StatusOK, gin.H{"key": id})
	})

	r.Run(":8080")
}

c.GetQuery校验请求是否传递某个参数并且获取传递的值

如果没传id则报错

package main

import (
	"net/http"

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

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

	r.GET("/query", func(c *gin.Context) {
		id, ok := c.GetQuery("id")

		if !ok {
			c.JSON(http.StatusNotFound, gin.H{"msg": "没有传id"})
		} else {
			c.JSON(http.StatusOK, gin.H{"data": id})
		}

	})

	r.Run(":8080")
}

c.DefaultQuery设置请求的默认值,如果没穿则设置一个默认值

package main

import (
	"net/http"

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

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

	r.GET("/query", func(c *gin.Context) {
		id := c.DefaultQuery("id", "1") // 如果请求没穿id则设置默认值
		c.JSON(http.StatusOK, gin.H{"id": id})

	})

	r.Run(":8080")
}

获取path参数

c.Param

发送

localhost:8080/pathparams/12323

获取

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.GET("/pathparams/:id", func(c *gin.Context) {
		id := c.Param("id")
		c.JSON(http.StatusOK, gin.H{"id": id})
	})
	r.Run(":8080")
}

获取请求头

获取请求头

c.GetHeader 获取一个具体的请求头

请求

localhost:8080/header

在请求头传参数

token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyTmFtZSI6InJvb3QiLCJleHAiOjE3MjM1MzYzODksImlzcyI6IuacrOS6uiIsIm5iZiI6MTcyMzUzNDk0OX0.Xd9jzJw7doy6ibbv9XHOBskI63NGMh9CfvgJjB74Q7g

获取

package main

import (
	"net/http"

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

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

	r.GET("/header", func(c *gin.Context) {
		token := c.GetHeader("token")
		c.JSON(http.StatusNotFound, gin.H{"token": token})

	})

	r.Run(":8080")
}

c.Request.Header 获取所有请求头

package main

import (
	"net/http"

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

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

	r.GET("/header", func(c *gin.Context) {
		headers := c.Request.Header
		c.JSON(http.StatusOK, gin.H{"headers": headers})

	})

	r.Run(":8080")
}

设置请求头

c.Header 设置请求头

package main

import (
	"net/http"

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

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

	r.GET("/header", func(c *gin.Context) {
		c.Header("Res-Header", "value")
		c.JSON(http.StatusOK, gin.H{"headers": "ok"})

	})

	r.Run(":8080")
}

bind 用结构体获取参数

gin 中的bind 可以方便的将前端 传递来的数据与结构体 进行 参数绑定,以及参数校验

使用这个功能,需要声明结构体,并在标签上加上 Tag

绑定body的请求参数

请求

localhost:8080/bind [post]

[body]
{
    "name": "小明",
    "age": 12,
    "sex": "男"
}

获取

package main

import (
	"net/http"

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

type UserInfo struct {
	Name string `json:"name`
	Aga  int    `json:"age`
	Sex  string `json:"sex`
}

func main() {
	r := gin.Default()
	r.POST("/bind", func(c *gin.Context) {
		var u UserInfo = UserInfo{}
		c.ShouldBindJSON(&u)
		c.JSON(http.StatusOK, gin.H{"data": u})
	})

	r.Run(":8080")
}

绑定query的请求参数

请求

localhost:8080/bind?name=小明&age=122&sex=男

响应

需要在结构体加 form 标签

package main

import (
	"net/http"

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

type UserInfo struct {
	Name string `json:"name" form:"name"`
	Aga  int    `json:"age" form:"age"`
	Sex  string `json:"sex" form:"sex"`
}

func main() {
	r := gin.Default()
	r.GET("/bind", func(c *gin.Context) {
		var u UserInfo = UserInfo{}
		c.ShouldBindQuery(&u)
		c.JSON(http.StatusOK, gin.H{"data": u})
	})

	r.Run(":8080")
}

绑定path中的参数

请求

localhost:8080/bind/姓名/15/男

响应

需要在结构体标签加上 uri 说明

package main

import (
	"net/http"

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

type UserInfo struct {
	Name string `json:"name" form:"name" uri:"name"`
	Aga  int    `json:"age" form:"age" uri:"age"`
	Sex  string `json:"sex" form:"sex" uri:"sex"`
}

func main() {
	r := gin.Default()
	r.GET("/bind/:name/:age/:sex", func(c *gin.Context) {
		var u UserInfo = UserInfo{}
		c.ShouldBindUri(&u)
		c.JSON(http.StatusOK, gin.H{"data": u})
	})

	r.Run(":8080")
}

bind校验

安装validator库

go get -u github.com/go-playground/validator/v10

在Gin框架中,数据绑定和验证是开发API时不可或缺的部分。Gin提供了强大的binding功能,允许我们将请求的数据绑定到结构体,并通过标签进行数据验证。本文将详细讲解如何在Gin中使用binding验证器进行数据验证,并提供代码示例帮助理解

具体使用

  1. 定义struct 数据模型配置验证字段
  2. 使用内置验证函数
  3. 错误处理

所有的验证规则都定义在binding标签内

自带验证器

常用验证器

  • required:字段是必填的。
  • email:验证字段是否是有效的电子邮件地址。
  • min:验证字段的值是否大于或等于指定的最小值(适用于数字和字符串)。
  • max:验证字段的值是否小于或等于指定的最大值(适用于数字和字符串)。
  • gte:验证字段的值是否大于或等于指定的最小值(适用于数字)。
  • lte:验证字段的值是否小于或等于指定的最大值(适用于数字)。
  • len:验证字段的长度是否等于指定值(适用于字符串、切片、数组、map)。
  • oneof:验证字段的值是否在指定的枚举值中。
  • uuid:验证字段是否是有效的 UUID。
  • ipv4 / ipv6 / ip:验证字段是否是有效的 IP 地址。
  • url:验证字段是否是有效的 URL。
验证器名称说明示例
-忽略字段binding:“-”
required必填字段binding:“required”
min最小长度binding:“min=10”
max最大长度binding:“max=10”
structonly如果有嵌套,可以决定只验证结构体上的binding:“structonly”
omitempty省略空,如果为空,则不会继续验证该字段上其他的规则,只有不为空才会继续验证其他的
len长度binding:“len=10”
eq等于binding:“eq=10”
ne不等于binding:“ne=10”
gt大于binding:“gt=10”
gte大于等于binding:“gte=10”
lt小于binding:“lt=10”
lte小于等于binding:“lte=10”
eqfield等于其他字段的值binding:“eqfield=ConfirmPassword”
nefield不等于其他字段的值
eqcsfield类似eqfield,它会验证相对于顶层结构提供的字段
necsfield
gtfield大于其他字段的值
gtefield大于等于其他字段的值
gtcsfield
gtecsfield
ltfield小于其他字段的值
ltefield
ltcsfield
ltecsfield
alpha字符串值仅包含字母字符
alphanum字符串值仅包含字母数字字符
numeric字符串值包含基本数字值。基本不包括指数等…
hexadecimal字符串值包含有效的十六进制
hexcolor验证字符串值包含有效的十六进制颜色, 包括井号(#)
rgb字符串值包含有效的rgb颜色
rgba字符串值包含有效的rgba颜色
HSL字符串值包含有效的hsl颜色
hsla字符串值包含有效的hsla颜色
email字符串值包含有效的电子邮件
url字符串值包含有效的网址,必须包含http://等
uri字符串值包含有效的uri. 它将接受golang请求uri接受的任何uri
base64字符串值包含有效的base64值
contains字符串值包含子字符串值, contains=@
containsany包含所有,containsany =!@#?
containsrune字符串值包含提供的符号 containsrune = @
excludes字符串值不包含子字符串值,excludes = @
excludeall排除所有
excluderune字符串值不包含提供的符号,excluderune = @
isbn国际标准书号,验证字符串值包含有效的isbn10或isbn13值
isbn10国际标准书号10, 验证字符串值包含有效的isbn10值
isbn13国际标准书号13, 字符串值包含有效的isbn13值
uuid字符串值包含有效的UUID
uuid3字符串值包含有效的版本3
uuid4字符串值包含有效的版本4
uuid5字符串值包含有效的版本
ascii字符串值仅包含ASCII字符. 注意:如果字符串为空, 则验证为true
asciiprint字符串值仅包含可打印的ASCII字符. 注意: 如果字符串为空,则验证为true
multibyte字符串值包含一个或多个多字节字符。注意:如果字符串为空,则验证为true
datauri字符串值包含有效的DataURI。注意:这还将验证数据部分是有效的base64
latitude纬度,字符串值包含有效的纬度
longitude经度,字符串值包含有效的经度
ssn字符串值包含有效的美国社会安全号码
ip字符串值包含有效的IP地址
ipv4字符串值包含有效的v4 IP地址
ipv6字符串值包含有效的v6 IP地址
cidr字符串值包含有效的CIDR地址
cidrv4字符串值包含有效的CIDR地址
cidrv6字符串值包含有效的v6 CIDR地址
tcp_addr字符串值包含有效的可解析TCP地址
dive嵌套验证

简单示例

package main

import (
	"net/http"

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

// 声明一个结构体用来接收请求参数
type User struct {
	Name  string `form:"name" json:"name" binding:"required"`
	Email string `form:"email" json:"email" binding:"required,email"`
	Age   int    `form:"age" json:"age" binding:"required,eq=10"`
}

func main() {
	r := gin.Default()
	// get请求
	r.GET("/test", func(c *gin.Context) {
		var user User
		if err := c.ShouldBindQuery(&user); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "User created successfully!", "user": user})
	})
	r.Run(":8080")
}

自定义验证

可以通过实现 validator.Func 接口来定义自定义验证函数。以下是一个示例

package main

import (
	"net/http"
	"regexp"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
)

// 定义自定义验证函数
var validUsername validator.Func = func(fl validator.FieldLevel) bool {
	if username, ok := fl.Field().Interface().(string); ok {
		return regexp.MustCompile(`^[a-zA-Z0-9_]+$`).MatchString(username)
	}
	return false
}

// 声明一个结构体用来接收请求参数
type User struct {
	Username string `json:"username" binding:"required,validUsername" form:"username"`
	Email    string `json:"email" binding:"required,email" form:"email"`
}

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

	// 获取默认验证器
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		// 注册自定义验证函数
		v.RegisterValidation("validUsername", validUsername)
	}

	// get请求
	r.GET("/test", func(c *gin.Context) {
		var user User
		if err := c.ShouldBindQuery(&user); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "User created successfully!", "user": user})
	})
	r.Run(":8080")
}

嵌套结构体验证

Gin 也支持对嵌套结构体进行验证。例如

package main

import (
	"net/http"

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

type Address struct {
	Street string `json:"street" binding:"required"`
	City   string `json:"city" binding:"required"`
}

type User struct {
	Name    string    `json:"name" binding:"required"`
	Email   string    `json:"email" binding:"required,email"`
	Address []Address `json:"address" binding:"required,dive"`
}

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

	// get请求
	r.POST("/test", func(c *gin.Context) {
		var user User
		if err := c.ShouldBindJSON(&user); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "User created successfully!", "user": user})
	})
	r.Run(":8080")
}

转化中文

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	zh_translations "github.com/go-playground/validator/v10/translations/zh"
)

var (
	uni      *ut.UniversalTranslator
	validate *validator.Validate
	trans    ut.Translator
)

func Init() {
	//注册翻译器
	zh := zh.New()
	uni = ut.New(zh, zh)

	trans, _ = uni.GetTranslator("zh")

	//获取gin的校验器
	validate := binding.Validator.Engine().(*validator.Validate)
	//注册翻译器
	zh_translations.RegisterDefaultTranslations(validate, trans)
}

// Translate 翻译错误信息
func Translate(err error) map[string][]string {

	var result = make(map[string][]string)

	errors := err.(validator.ValidationErrors)

	for _, err := range errors {
		result[err.Field()] = append(result[err.Field()], err.Translate(trans))
	}
	return result
}

type Booking struct {
	CheckIn  string `form:"check_in" json:"check_in"  binding:"required,email" `
	CheckOut string `form:"check_out" json:"check_out"  binding:"required"`
}

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

	// get请求
	r.POST("/test", func(c *gin.Context) {
		var b Booking
		err := c.ShouldBindJSON(&b)
		if err == nil {
			c.JSON(200, gin.H{"message": "Success"})
			return
		} else {
			c.JSON(200, gin.H{"message": Translate(err)})
			return
		}
	})
	r.Run(":8080")
}

文件操作

c.FormFile 获取上传文件

请求

在这里插入图片描述

响应

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.POST("/upload", func(c *gin.Context) {
		file, err := c.FormFile("file")
		if err != nil {
			c.JSON(http.StatusOK, gin.H{"msg": "上传失败"})
		} else {
			fileSize := file.Size / 1024
			c.JSON(http.StatusOK, gin.H{"msg": "上传成功", "fileSize": fileSize})
		}
	})

	r.Run(":8080")
}

c.SaveUploadedFile将上传的文件保存

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.POST("/upload", func(c *gin.Context) {
		file, err := c.FormFile("file")
		if err != nil {
			c.JSON(http.StatusOK, gin.H{"msg": "上传失败"})
		} else {

			fileSize := file.Size / 1024
			path := "./file/" + file.Filename
            // file具体的文件 path是要保存到的路径
			c.SaveUploadedFile(file, path)
			c.JSON(http.StatusOK, gin.H{"msg": "上传成功", "fileSize": fileSize})
		}
	})

	r.Run(":8080")
}

c.File 下载文件

package main

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

func main() {
	r := gin.Default()
	r.GET("/download", func(c *gin.Context) {
		path := "file/内饰.pdf"
		c.Header("Content-Type", "application/octet-steam")
		c.Header("Content-Disposition", "attachment; filename="+"牛掰.pdf")
		c.Header("Content-Transfer-Encoding", "binary")
		c.File(path)
	})

	r.Run(":8080")
}

中间件

gin允许开发者在处理请求过程中,加入用户自己的狗子函数,这个函数就是中间件

中间件射虎处理公共的业务逻辑,比如登录验证,权限校验,数据分页,记录日志,统计耗时等

package main

import (
	"log"
	"net/http"

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

// 这个函数就是一个中间件
func m1(c *gin.Context) {
	log.Println("中间件执行了")
}

func main() {
	r := gin.Default()
	r.GET("/test", m1, func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"msg": "成功"})
	})

	r.Run(":8080")
}

c.Abort() 拦截请求往下执行

package main

import (
	"log"
	"net/http"

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

func m1(c *gin.Context) {
	c.Abort() // 拦截请求往下执行
}

func main() {
	r := gin.Default()
	r.GET("/test", m1, func(c *gin.Context) {
        // 这里不会执行
		c.JSON(http.StatusOK, gin.H{"msg": "成功"})
	})

	r.Run(":8080")
}

加入多个中间件

package main

import (
	"log"
	"net/http"

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

// 第一个中间件
func m1(c *gin.Context) {
	log.Println(" 第一个中间件执行了")
}

// 第二个中间件
func m2(c *gin.Context) {
	log.Println("第二个中间件执行了")
}

func main() {
	r := gin.Default()
	r.GET("/test", m1, m2, func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"msg": "成功"})
	})

	r.Run(":8080")
}

c.Next() 洋葱模型

package main

import (
	"log"
	"net/http"

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

// 第一个中间件
func m1(c *gin.Context) {
	log.Println(" 第一个中间件in")
	c.Next()
	log.Println(" 第一个中间件out")

}

func main() {
	r := gin.Default()
	r.GET("/test", m1, func(c *gin.Context) {
		log.Println("响应数据")
		c.JSON(http.StatusOK, gin.H{"msg": "成功"})
	})

	r.Run(":8080")
}

打印结果

11:11:57 app         | 2024/08/14 11:11:57  第一个中间件in
11:11:57 app         | 2024/08/14 11:11:57 响应数据
2024/08/14 11:11:57  第一个中间件out

注册全局中间件

package main

import (
	"log"
	"net/http"

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

// 第一个全局中间件
func global1(c *gin.Context) {
	log.Println(" 第1个中间件in")
	c.Next()
	log.Println(" 第1个中间件out")
}

// 第二个全局中间件
func global2(c *gin.Context) {
	log.Println(" 第2个中间件in")
	c.Next()
	log.Println(" 第2个中间件out")
}

func main() {
	r := gin.Default()
	r.Use(global1, global2)
	r.GET("/test", func(c *gin.Context) {
		log.Println("响应数据")
		c.JSON(http.StatusOK, gin.H{"msg": "成功"})
	})

	r.Run(":8080")
}

输出

第1个中间件in
第2个中间件in
响应数据
第2个中间件out
第1个中间件out

通过 c.Set c.Get 实现中间件传值

上一个中间件通过 c.Set方法可以在上下文对象中存入一个值

下游中间件通过 c.Get 方法从上下文对象取出

package main

import (
	"log"
	"net/http"

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

// 第一个全局中间件
func m1(c *gin.Context) {
	c.Set("key", "value")
	c.Next()
}

func main() {
	r := gin.Default()
	r.GET("/test", m1, func(c *gin.Context) {

		value, _ := c.Get("key")
		log.Printf("响应数据%v", value)
		c.JSON(http.StatusOK, gin.H{"msg": "成功", "data": value})
	})

	r.Run(":8080")
}

路由分组

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	mainRouter := r.Group("/api")

	{
		mainRouter.GET("/get", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "成功"})
		})
		mainRouter.POST("/post", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "成功"})
		})
	}

	r.Run(":8080")
}

通过 r.Group(“/api”) 返回一个路由组对象

在通过调用组对象的 get post put …方法

这样请求就必须写成

localhost:8080/api/post [post]
localhost:8080/api/get [get]

分组嵌套

实际项目中通常会将接口进行分模块处理

比如用户模块的接口通常会写成

localhost:8080/api/user/xxx

文章模块的接口通常会写成

localhost:8080/api/article/xxx

具体实现

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)
func main() {
	r := gin.Default()
	mainRouter := r.Group("/api")

	// 用户模块
	userRouter := mainRouter.Group("/user")
	{
		userRouter.GET("/:id", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "调用用户模块"})
		})
	}

	// 文章模块
	articleRouter := mainRouter.Group("/article")
	{
		articleRouter.GET("/:id", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "调用文章模块"})
		})
	}

	r.Run(":8080")
}

将路由文件抽离

实际项目不可能将所有路由都写在main文件中,一般会创建一个单独的包用来放各个模块的路由

创建 router 包 并创建 article.go 和 user.go

article.go

package router

import (
	"net/http"

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

// 创建用户路由
func InitArticleRouter(router *gin.RouterGroup) {
	// 用户模块
	userRouter := router.Group("/article")
	{
		userRouter.GET("/:id", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "调用文章模块"})
		})
	}
}

user.go

package router

import (
	"net/http"

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

// 创建用户路由
func InitUserRouter(router *gin.RouterGroup) {
	// 用户模块
	userRouter := router.Group("/user")
	{
		userRouter.GET("/:id", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "调用用户模块"})
		})
	}
}

main.go

package main

import (
	"gostudy/router"

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

func main() {
	r := gin.Default()
	mainRouter := r.Group("/api")

	{
		router.InitUserRouter(mainRouter)    // 初始化用户路由
		router.InitArticleRouter(mainRouter) // 初始化文章路由
	}

	r.Run(":8080")
}

闭包中间件

有时候我们希望在 r.use( ) 注册中间件时 里边传入的是一个函数

比如

func main() {
	r := gin.Default()
	r.Use(m1())
	r.GET("/test")
	r.Run(":8080")
}

这样就可以在注册中间件时候传入参数

比如

func main() {
	r := gin.Default()
	r.Use(m1("传入的参数"))
	r.GET("/test")
	r.Run(":8080")
}

具体实现

package main

import (
	"log"

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

func m1(str string) gin.HandlerFunc {
	return func(c *gin.Context) {
		log.Printf(str)
		c.Next()
	}
}

func main() {
	r := gin.Default()
	r.Use(m1("log info"))
	r.GET("/test")
	r.Run(":8080")
}

控制台打印

log info

hub.com/gin-gonic/gin"
)

// 创建用户路由
func InitArticleRouter(router *gin.RouterGroup) {
// 用户模块
userRouter := router.Group(“/article”)
{
userRouter.GET(“/:id”, func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{“msg”: “调用文章模块”})
})
}
}


user.go 

```go
package router

import (
	"net/http"

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

// 创建用户路由
func InitUserRouter(router *gin.RouterGroup) {
	// 用户模块
	userRouter := router.Group("/user")
	{
		userRouter.GET("/:id", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "调用用户模块"})
		})
	}
}

main.go

package main

import (
	"gostudy/router"

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

func main() {
	r := gin.Default()
	mainRouter := r.Group("/api")

	{
		router.InitUserRouter(mainRouter)    // 初始化用户路由
		router.InitArticleRouter(mainRouter) // 初始化文章路由
	}

	r.Run(":8080")
}

闭包中间件

有时候我们希望在 r.use( ) 注册中间件时 里边传入的是一个函数

比如

func main() {
	r := gin.Default()
	r.Use(m1())
	r.GET("/test")
	r.Run(":8080")
}

这样就可以在注册中间件时候传入参数

比如

func main() {
	r := gin.Default()
	r.Use(m1("传入的参数"))
	r.GET("/test")
	r.Run(":8080")
}

具体实现

package main

import (
	"log"

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

func m1(str string) gin.HandlerFunc {
	return func(c *gin.Context) {
		log.Printf(str)
		c.Next()
	}
}

func main() {
	r := gin.Default()
	r.Use(m1("log info"))
	r.GET("/test")
	r.Run(":8080")
}

控制台打印

log info
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值