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验证器进行数据验证,并提供代码示例帮助理解
具体使用
- 定义struct 数据模型配置验证字段
- 使用内置验证函数
- 错误处理
所有的验证规则都定义在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颜色 | |
字符串值包含有效的电子邮件 | ||
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