这个教程将分为三个部分:
- 第一部分:Gin入门基础 - 快速上手,了解核心概念。
- 第二部分:核心功能详解 - 深入路由、中间件、参数绑定等。
- 第三部分:项目实战 - 构建一个简单的RESTful API。
第一部分:Gin入门基础
1. 环境准备与安装
确保你已经安装了Go(1.16+版本推荐)。
bash
复制下载
# 1. 初始化你的项目模块
go mod init gin-tutorial
# 2. 下载Gin框架
go get -u github.com/gin-gonic/gin
2. 第一个Gin应用:Hello Gin!
创建一个 main.go 文件。
go
复制下载
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
// 1. 创建一个默认的路由引擎
r := gin.Default()
// 2. 定义一个GET路由
// 路径:/hello
// 处理函数:当访问/hello时,执行这个匿名函数
r.GET("/hello", func(c *gin.Context) {
// c.JSON 返回一个JSON格式的数据
// 200 是HTTP状态码
// gin.H 是一个map[string]interface{}的快捷方式
c.JSON(200, gin.H{
"message": "Hello Gin!",
})
})
// 3. 启动HTTP服务,默认在 0.0.0.0:8080 上监听
// 也可以使用 r.Run(":9090") 来指定端口
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
运行并测试:
bash
复制下载
go run main.go
然后用浏览器访问 http://localhost:8080/hello,或者使用curl:
bash
复制下载
curl http://localhost:8080/hello
你会看到返回 {"message":"Hello Gin!"}。
第二部分:核心功能详解
1. 路由
Gin支持所有标准HTTP方法。
go
复制下载
func main() {
r := gin.Default()
r.GET("/get", func(c *gin.Context) {
c.String(200, "This is a GET request")
})
r.POST("/post", func(c *gin.Context) {
c.String(200, "This is a POST request")
})
r.PUT("/put", func(c *gin.Context) {
c.String(200, "This is a PUT request")
})
r.DELETE("/delete", func(c *gin.Context) {
c.String(200, "This is a DELETE request")
})
r.Run()
}
2. 获取请求参数
这是Web框架的核心功能之一。
- 路径参数 (Path Parameters)
go
复制下载
// 冒号(:)后面是参数名
r.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name") // 获取路径参数
c.String(200, "Hello %s", name)
})
// 访问 /user/zhangsan -> Hello zhangsan
// 通配符路径参数
r.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
c.String(200, "%s is doing %s", name, action)
})
// 访问 /user/zhangsan/sleep -> zhangsan is doing /sleep
- 查询字符串 (Query String)
go
复制下载
// /welcome?firstname=Li&lastname=Si
r.GET("/welcome", func(c *gin.Context) {
// 使用 DefaultQuery,如果没有则返回默认值
firstname := c.DefaultQuery("firstname", "Guest")
// 使用 Query,如果没有则返回空字符串
lastname := c.Query("lastname")
c.String(200, "Hello %s %s", firstname, lastname)
})
- 表单参数 (Form Data)
go
复制下载
// POST /form_post
// Content-Type: application/x-www-form-urlencoded
// message=hello&nick=gin_fan
r.POST("/form_post", func(c *gin.Context) {
message := c.PostForm("message")
nick := c.DefaultPostForm("nick", "anonymous") // 默认值
c.JSON(200, gin.H{
"status": "posted",
"message": message,
"nick": nick,
})
})
3. 参数绑定 (Model Binding)
Gin提供了一个非常强大的功能,可以将请求体(JSON, XML, Form等)直接绑定到Go的结构体(Struct)。
go
复制下载
// 定义一个结构体,使用标签(tag)来映射请求参数
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func main() {
r := gin.Default()
// 绑定JSON的示例 ({"user": "root", "password": "123"})
r.POST("/loginJSON", func(c *gin.Context) {
var login Login
// ShouldBindJSON 将请求体中的JSON绑定到 login 变量
if err := c.ShouldBindJSON(&login); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return // 如果绑定失败,直接返回错误
}
// 绑定成功,使用结构体中的数据
if login.User == "root" && login.Password == "123" {
c.JSON(200, gin.H{"status": "login success"})
} else {
c.JSON(401, gin.H{"status": "unauthorized"})
}
})
// 同样可以绑定Form数据
r.POST("/loginForm", func(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err != nil { // ShouldBind 会根据Content-Type自动判断
c.JSON(400, gin.H{"error": err.Error()})
return
}
// ... 后续逻辑
})
r.Run()
}
4. 中间件 (Middleware)
中间件是Gin的精髓。它是在请求到达最终处理函数之前或之后执行的函数。
-
使用内置中间件
gin.Default()默认使用了Logger和Recovery中间件。Logger: 记录每个请求的日志。Recovery: 从任何Panic中恢复,确保服务不会崩溃。
-
自定义中间件
go
复制下载
// 一个简单的统计请求耗时的中间件
func StatCost() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
// 在请求之前执行
fmt.Println("中间件开始执行")
// 调用该请求的剩余处理程序
c.Next()
// 在请求之后执行
cost := time.Since(start)
fmt.Printf("本次请求耗时:%v\n", cost)
}
}
func main() {
r := gin.New() // 不使用任何默认中间件
// r := gin.Default() // 使用默认中间件
// 全局使用中间件
r.Use(StatCost())
r.GET("/test", func(c *gin.Context) {
time.Sleep(100 * time.Millisecond) // 模拟业务处理耗时
c.JSON(200, gin.H{"message": "test"})
})
r.Run()
}
第三部分:项目实战:构建一个简单的RESTful API
我们来构建一个管理“待办事项”(Todo)的简单API。
项目结构:
text
复制下载
gin-tutorial/
├── go.mod
├── go.sum
└── main.go
main.go 完整代码:
go
复制下载
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// 定义Todo模型
type Todo struct {
ID string `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
// 模拟一个内存数据库
var todos = []Todo{
{ID: "1", Title: "Learn Go", Completed: false},
{ID: "2", Title: "Build a RESTful API with Gin", Completed: false},
}
func main() {
r := gin.Default()
// 路由组,API路径都以 /api/v1 开头
v1 := r.Group("/api/v1")
{
todosGroup := v1.Group("/todos")
{
// 获取所有Todo
todosGroup.GET("", getTodos)
// 根据ID获取单个Todo
todosGroup.GET("/:id", getTodo)
// 创建一个新的Todo
todosGroup.POST("", createTodo)
// 更新一个Todo
todosGroup.PUT("/:id", updateTodo)
// 删除一个Todo
todosGroup.DELETE("/:id", deleteTodo)
}
}
r.Run(":8080")
}
// --- 控制器(Handler)函数 ---
// 获取所有Todo
func getTodos(c *gin.Context) {
c.JSON(http.StatusOK, todos)
}
// 根据ID获取单个Todo
func getTodo(c *gin.Context) {
id := c.Param("id")
for _, todo := range todos {
if todo.ID == id {
c.JSON(http.StatusOK, todo)
return
}
}
// 如果没找到
c.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"})
}
// 创建Todo
func createTodo(c *gin.Context) {
var newTodo Todo
// 绑定客户端发送的JSON数据到newTodo
if err := c.ShouldBindJSON(&newTodo); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 简单的ID生成(生产环境请勿使用!)
// 在实际项目中,ID通常由数据库自动生成
newTodo.ID = string(rune(len(todos) + 1))
todos = append(todos, newTodo)
c.JSON(http.StatusCreated, newTodo)
}
// 更新Todo
func updateTodo(c *gin.Context) {
id := c.Param("id")
var updatedTodo Todo
if err := c.ShouldBindJSON(&updatedTodo); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
for i, todo := range todos {
if todo.ID == id {
// 更新找到的Todo
updatedTodo.ID = id // 确保ID不被修改
todos[i] = updatedTodo
c.JSON(http.StatusOK, updatedTodo)
return
}
}
c.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"})
}
// 删除Todo
func deleteTodo(c *gin.Context) {
id := c.Param("id")
for i, todo := range todos {
if todo.ID == id {
// 从切片中删除元素
todos = append(todos[:i], todos[i+1:]...)
c.JSON(http.StatusOK, gin.H{"message": "Todo deleted"})
return
}
}
c.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"})
}
测试API:
你可以使用 curl 或 Postman 来测试。
-
获取所有Todos:
bash
复制下载
curl http://localhost:8080/api/v1/todos -
创建一个新的Todo:
bash
复制下载
curl -X POST -H "Content-Type: application/json" -d '{"title":"Buy milk"}' http://localhost:8080/api/v1/todos -
更新一个Todo (将ID=1的标记为完成):
bash
复制下载
curl -X PUT -H "Content-Type: application/json" -d '{"title":"Learn Go", "completed": true}' http://localhost:8080/api/v1/todos/1 -
删除一个Todo:
bash
复制下载
curl -X DELETE http://localhost:8080/api/v1/todos/2
总结与下一步
通过这个教程,你已经掌握了Gin框架的核心:
- ✅ 基础设置和启动
- ✅ 路由定义
- ✅ 获取各种请求参数
- ✅ 强大的模型绑定
- ✅ 自定义中间件
- ✅ 构建一个完整的RESTful API
下一步学习建议(大地老师课程后续内容):
- 连接真实的数据库:如MySQL, PostgreSQL,使用GORM库。
- 用户认证与授权:实现JWT (JSON Web Token) 登录。
- 配置文件管理:使用Viper库管理不同环境的配置。
- 文件上传:处理单文件、多文件上传。
- 优雅关机与重启:保证服务在更新时不会中断现有请求。
希望这个浓缩版的“大地老师Gin教程”能帮助你快速入门Gin框架!实践是学习编程最好的方式,请务必动手敲一遍代码并进行修改。