Gin
1. Gin 介绍
Gin框架是一个基于Go语言的轻量级Web框架,对Go语言的HTTP包进一步封装,使得Web开发更加便捷高效。
2. 原生http库
通过以下代码可创建一个Go语言内置HTTP请求。
go
package main
import (
"fmt"
"io"
"net/http"
)
// 处理方法
func Index(writer http.ResponseWriter, request *http.Request) {
fmt.Println(request.Method, request.URL.String())
if request.Method != "GET" {
byteData, _ := io.ReadAll(request.Body)
fmt.Println(string(byteData))
}
fmt.Println("REQUEST HEADER: ", request.Header)
fmt.Println("REQUEST METHOD: ", request.Method)
fmt.Println("REQUEST URL: ", request.URL)
fmt.Println("REQUEST MULTIPART_FORM: ", request.MultipartForm)
fmt.Println("REQUEST REQUEST_URI: ", request.RequestURI)
writer.Write([]byte("Hello HTTP!"))
}
func main() {
http.HandleFunc("/index", Index)
fmt.Println("HTTP Server Start Running 127.0.0.1:8080")
http.ListenAndServe(":8080", nil)
}
Index函数中参数所属方法:


启动编写的单请求Web服务。

使用CURL命令发送GET请求。


使用Apifox发送GET请求。

3. Gin框架
为解决原生Go HTTP库繁琐问题(请求方式/JSON单独判断、错误返回),在此基础上编写了Gin框架。
3.1 导入Gin
安装三方库
go
go get github.com/gin-gonic/gin
访问失败

更换三方源
配置国内源命令 & 最好记忆的三方源(七牛云)
go
go env -w GOPROXY=https://goproxy.cn,direct
三方源
go
https://goproxy.cn,direct
https://mirrors.aliyun.com/goproxy/
https://goproxy.tuna.tsinghua.edu.cn
访问成功

3.2 了解Gin
Gin程序固定步骤:初始化 → 路由 → 监听运行
Context结构体

编写简单服务
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: "成功",
Data: map[string]any{},
})
}
func main() {
// 1. 初始化
r := gin.Default()
// 2. 挂载路由
r.GET("/index", Index)
// 3. 绑定端口 运行
r.Run(":8080")
}


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: "成功",
Data: map[string]any{},
})
}
func main() {
// 1. 初始化
gin.setMode("release") // 关闭DEBUG日志
r := gin.Default()
// 2. 挂载路由
r.GET("/index", Index)
// 3. 绑定端口 运行
r.Run(":8080") // 内网运行 --> 等价于r.Run("0.0.0.0:8080")
// r.Run("127.0.0.1:8080") // 本机运行 --> 等价于r.Run("0.0.0.0:8080")
}
4. 响应:文件 - 封装
4.1 响应JSON
目前大部分前后端交互都是以JSON为主。
但是一般不会直接返回JSON,会对其进行封装,定义一种标准的返回格式:code / data /msg
前端可以根据code判断操作是否成功,不同公司不同定义。
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{"code": 0, "msg": "成功", "data": gin.H{}})
})
r.Run()
}
一般除服务器软硬件错误,状态码默认为200,业务操作逻辑利用Response中的业务码code进行表示。
在res包内定义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: 0,
Msg: msg,
Data: data,
})
}
func Ok(c *gin.Context, data any, msg string) {
response(c, 2001, data, msg)
}
func OkWithData(c *gin.Context, data any) {
response(c, 2001, data, "成功")
}
func OkWithMsg(c *gin.Context, msg string) {
response(c, 2001, gin.H{}, 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, gin.H{}, msg)
}
func FailWithCode(c *gin.Context, code int) {
msg, ok := codeMap[code]
if !ok {
msg = "服务错误"
}
response(c, code, gin.H{}, msg)
}
Gin代码
go
package main
import (
"gin_study/response/res"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/index", func(c *gin.Context) {
res.OkWithMsg(c, "成功进入首页!")
})
r.GET("/user", func(c *gin.Context) {
res.OkWithData(c, map[string]any{
"UserName": "Mike",
"Gender": 0,
})
})
r.Run()
}
利用Apifox发起GET请求


