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")
}
相关推荐
屁股割了还要学37 分钟前
【计算机网络入门】初学计算机网络(五)
学习·计算机网络·考研·青少年编程
屁股割了还要学43 分钟前
【计算机网络入门】初学计算机网络(七)
网络·学习·计算机网络·考研·青少年编程
一天八小时3 小时前
计算机网络学习————(五)TCP/IP学习
学习·tcp/ip·计算机网络
tt5555555555553 小时前
每日一题——接雨水
数据结构·笔记·学习·算法
熊猫烧竹3 小时前
【量化金融自学笔记】--开篇.基本术语及学习路径建议
笔记·学习·金融
wyz09235 小时前
python 之协程笔记
开发语言·笔记·python
武昌库里写JAVA5 小时前
【Redis学习】Redis Docker安装,自定义config文件(包括RDB\AOF setup)以及与Spring Boot项目集成
java·开发语言·spring boot·学习·课程设计
姓刘的哦5 小时前
IMX6Ull学习笔记1:汇编点亮LED灯
汇编·笔记·学习
@Dai6 小时前
【AI】DeepSeek本地部署,Ollama + vscode + Continue,实现本地运行LLM大模型,以及代码自动补全
人工智能·vscode·深度学习·学习·编辑器
虾球xz6 小时前
游戏引擎学习第128天
java·学习·游戏引擎