gin框架学习笔记

初始gin

go 复制代码
package main

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

type Response struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data any    `json:"data"`
}

func index(c *gin.Context) {
	c.JSON(200, Response{
		Code: 0,
		Msg:  "111",
		Data: 222,
	})
}
func main() {

	gin.SetMode("release")
	//1.初始化
	r := gin.Default()

	//挂载路由
	r.GET("/index", index)

	//绑定端口,运行
	r.Run(":8081")
}

响应

enter.go

go 复制代码
package res

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

type Response struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data any    `json:"data"`
}

var codeMap = map[int]string{
	1001: "权限错误",
	1002: "角色错误",
}

func response(c *gin.Context, code int, data any, msg string) {
	c.JSON(200, Response{
		Code: code,
		Data: data,
		Msg:  msg,
	})
}

func Ok(c *gin.Context, data any, msg string) {
	response(c, 0, data, msg)
}
func OkWithMsg(c *gin.Context, msg string) {
	Ok(c, gin.H{}, msg)
}
func OkWithData(c *gin.Context, data any) {
	Ok(c, data, "成功")
}

func Fail(c *gin.Context, code int, data any, msg string) {
	response(c, code, data, msg)
}

func FailWithMsg(c *gin.Context, msg string) {
	response(c, 1001, nil, msg)
}
func FailWithCode(c *gin.Context, code int) {
	msg, ok := codeMap[code]
	if !ok {
		msg = "服务错误"
	}
	response(c, code, nil, msg)
}

1.json.go

go 复制代码
package main

import (
	"gin_study/study_response/res"
	"github.com/gin-gonic/gin"
)

func index(c *gin.Context) {
	c.JSON(200, gin.H{"code": 0, "meg": "成功", "data": gin.H{}})
}
func main() {

	r := gin.Default()

	r.GET("/login", func(c *gin.Context) {
		res.OkWithMsg(c, "登录成功")
	})
	r.GET("/users", func(c *gin.Context) {
		res.OkWithData(c, map[string]any{
			"name": 1,
		})
	})
	r.POST("/users", func(c *gin.Context) {
		res.FailWithMsg(c, "参数错误")
	})

	r.Run(":8080")
}

响应html

html.go

go 复制代码
package main

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

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("study_response/templates/*") //加载所有
	//r.LoadHTMLFiles("study_response/templates/index.html") //加载单个
	r.GET("/", func(c *gin.Context) {
		c.HTML(200, "index.html", map[string]any{
			"Title": "1111111",
		})
	})
	r.Run(":8080")
}

index.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{.Title}}</title>
</head>
<body>
00000000000
</body>
</html>

响应文件

go 复制代码
package main

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

func main() {
	r := gin.Default()
	r.GET("", func(c *gin.Context) {
		c.Header("Content-Type", "application/octet-stream")//表示是文件流,唤起浏览器下载,一般设置了这个,就要设置文件名
		c.Header("Content-Disposition", "attachment; filename=3.file.go") // 用来指定下载下来的文件名
		fmt.Println("XXX")
		c.File("study_response/3.file.go")//文件路径
	})

	r.Run(":8080")
}

静态文件

go 复制代码
r.Static("static", "static") // 第一个参数是别名,第二个才是实际路径
r.StaticFile("abcd", "static/abc.txt")

静态文件的路径不能在被路由使用

go 复制代码
package main

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

func main() {

	r := gin.Default()

	r.Static("st", "study_response/static") //static为根目录,st为别名
	r.StaticFile("abc", "study_response/static/a.txt")
	r.Run(":8090")
}

请求

查询参数

127.0.0.1:8085/?name=tom&age=20&key=1111&key=2222

go 复制代码
package main

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

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		name := c.Query("name")
		age := c.DefaultQuery("age", "25") //不传参数默认值25
		keyList := c.QueryArray("key")
		fmt.Println(name)
		fmt.Println(age)
		fmt.Println(keyList)
	})

	r.Run(":8085")
}

动态参数

127.0.0.1:8086/users/12/123

go 复制代码
package main

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

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

	r.GET("users/:id", func(c *gin.Context) {
		userID := c.Param("id")
		fmt.Println(userID)
	})
	r.GET("users/:id/:name", func(c *gin.Context) {
		userID := c.Param("id")
		userName := c.Param("name")
		fmt.Println(userName)
		fmt.Println(userID)
	})

	r.Run(":8086")
}

表单参数

go 复制代码
package main

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

func main() {

	r := gin.Default()

	r.POST("users", func(c *gin.Context) {
		name := c.PostForm("name")
		age, ok := c.GetPostForm("age")
		fmt.Println(name)
		fmt.Println(age, ok)
	})
	r.Run(":8080")
}

文件上传