服务器响应GET请求

4.2 响应html
go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.LoadHTMLGlob("response/templates/*")
// r.LoadHTMLFiles("response/templates/index.html")
r.GET("", func(c *gin.Context) {
c.HTML(200, "index.html", nil)
})
r.Run(":8080")
}

go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.LoadHTMLGlob("response/templates/*")
// r.LoadHTMLFiles("response/templates/index.html")
r.GET("", func(c *gin.Context) {
c.HTML(200, "index.html", map[string]any{
"title": "新的首页",
"context": "内容",
})
})
r.Run(":8080")
}


关于部署:
- 前端单独部署,后端单独部署
- 前端打包完成,后端统一部署
4.3 响应文件
用于浏览器直接发起下载请求
go
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename=index.html")
c.File("response/templates/index.html")
完整代码
go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
// r.LoadHTMLFiles("response/templates/index.html")
r.GET("", func(c *gin.Context) {
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename=index.html")
c.File("response/templates/index.html")
})
r.Run(":8080")
}


当指定文件不存在时则会出现404
前端请求后端接口,唤起浏览器下载
go
c.Header("filename", "xxx.png")
c.Header("msg", "文件下载成功")
c.File("response/templates/xxx.png")
唤起本质
go
<a href="文件地址" download="文件名">文件下载</a>
前端调用下载接口请求,后端返回文件下载地址而不直接返回文件,前端构造需点击元素唤起下载。
4.4 静态文件
静态文件路径不能再被路由使用
go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.Static("st", "response/static")
// r.StaticFile("abx", "response/static/abc.txt")
r.Run(":8080")
}



5. 请求:参数/文件 - 接口
5.1 查询参数
查询参数
- 示例:
?key1=value1&key1=value2&key3=value3(同一key可重复多个value) - 并非GET请求专属
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")
gender := c.DefaultQuery("gender", "22")
books := c.QueryArray("books")
fmt.Println(name, gender, books)
})
r.Run(":8080")
}


5.2 动态参数
用户个人信息
go
/users?id=123 // 查询参数模式
/users/123 // 动态参数模式
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("users/:id/:name", func(c *gin.Context) {
id := c.Param("id")
name := c.Param("name")
fmt.Println(id, name)
})
r.Run(":8080")
}


5.3 表单参数
POST请求Form表单
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.POST("users", func(c *gin.Context) {
id := c.PostForm("id")
name, nameOk := c.GetPostForm("name")
fmt.Println(id)
fmt.Println(name, nameOk)
})
r.Run(":8080")
}


5.5 文件上传
单文件上传
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("File Header : ", fileHeader.Filename) // 文件名
fmt.Println("File Size : ", fileHeader.Size) // 文件大小 单位字节
file, _ := fileHeader.Open() // 第二个参数是error类型
byteData, _ := io.ReadAll(file) // 第二个参数是error类型
err = os.WriteFile("xxx.png", byteData, 0777)
fmt.Println(err)
})
r.Run(":8080")
}


对上传的文件的封装方法如下。
go
//file, _ := fileHeader.Open() // 第二个参数是error类型
//byteData, _ := io.ReadAll(file) // 第二个参数是error类型
//err = os.WriteFile("xxx.png", byteData, 0777)
//fmt.Println(err)
// 等效代码
err = c.SaveUploadedFile(fileHeader, "uploads/yyy/"+fileHeader.Filename)
fmt.Println(err)

多文件上传
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
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/zzz/"+header.Filename)
}
}
})
r.Run(":8080")
}


5.6 原始内容
不同请求体对应的原始内容
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阅后即焚,使用bytes.NewReader可解决此问题
c.Request.Body = io.NopCloser(bytes.NewReader(byteData))
name := c.PostForm("name")
fmt.Println("name", name)
})
r.Run(":8080")
}

