Gin教程 Golang+Gin框架入门实战教程 大地老师

164 阅读6分钟

9-20012021415E39.jpg

Gin教程 Golang+Gin框架入门实战教程 大地老师

这个教程将分为三个部分:

  1. 第一部分:Gin入门基础 - 快速上手,了解核心概念。
  2. 第二部分:核心功能详解 - 深入路由、中间件、参数绑定等。
  3. 第三部分:项目实战 - 构建一个简单的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 来测试。

  1. 获取所有Todos:

    bash

    复制下载

    curl http://localhost:8080/api/v1/todos
    
  2. 创建一个新的Todo:

    bash

    复制下载

    curl -X POST -H "Content-Type: application/json" -d '{"title":"Buy milk"}' http://localhost:8080/api/v1/todos
    
  3. 更新一个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
    
  4. 删除一个Todo:

    bash

    复制下载

    curl -X DELETE http://localhost:8080/api/v1/todos/2
    

总结与下一步

通过这个教程,你已经掌握了Gin框架的核心:

  • ✅ 基础设置和启动
  • ✅ 路由定义
  • ✅ 获取各种请求参数
  • ✅ 强大的模型绑定
  • ✅ 自定义中间件
  • ✅ 构建一个完整的RESTful API

下一步学习建议(大地老师课程后续内容):

  1. 连接真实的数据库:如MySQL, PostgreSQL,使用GORM库。
  2. 用户认证与授权:实现JWT (JSON Web Token) 登录。
  3. 配置文件管理:使用Viper库管理不同环境的配置。
  4. 文件上传:处理单文件、多文件上传。
  5. 优雅关机与重启:保证服务在更新时不会中断现有请求。

希望这个浓缩版的“大地老师Gin教程”能帮助你快速入门Gin框架!实践是学习编程最好的方式,请务必动手敲一遍代码并进行修改。