go 复制代码
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"os"
)

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

	r.POST("users", func(c *gin.Context) {
		fileHeader, err := c.FormFile("file")
		if err != nil {
			fmt.Println(err)
			return
		}
		fmt.Println(fileHeader.Filename)
		fmt.Println(fileHeader.Size)
		file, _ := fileHeader.Open()
		byteDate, _ := io.ReadAll(file)
		err = os.WriteFile("1.jpg", byteDate, 0666)
		fmt.Println(err)
	})

	r.Run(":8080")
}

简单方式

go 复制代码
err = c.SaveUploadedFile(fileHeader, "uploads/xxx/yyy/"+fileHeader.Filename)
fmt.Println(err)

多文件上传

go 复制代码
r.POST("users", func(c *gin.Context) {
    form, err := c.MultipartForm()
    if err != nil {
      fmt.Println(err)
      return
    }
    for _, headers := range form.File {
      for _, header := range headers {
        c.SaveUploadedFile(header, "uploads/"+header.Filename)
      }
    }
  })

原始内容

解决body阅后即焚问题

go 复制代码
package main

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
)

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

	r.POST("", func(c *gin.Context) {
		byteData, _ := io.ReadAll(c.Request.Body)
		fmt.Println(string(byteData))
		//读了之后body就没了,阅后即焚

		//添加
		c.Request.Body = io.NopCloser(bytes.NewReader(byteData))
		
		name := c.PostForm("name")
		fmt.Println(name)
	})
	r.Run(":8080")
}
form-data
go 复制代码
----------------------------853882779395683818968400
Content-Disposition: form-data; name="name"

枫枫
----------------------------853882779395683818968400
Content-Disposition: form-data; name="age"

1234
----------------------------853882779395683818968400--

对应的分隔符为

go 复制代码
Content-Type:[multipart/form-data; boundary=--------------------------052455317193517003536866]
x-www-form-urlencoded

url编码

复制代码
name=%E6%9E%AB%E6%9E%AB&age=1234
json
go 复制代码
{
    "name": "枫枫",
    "age": 23
}

bind绑定器

查询参数

go 复制代码
package main

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

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

	r.GET("/", func(c *gin.Context) {
		type user struct {
			Name string `form:"name"`
			Age  int    `form:"age"`
		}

		var u user
		err := c.ShouldBindQuery(&u)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(u)
	})
	r.Run(":8080")
}

路径参数

http://localhost:8080/users/1/www

go 复制代码
type user struct {
			Name string `uri:"name"`
			Id   int    `uri:"id"`
		}
		var u user

		err := c.ShouldBindUri(&u)
		fmt.Println(err, u)
	})

表单参数

go 复制代码
	//表单参数
	r.POST("form", func(c *gin.Context) {
		type user struct {
			Name string `form:"name"`
			Age  int    `form:"age"`
		}
		var u user
		err := c.ShouldBind(&u)
		fmt.Println(u, err)
	})

json

go 复制代码
r.POST("json", func(c *gin.Context) {
		type user struct {
			Name string `json:"name"`
			Age  int    `json:"age"`
		}
		var u user
		err := c.ShouldBindJSON(&u)
		fmt.Println(u, err)

	})

header参数

go 复制代码
r.POST("header", func(c *gin.Context) {
		type user struct {
			Name        string `header:"Name"`
			Age         int    `header:"Age"`
			ContentType string `header:"Content-Type"`
		}
		var u user
		err := c.ShouldBindHeader(&u)
		fmt.Println(u, err)

	})

binding内置规则

go 复制代码
// 不能为空,并且不能没有这个字段
required: 必填字段,如:binding:"required"  

// 针对字符串的长度
min 最小长度,如:binding:"min=5"
max 最大长度,如:binding:"max=10"
len 长度,如:binding:"len=6"

// 针对数字的大小
eq 等于,如:binding:"eq=3"
ne 不等于,如:binding:"ne=12"
gt 大于,如:binding:"gt=10"
gte 大于等于,如:binding:"gte=10"
lt 小于,如:binding:"lt=10"
lte 小于等于,如:binding:"lte=10"

// 针对同级字段的
eqfield 等于其他字段的值,如:PassWord string `binding:"eqfield=Password"`
nefield 不等于其他字段的值


- 忽略字段,如:binding:"-" 或者不写

// 枚举  只能是red 或green
oneof=red green 

// 字符串  
contains=fengfeng  // 包含fengfeng的字符串
excludes // 不包含
startswith  // 字符串前缀
endswith  // 字符串后缀

// 数组
dive  // dive后面的验证就是针对数组中的每一个元素

// 网络验证
ip
ipv4
ipv6
uri
url
// uri 在于I(Identifier)是统一资源标示符,可以唯一标识一个资源。
// url 在于Locater,是统一资源定位符,提供找到该资源的确切路径