form-data
go
----------------------------001246823629557183212734
Content-Disposition: form-data; name="name"
你好
----------------------------001246823629557183212734
Content-Disposition: form-data; name="age"
32
----------------------------001246823629557183212734--
x-www-form-urlencoded
url编码
go
name=abc&age=35
json
go
{
"name": "xyz",
"age": 12
}
※ 接口测试工具
常用工具:Postman / Apifox
- get加请求体
- ws加请求头
6. bind绑定器
6.1 绑定参数
使用binding可以完成参数绑定,不能对x-www-form-urlencoded进行解析。
6.1.1 查询参数
go
package bind
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)
})
r.Run(":8080")
}
6.1.2 路径参数
go
package bind
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("users/:id/:name", func(c *gin.Context) {
type User struct {
Name string `uri:"name"`
ID int `uri:"id"`
}
var user User
err := c.ShouldBindQuery(&user)
fmt.Println(user, err)
})
r.Run(":8080")
}
6.1.3 表单参数
go
package bind
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.POST("form", func(c *gin.Context) {
type User struct {
Name string `form:"name"`
ID int `form:"id"`
}
var user User
err := c.ShouldBind(&user)
fmt.Println(user, err)
})
r.Run(":8080")
}
6.1.4 json参数
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("json", func(c *gin.Context) {
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
var user User
err := c.ShouldBindJSON(&user)
fmt.Println(user, err)
})
r.Run(":8080")
}
6.1.5 header参数
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("header", func(c *gin.Context) {
type User struct {
Name string `header:"Name"`
Age int `header:"Age"`
UserAgent string `header:"UserAgent"`
}
var user User
err := c.ShouldBindHeader(&user)
fmt.Println(user, err)
})
r.Run(":8080")
}
6.2 binding内置规则
多条不同规则可以以逗号间隔
go
// 全局
require 必填字段 不为空+不消失
- 忽略字段 binding:"-" 或 不写
// 字符串
min 最小长度 binding:"min=5"
max 最大长度 binding:"max=5"
len 长度 binding:"len=5"
contains 包含
excludes 不包含
startwith 字符串前缀
endswith 字符串后缀
// 数字
eq 等于 binding:"eq=3"
ne 等于
gt 大于
ge 大于等于
lt 小于
lte 小于等于
// 同级字段
eqfield 等于其他字段的值 Password string `binding:"eqfield=Password"`
nefield 不等于其他字段的值
// 网络验证
ip
ipv4
ipv6
uri Identifier 统一资源标识符 标识唯一资源
url Locator 统一资源定位符 提供资源路径
email 邮箱校验
// 日期验证
datetime=2026-01-26
// 枚举(仅限设定的选项)
oneof=item1 item2
// 校验数组
dive
6.3 binding错误信息显示中文
go
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/zh"
"github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
"strings"
)
var trans ut.Translator
func init() {
// 创建翻译器
uni := ut.New(zh.New())
trans, _ = uni.GetTranslator("zh")
// 注册翻译器
v, ok := binding.Validator.Engine().(*validator.Validate)
if ok {
_ = zh_translations.RegisterDefaultTranslations(v, trans)
}
}
func ValidateErr(err error) string {
errs, ok := err.(validator.ValidationErrors)
if !ok {
return err.Error()
}
var list []string
for _, e := range errs {
list = append(list, e.Translate(trans))
}
return strings.Join(list, ";")
}
type User struct {
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"required,email"`
}
func main() {
r := gin.Default()
// 注册路由
r.POST("/user", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
// 参数验证失败
c.String(200, ValidateErr(err))
}
})
// 启动HTTP服务器
r.Run()
}

6.4 binding显示错误字段及信息
返回字符串
go
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/zh"
"github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
"reflect"
"strings"
)
var trans ut.Translator
func init() {
// 创建翻译器
uni := ut.New(zh.New())
trans, _ = uni.GetTranslator("zh")
// 注册翻译器
v, ok := binding.Validator.Engine().(*validator.Validate)
if ok {
_ = zh_translations.RegisterDefaultTranslations(v, trans)
}
v.RegisterTagNameFunc(func(field reflect.StructField) string {
label := field.Tag.Get("label")
if label == "" {
return field.Name
}
return label
})
}
func ValidateErr(err error) string {
errs, ok := err.(validator.ValidationErrors)
if !ok {
return err.Error()
}
var list []string
for _, e := range errs {
list = append(list, e.Translate(trans))
}
return strings.Join(list, ";")
}
type User struct {
Name string `json:"name" binding:"required" label:"用户名"`
Email string `json:"email" binding:"required,email" label:"邮箱"`
}
func main() {
r := gin.Default()
// 注册路由
r.POST("/user", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
// 参数验证失败
c.String(200, ValidateErr(err))
}
})
// 启动HTTP服务器
r.Run(":8080")
}

JSON化
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/zh"
"github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
"reflect"
"strings"
)
var trans ut.Translator
func init() {
// 创建翻译器
uni := ut.New(zh.New())
trans, _ = uni.GetTranslator("zh")
// 注册翻译器
v, ok := binding.Validator.Engine().(*validator.Validate)
if ok {
_ = zh_translations.RegisterDefaultTranslations(v, trans)
}
v.RegisterTagNameFunc(func(field reflect.StructField) string {
label := field.Tag.Get("label")
if label == "" {
return field.Name
}
attr := field.Tag.Get("json")
label = fmt.Sprintf("%s--%s", attr, label)
return label
})
}
func ValidateErr(err error) any {
errs, ok := err.(validator.ValidationErrors)
if !ok {
return err.Error()
}
var _list []string
var m = map[string]any{}
for _, e := range errs {
msg := e.Translate(trans)
_list = strings.Split(msg, "--")
m[_list[0]] = _list[1]
}
return m
}
type User struct {
Name string `json:"name" binding:"required" label:"用户名"`
Email string `json:"email" binding:"required,email" label:"邮箱"`
}
func main() {
r := gin.Default()
// 注册路由
r.POST("/user", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
// 参数验证失败
c.JSON(200, map[string]any{
"code": 7,
"msg": "验证错误",
"data": ValidateErr(err),
})
}
})
// 启动HTTP服务器
r.Run(":8080")
}

7.自定义验证
go
v.RegisterValidation("fip", func(fl validator.FieldLevel) bool {
这种验证方式参数fl的方法如下

go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/zh"
"github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
"net"
"net/http"
"reflect"
"strings"
)
var trans ut.Translator
func init() {
// 创建翻译器
uni := ut.New(zh.New())
trans, _ = uni.GetTranslator("zh")
// 注册翻译器
v, ok := binding.Validator.Engine().(*validator.Validate)
if ok {
_ = zh_translations.RegisterDefaultTranslations(v, trans)
}
v.RegisterTagNameFunc(func(field reflect.StructField) string {
label := field.Tag.Get("label")
if label == "" {
return field.Name
}
attr := field.Tag.Get("json")
label = fmt.Sprintf("%s--%s", attr, label)
return label
})
v.RegisterValidation("fip", func(fl validator.FieldLevel) bool {
fmt.Println("fl.Field() : ", fl.Field())
fmt.Println("fl.FieldName() : ", fl.FieldName())
fmt.Println("fl.StructFieldName() : ", fl.StructFieldName())
fmt.Println("fl.Parent() : ", fl.Parent())
fmt.Println("fl.Top() : ", fl.Top()) // 顶层 JSON内部可以嵌套很多层
fmt.Println("fl.Param() : ", fl.Param())
ip, ok := fl.Field().Interface().(string)
if ok && ip != "" {
ipObj := net.ParseIP(ip)
return ipObj != nil
}
return false
})
}
func ValidateErr(err error) any {
errs, ok := err.(validator.ValidationErrors)
if !ok {
return err.Error()
}
var _list []string
var m = map[string]any{}
for _, e := range errs {
msg := e.Translate(trans)
_list = strings.Split(msg, "--")
m[_list[0]] = _list[1]
}
return m
}
type User struct {
Ip string `json:"ip" binding:"fip" label:"ip地址"`
}
func main() {
r := gin.Default()
// 注册路由
r.POST("/user", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
// 参数验证失败
c.JSON(200, map[string]any{
"code": 7,
"msg": "验证错误",
"data": ValidateErr(err),
})
}
c.JSON(http.StatusOK, user)
})
// 启动HTTP服务器
r.Run(":8080")
}



8. 路由
路由规范
go
r := gin.Default()
r.POST() // 提交数据
r.GET() // 获取/下载数据
r.PUT() // 全量更新数据
r.PATCH() // 增量更新数据
r.DELETE() // 删除数据
r.any() //【支持所有】
r.Group("api") // 分组
路由组可以重名以区分是否添加中间件
go
apiGroup := r.Group("api")
apiGroup.Use()
UserGroup(apiGroup)
noMiddleWareGroup := r.Group("api")
LoginGroup(noMiddleWareGroup)
9. 中间件
可以近似理解为 "过滤器"、"拦截器",可以有多个中间件,作用:拦截 / 处理 / 放行。
9.1 局部中间件【PPT示意图】
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func Home(c *gin.Context) {
fmt.Println("Home")
c.String(200, "Home")
}
// 局部中间件1
func MiddleWare1(c *gin.Context) {
fmt.Println("MiddleWare 1 请求部分")
c.Next()
fmt.Println("MiddleWare 1 响应部分")
}
// 局部中间件2
func MiddleWare2(c *gin.Context) {
fmt.Println("MiddleWare 2 请求部分")
c.Next()
fmt.Println("MiddleWare 2 响应部分")
}
func main() {
r := gin.Default()
r.GET("", MiddleWare1, MiddleWare2, Home)
r.Run(":8080")
}
9.2 全局中间件
全局即路由组,这使得中间件设置更为便捷。
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func Home(c *gin.Context) {
fmt.Println("Home")
c.String(200, "Home")
}
// 全局中间件1
func GroupMiddleWare1(c *gin.Context) {
fmt.Println("GroupMiddleWare 1 请求")
c.Next()
c.String(200, "MiddleWare 1 响应")
return
}
// 全局中间件2
func GroupMiddleWare2(c *gin.Context) {
fmt.Println("GroupMiddleWare 2 请求")
c.Next()
c.String(200, "MiddleWare 2 响应")
return
}
func main() {
r := gin.Default()
g := r.Group("api")
g.Use(GroupMiddleWare1, GroupMiddleWare2)
// 等同于 g.Use(GroupMiddleWare1) + g.Use(GroupMiddleWare2)
g.GET("users", Home)
r.Run(":8080")
}
9.3 中间件操作
9.3.1 中间件放行
go
func MiddleWare1(c *gin.Context) {
fmt.Println("MiddleWare 1 请求部分")
c.Next()
fmt.Println("MiddleWare 1 响应部分")
}
func MiddleWare2(c *gin.Context) {
fmt.Println("MiddleWare 2 请求部分")
c.Next()
fmt.Println("MiddleWare 2 响应部分")
}

9.3.2 中间件中断
go
func MiddleWare1(c *gin.Context) {
fmt.Println("MiddleWare 1 请求部分")
c.Abort()
fmt.Println("MiddleWare 1 响应部分")
}
func MiddleWare2(c *gin.Context) {
fmt.Println("MiddleWare 2 请求部分")
c.Next()
fmt.Println("MiddleWare 2 响应部分")
}

9.3.3 中间件响应
go
func MiddleWare1(c *gin.Context) {
fmt.Println("MiddleWare 1 请求部分")
c.Abort()
c.String(200, "MiddleWare 1 响应")
return
}
func MiddleWare2(c *gin.Context) {
fmt.Println("MiddleWare 2 请求部分")
c.Next()
fmt.Println("MiddleWare 2 响应部分")
}


9.3 中间件传参
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func Home(c *gin.Context) {
fmt.Println("Home")
c.Get("name")
c.Get("classmate")
c.String(200, "Home")
}
func GroupMiddleWare1(c *gin.Context) {
fmt.Println("GroupMiddleWare 1 请求")
// 可以传递所有Go支持类型
c.Set("name", "Your Dream Name")
c.Next()
c.String(200, "MiddleWare 1 响应")
return
}
func GroupMiddleWare2(c *gin.Context) {
fmt.Println("GroupMiddleWare 2 请求")
c.Set("classmate", "Your Dream Classmate")
c.Next()
c.String(200, "MiddleWare 2 响应")
return
}
func main() {
r := gin.Default()
g := r.Group("api")
g.Use(GroupMiddleWare1, GroupMiddleWare2)
g.GET("users", Home)
r.Run(":8080")
}


10. Gin框架项目
简单模板
go
├── cmd/ # 项目入口目录
│ └── main.go # 主程序入口
├── internal/ # 私有代码目录
│ ├── handler/ # HTTP处理器(Controller)
│ │ └── user.go
│ ├── service/ # 业务逻辑层
│ │ └── user.go
│ ├── repository/ # 数据访问层(DAO)
│ │ └── user.go
│ └── model/ # 数据模型
│ └── user.go
├── pkg/ # 可被外部引用的包
│ ├── middleware/ # 中间件
│ ├── config/ # 配置
│ └── utils/ # 工具函数
├── api/ # API文档(Swagger/OpenAPI)
│ └── swagger.json
├── configs/ # 配置文件目录
│ └── config.yaml
├── scripts/ # 构建、部署脚本
├── test/ # 测试文件目录
└── go.mod # Go模块文件
复杂模板
go
project-root-directory/
├── cmd/
│ └── main.go
├── config/
│ ├── config.yaml
│ └── ...
├── handlers/
│ └── hello.go
├── internal/
│ ├── pkg/
│ │ ├── mypackage/
│ │ │ ├── mypackage.go
│ │ │ └── mypackage_test.go
│ │ └── ...
│ └── ...
├── models/
│ └── user.go
├── routes/
│ └── routes.go
├── repository/
│ ├── rediskeys/
│ │ └── ...
│ ├── couchbaseQuery/
│ │ └── ...
│ └── ...
├── services/
│ └── ...
├── utils/
│ └── ...
├── static/
├── templates/
├── tests/
│ ├── unit/
│ │ └── hello_test.go
│ └── ...
├── go.mod
├── go.sum
├── README.md
└── ...
- cmd :存放程序的入口文件,通常是
main.go。 - config :存放配置文件,如
config.yaml。 - handlers:处理请求和响应的处理器,类似于Spring Boot中的controller层。
- internal:存放项目特定的包,这些包不打算被外部应用程序或库使用。
- models:定义数据库模型和数据结构,类似于DAO层。
- routes:定义路由和中间件,组织项目的路由逻辑。
- repository:包含数据库访问和数据检索逻辑,封装与数据库的交互。
- services:业务逻辑层,处理具体的业务逻辑。
- utils:存放工具函数和帮助函数,用于代码复用。
- static:存放静态资源,如CSS、JavaScript文件和图片。
- templates:存放HTML模板文件。
- tests:存放测试代码,如单元测试。
两个经典模板
-
Go-Clean-Template:遵循清晰架构的Gin项目模板 Star数7k+

-
Gin-Vue-Admin:完整的前后端分离权限管理系统 由Gin+Vue实现 Star数24k+
