p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解
目录
Gin 框架是一个基于 Go 语言的轻量级 Web 框架,它基于 Go 语言的 net/http 包进行开发,提供了高效、快速、易用的 Web 服务开发体验。
原生HTTP库缺点
go
package main
import "net/http"
import "fmt"
import "io"
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Method,r.URL.String())
if r.Method == "GET" {
byteData, _ := io.ReadAll(r.Body)
fmt.Println(string(byteData))
}
w.Write([]byte("Hello, World!"))
}
func main() {
//访问服务
http.HandleFunc("/index", Index)
http.ListenAndServe("0.0.0.0:8080", nil)
}
C:\Users\Lenovo>curl http://127.0.0.1:8080/index?key=123
Hello, World!
但是在实际项目中使用原生 go http 库那会非常不方便。
主要体现在:参数解析与验证、路由不明确、响应处理比较原始
gin使用
go
package main
import "github.com/gin-gonic/gin"
func main() {
//初始化
r := gin.Default()
//挂载路由
r.GET("/index", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello, World!",
})
})
//绑定端口,启动服务
r.Run(":8080")
}
响应
响应JSON
go
package res
import "github.com/gin-gonic/gin"
type Res 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, Res{
Code: code,
Msg: msg,
Data: data,
})
}
func Ok(c *gin.Context, data any, msg string) {
response(c, 0, data, msg)
}
func OkWithData(c *gin.Context, data any) {
Ok(c, data, "成功")
}
func OkWithMsg(c *gin.Context, msg string) {
Ok(c, nil, msg)
}
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) {
codeMsg, ok := codeMap[code]
if !ok {
codeMsg = "未知错误"
}
response(c, code, nil, codeMsg)
}
go
package main
import "golang/res"
import "github.com/gin-gonic/gin"
func main() {
//初始化
r := gin.Default()
//挂载路由
r.GET("/index", func(c *gin.Context) {
// c.JSON(200, gin.H{
// "message": "Hello, World!",
// })
res.OkWithMsg(c, "这是一个成功的响应")
})
//挂载路由
r.GET("/user", func(c *gin.Context) {
res.OkWithData(c, gin.H{
"name": "张三",
"age": 30,
})
})
//绑定端口,启动服务
r.Run(":8080")
}
响应html
go
package main
import "github.com/gin-gonic/gin"
func main() {
//初始化
r := gin.Default()
r.LoadHTMLGlob("templates/*")
r.GET("/", func(c *gin.Context) {
//可很方便修改标题
c.HTML(200, "index.html", map[string]any{
"title": "Gin框架示例",
})
})
//绑定端口,启动服务
r.Run(":8080")
}
响应文件
用于浏览器直接请求这个接口唤起下载
go
package main
import "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=res/res.go") // 用来指定下载下来的文件名
c.File("res/res.go")
})
//绑定端口,启动服务
r.Run(":8080")
}
}
前端唤起浏览器下载的本质
<a href="文件地址" download="文件名">文件下载</a>
响应静态文件
go
package main
import "github.com/gin-gonic/gin"
func main() {
//初始化
r := gin.Default()
//加载静态文件
//注意:静态文件的路径,不能再被路由使用了
r.Static("st", "static")
//绑定端口,启动服务
r.Run(":8080")
}
请求
查询参数
?key=xxx&name=xxxx 这种就被称为查询参数
go
package main
import "github.com/gin-gonic/gin"
import "fmt"
func main() {
//初始化
r := gin.Default()
r.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")//动态参数
name := c.Query("name")//查询参数
fmt.Printf("id: %s, name: %s\n", id, name)
})
//绑定端口,启动服务
r.Run(":8080")
}
}
表单参数
go
package main
import "github.com/gin-gonic/gin"
import "fmt"
func main() {
//初始化
r := gin.Default()
r.POST("users", func(c *gin.Context) {
name := c.PostForm(key:"name")
age, ok := c.GetPostForm(key:"age")//判断是否传入了这个参数,无论是否有值
fmt.Println(name)
fmt.Println(age, ok)
})
//绑定端口,启动服务
r.Run(":8080")
}
上传文件
go
package main
import (
"fmt"
"io"
"os"
"github.com/gin-gonic/gin"
)
func main() {
//初始化
r := gin.Default()
r.POST("users", func(c *gin.Context) {
fileHeader, err := c.FormFile(name: "file")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(fileHeader.Filename) // 文件名
fmt.Println(fileHeader.Size) // 文件大小,单位是字节
// file, _ := fileHeader.Open()
// byteData, _ := io.ReadAll(file)
// err = os.WriteFile(name: "qill7.jpg", byteData, perm: 0666)
// fmt.Println(err)
err = c.SaveUploadedFile(fileHeader, "uploads/xxx/yyy/"+fileHeader.Filename)
fmt.Println(err)
})
//绑定端口,启动服务
r.Run(":8080")
}
多文件上传
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.POST(relativePath: "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)
}
}
})
r.Run(addr: ":8080")
}
bind绑定器
Gin 的 Bind 绑定器主要用于解析和验证 HTTP 请求中的参数,将请求数据绑定到 Go 的结构体(struct)中。
主要用途:
- 数据绑定
自动从请求中提取数据并填充到结构体:
从 URL 查询参数绑定
从 POST 表单数据绑定
从 JSON/XML 请求体绑定
从 URL 路径参数绑定- 数据验证
结合验证标签对数据进行验证
查询参数
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 user User
err := c.ShouldBindQuery(&user)
fmt.Println(user, err)
// 返回JSON响应
c.JSON(200, gin.H{
"name": user.Name,
"age": user.Age,
})
})
r.Run(":8080")
}
路径参数
go
type User struct {
Name string `uri:"name"`
ID int `uri:"id"`
}
var user User
err := c.ShouldBindUri(&user)
fmt.Println(user, err)
表单参数
注意:不能解析 x-www-form-urlencoded 的格式
go
type User struct {
Name string `form:"name"`
Age int `form:"age"`
}
var user User
err := c.ShouldBind(&user)
fmt.Println(user, err)
JSON参数
go
type User struct {
Name string `form:"name"`
Age int `form:"age"`
}
var user User
err := c.ShouldBindJSON(&user)
fmt.Println(user, err)
Header参数
go
type User struct {
Name string `header:"Name"`
Age int `header:"Age"`
UserAgent string `header:"User-Agent"`
}
var user User
err := c.ShouldBindHeader(&user)
fmt.Println(user, err)
内置规则
对传入的参数进行为空校验、枚举校验等
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=18"
gte 大于等于,如:binding:"gte=18"
lt 小于,如:binding:"lt=18"
lte 小于等于,如:binding:"lte=18"
// 针对同字段的值
eqfield 等于其他字段的值,如:Password string `binding:"eqfield=Password"`
nefield 不等于其他字段的值
// 忽略字段,如:binding:"-" 或者不写
-
// 枚举 只要是red或green
oneof=red green
自定义验证器
go
v.RegisterValidation(tag:"fip", func(fl validator.FieldLevel) bool {
fmt.Println(a...:"fl.Field(): ", fl.Field())
fmt.Println(a...:"fl.FieldName(): ", fl.FieldName())
fmt.Println(a...:"fl.StructFieldName(): ", fl.StructFieldName())
fmt.Println(a...:"fl.Parent(): ", fl.Parent())
fmt.Println(a...:"fl.Top(): ", fl.Top())
fmt.Println(a...:"fl.Param(): ", fl.Param())
ip, ok := fl.Field().Interface().(string)
if ok && ip != "" {
// 传了值就去校验是不是IP地址
ipObj := net.ParseIP(ip)
return ipObj != nil
}
return false
})
路由与中间件
go
func main() {
r := gin.Default()
r.POST()
r.GET()
r.PUT()
r.PATCH()
r.DELETE()
r.Any(relativePath: "")
}
路由分组
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
apiGroup := r.Group("api")
//绑定全局中间件
apiGroup.Use()
//可以分组多个同名的路由
//apiGroup3 := r.Group("api")
//apiGroup2 := r.Group("api")
//绑定实现方法
UserGroup(apiGroup)
r.Run(":8080")
}
//实现方法
func UserView(c *gin.Context) {
path := c.Request.URL
fmt.Println(path)
}
func UserGroup(r *gin.RouterGroup) {
r.GET("users", UserView)
r.POST("users", UserView)
r.DELETE("users", UserView)
r.PUT("users", UserView)
}
加入中间件
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 请求前(Let freedom ring!)")
c.Next()
fmt.Println("M1 请求后,即响应部分")
}
//中间件
func M2(c *gin.Context) {
fmt.Println("M2 请求")
c.Next()//放行
//c.Abort() 拦截
fmt.Println("M2 响应")
}
//局部中间件
func main() {
r := gin.Default()
r.GET("/",M1,M2,Home)
r.Run(":8080")
}