// 日期验证  1月2号下午3点4分5秒在2006年
datetime=2006-01-02

5. gin中间件和路由

路由

路由(api)分组

go 复制代码
package main

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

func main() {

	r := gin.Default()

	apiGroup := r.Group("api")

	UserGroup(apiGroup)
	r.Run(":8080")
}

func UserGroup(r *gin.RouterGroup) {
	r.GET("users", UserView)
	r.POST("users", UserView)
	r.PUT("users", UserView)
	r.PATCH("users", UserView)
	r.DELETE("users", UserView)
}
func UserView(c *gin.Context) {
	path := c.Request.URL
	fmt.Println(c.Request.Method)
	fmt.Println(path)
}

RESTFul Api规范

尽量使用名词复数来定义

go 复制代码
// 在没有resetful规范正确,表示创建用户,删除用户
/api/user_create
/api/users/create
/api/users/add
/api/add_user
/api/user/delete
/api/user_remove

// 使用resetful规范
GET /api/users  用户列表
POST /api/users  创建用户
PUT /api/users/:id 更新用户信息
DELETE /api/users 批量删除用户
DELETE /api/users/:id 删除单个用户

中间件

局部中间件

直接用于单个路由

go 复制代码
package main

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

func Home(c *gin.Context) {
	fmt.Println("Home")
	c.String(200, "Home")
}

func M1(c *gin.Context) {
	fmt.Println("M1 请求部分")
	c.Next()
	fmt.Println("M1 响应部分")
}
func M2(c *gin.Context) {
	fmt.Println("M2 请求部分")
	c.Abort()
	fmt.Println("M2 响应部分")
}
func main() {
	r := gin.Default()

	r.GET("", M1, M2, Home)

	r.Run(":8080")
}
全局中间件

全局也就是路由组。这也就是给路由分组的意义

go 复制代码
package main

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

func Home(c *gin.Context) {
	fmt.Println("Home")
	c.String(200, "Home")
}

func M1(c *gin.Context) {
	fmt.Println("M1 请求部分")
	c.Next()
	fmt.Println("M1 响应部分")
}
func M2(c *gin.Context) {
	fmt.Println("M2 请求部分")
	c.Abort()
	fmt.Println("M2 响应部分")
}
func GM1(c *gin.Context) {
	fmt.Println("GM1 请求部分")
	c.Next()
	fmt.Println("GM2 响应部分")
}

func GM2(c *gin.Context) {
	fmt.Println("GM2 请求部分")
	c.Next()
	fmt.Println("GM2 响应部分")
}
func main() {
	r := gin.Default()

	g := r.Group("api")
	g.Use(GM1, GM2)

	g.GET("users", Home)
	r.GET("", M1, M2, Home)

	r.Run(":8080")
}
中间件传递参数
go 复制代码
package main

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

type UserInfo struct {
	Name string
}

func Home(c *gin.Context) {
	fmt.Println("Home")

	userName, ok := c.Get("user")
	if ok {
		name, ok := userName.(UserInfo)
		if ok {
			fmt.Println(name)
		}
	}

	fmt.Println(c.Get("GM1"))
	fmt.Println(c.Get("GM2"))
	c.String(200, "Home")
}

func M1(c *gin.Context) {
	fmt.Println("M1 请求部分")
	c.Next()
	fmt.Println("M1 响应部分")
}
func M2(c *gin.Context) {
	fmt.Println("M2 请求部分")
	c.Abort()
	fmt.Println("M2 响应部分")
}
func GM1(c *gin.Context) {
	fmt.Println("GM1 请求部分")
	c.Set("GM1", "GM1")
	var user = UserInfo{Name: "aaa"}
	c.Set("user", user)
	c.Next()
	fmt.Println("GM2 响应部分")
}

func GM2(c *gin.Context) {
	fmt.Println("GM2 请求部分")
	c.Set("GM2", "GM2")
	c.Next()
	fmt.Println("GM2 响应部分")
}
func main() {
	r := gin.Default()

	g := r.Group("api")
	g.Use(GM1, GM2)

	g.GET("users", Home)
	r.GET("", M1, M2, Home)

	r.Run(":8080")
}
相关推荐
知识分享小能手1 小时前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
汇能感知3 小时前
摄像头模块在运动相机中的特殊应用
经验分享·笔记·科技
阿巴Jun4 小时前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
茯苓gao4 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾4 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT5 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
aaaweiaaaaaa5 小时前
HTML和CSS学习
前端·css·学习·html
ST.J5 小时前
前端笔记2025
前端·javascript·css·vue.js·笔记
Suckerbin5 小时前
LAMPSecurity: CTF5靶场渗透
笔记·安全·web安全·网络安全
看海天一色听风起雨落6 小时前
Python学习之装饰器
开发语言·python·学习