30天学会Go--第8天 GO语言 Gin Web框架学习与实践

30天学会Go--第8天 GO语言 Gin Web框架学习与实践

文章目录

  • [30天学会Go--第8天 GO语言 Gin Web框架学习与实践](#30天学会Go--第8天 GO语言 Gin Web框架学习与实践)
    • 前言
    • [一、Gin 的简介与安装](#一、Gin 的简介与安装)
      • [1.1 Gin 的特点](#1.1 Gin 的特点)
      • [1.2 安装 Gin](#1.2 安装 Gin)
    • [二、Gin 的基础用法](#二、Gin 的基础用法)
      • [2.1 路由](#2.1 路由)
        • [2.1.1 基本路由](#2.1.1 基本路由)
        • [2.1.2 路由参数](#2.1.2 路由参数)
        • [2.1.3 查询参数](#2.1.3 查询参数)
        • [2.1.4 路由分组](#2.1.4 路由分组)
      • [2.2 中间件](#2.2 中间件)
        • [2.2.1 使用内置中间件](#2.2.1 使用内置中间件)
        • [2.2.2 自定义中间件](#2.2.2 自定义中间件)
        • [2.2.3 路由级中间件](#2.2.3 路由级中间件)
      • [2.3 请求与响应](#2.3 请求与响应)
        • [2.3.1 绑定请求参数](#2.3.1 绑定请求参数)
        • [2.3.2 返回 JSON](#2.3.2 返回 JSON)
        • [2.3.3 返回文件](#2.3.3 返回文件)
      • [2.4 错误处理](#2.4 错误处理)
    • [三、Gin 实践:构建一个简单的 RESTful API](#三、Gin 实践:构建一个简单的 RESTful API)
      • [3.1 项目需求](#3.1 项目需求)
      • [3.2 项目结构](#3.2 项目结构)
      • [3.3 实现代码](#3.3 实现代码)
        • [3.3.1 数据模型](#3.3.1 数据模型)
        • [3.3.2 路由与控制器](#3.3.2 路由与控制器)
      • [3.4 功能验证](#3.4 功能验证)
        • [1. 获取用户列表](#1. 获取用户列表)
        • [2. 获取单个用户](#2. 获取单个用户)
        • [3. 创建用户](#3. 创建用户)
        • [4. 更新用户](#4. 更新用户)
        • [5. 删除用户](#5. 删除用户)
    • 四、总结

前言

Gin 是一个高性能的 Go Web 框架,基于 HTTP 路由和中间件设计,支持快速开发 Web 应用和 RESTful API。本篇文章将带你快速学习 Gin 的基本用法,并通过实践构建一个简单的 Web 应用。

Gin框架官方编程指南:文档 | Gin Web Framework

Gin框架的官方中文文档学习笔记很全,推荐去官网学习

30天学会GO--第6天 GO语言 RESTful API 学习与实践:30天学会Go--第6天 GO语言 RESTful API 学习与实践-CSDN博客

30天学会Go--第7天 GO语言 Redis 学习与实践:30天学会Go--第7天 GO语言 Redis 学习与实践-CSDN博客


一、Gin 的简介与安装

1.1 Gin 的特点

  • 高性能 :Gin 基于 net/http 构建,性能极高。
  • 简洁易用:提供了清晰的 API,开发体验良好。
  • 中间件支持:支持自定义中间件,灵活扩展功能。
  • 内置功能丰富:如路由分组、参数绑定、JSON 处理、错误处理等。
  • 社区活跃:文档完善,生态丰富。

1.2 安装 Gin

在开始使用 Gin 之前,需要在项目中安装 Gin 包。

运行以下命令安装:

bash 复制代码
go get -u github.com/gin-gonic/gin

安装完成后,创建一个简单的 Gin 应用以验证安装是否成功:

go 复制代码
package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default() // 创建一个默认的 Gin 引擎,Default函数会设置一些中间件,比如logger和recovery(用于处理panic)

	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello, Gin!",
		})
	})

	r.Run(":8080") // 启动服务,监听 8080 端口
}

运行程序后,访问 http://localhost:8080,如果返回 {"message":"Hello, Gin!"},说明 Gin 安装成功。


二、Gin 的基础用法

2.1 路由

路由是 Gin 的核心功能之一,用于定义 HTTP 请求的处理逻辑。

2.1.1 基本路由

使用 GETPOSTPUTDELETE 等方法定义路由:

go 复制代码
r.GET("/ping", func(c *gin.Context) {
	c.JSON(200, gin.H{   
		"message": "pong",
	})  // 构建并发送一个JSON响应给客户端。状态码200表示成功,gin.H是一个map类型,用于构建JSON对象。
})
2.1.2 路由参数

支持动态路由参数:

go 复制代码
r.GET("/user/:id", func(c *gin.Context) {
	id := c.Param("id") // 获取路径参数
	c.JSON(200, gin.H{
		"user_id": id,
	})
})
2.1.3 查询参数

通过 Query 获取 URL 查询参数:

go 复制代码
r.GET("/search", func(c *gin.Context) {
	query := c.Query("q") // 获取查询参数 q
	page := c.DefaultQuery("page", "1") // 获取查询参数 page,默认值为 1
	c.JSON(200, gin.H{
		"query": query,
		"page":  page,
	})
})

注意:

  • id := c.Param("id"):这一行是用来获取URL路径参数(Path Parameter)。在定义路由时,使用冒号(:)标记的参数,如/user/:id中的id,即为路径参数。当访问诸如/user/123的URL时,c.Param("id")会返回字符串"123"`。路径参数通常用于标识资源的唯一标识符。
  • query := c.Query("q"):这一行则是用来获取查询字符串(Query String)中的参数。查询字符串是URL中?后面的部分,例如,在URL`由于安全原因,超链接被移除
  • 总结来说,c.Param用于获取路径中的动态部分,而c.Query则用于获取URL的查询字符串参数。两者都是从HTTP请求中提取数据的方式,但针对的数据位置不同。
2.1.4 路由分组

使用路由分组管理 API:

go 复制代码
api := r.Group("/api")
{
	api.GET("/users", func(c *gin.Context) {
		c.JSON(200, gin.H{"message": "List of users"})
	})
	api.POST("/users", func(c *gin.Context) {
		c.JSON(201, gin.H{"message": "User created"})
	})
}

2.2 中间件

中间件是 Gin 的重要特性,用于在请求处理的前后执行额外的逻辑,比如日志、认证等。

2.2.1 使用内置中间件

Gin 提供了一些内置中间件,如日志和恢复中间件:

go 复制代码
r := gin.Default() // 默认包含 Logger 和 Recovery 中间件
2.2.2 自定义中间件

可以编写自定义中间件,下面是一个简单的 Gin 中间件示例,用于基于 Authorization 头部的值进行身份验证:

go 复制代码
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取 HTTP 请求头中的 Authorization 字段
		token := c.GetHeader("Authorization")

		// 验证 token 是否等于 "valid_token"
		if token != "valid_token" {
			// 如果 token 无效,返回 401 状态码和错误信息
			c.JSON(401, gin.H{"error": "Unauthorized"})
			c.Abort() // 终止请求,不再执行后续的中间件或处理函数
			return
		}

		// 如果 token 有效,继续处理请求
		c.Next()
	}
}

r.Use(AuthMiddleware()) // 全局使用中间件
2.2.3 路由级中间件

中间件也可以应用于特定的路由或路由组:

go 复制代码
auth := r.Group("/auth")
auth.Use(AuthMiddleware()) // 仅对 /auth 路由组生效
{
	auth.GET("/profile", func(c *gin.Context) {
		c.JSON(200, gin.H{"user": "authenticated user"})
	})
}

2.3 请求与响应

2.3.1 绑定请求参数

Gin 支持将请求参数绑定到结构体中:

go 复制代码
type LoginRequest struct {
	Username string `json:"username" binding:"required"` // binding:"required" 是 Gin 的验证标签,表示该字段为必填项。如果请求体中缺少该字段,验证会失败
	Password string `json:"password" binding:"required"`
}

r.POST("/login", func(c *gin.Context) {
	var req LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	c.JSON(200, gin.H{"message": "Login successful"})
})
2.3.2 返回 JSON

使用 c.JSON 返回 JSON 数据:

go 复制代码
c.JSON(200, gin.H{"key": "value"})
2.3.3 返回文件

使用 c.File 返回文件:

go 复制代码
c.File("path/to/file")

2.4 错误处理

Gin 提供了多种方式处理错误:

  1. 使用 c.JSON 返回错误信息。
  2. 使用 c.AbortWithStatusJSON 中止请求并返回错误。

三、Gin 实践:构建一个简单的 RESTful API

3.1 项目需求

构建一个简单的用户管理 API,支持以下功能:

  • 获取用户列表
  • 获取单个用户
  • 创建用户
  • 更新用户
  • 删除用户

3.2 项目结构

plaintext 复制代码
project/
├── main.go
└── models/
    └── user.go

3.3 实现代码

3.3.1 数据模型

创建 models/user.go

go 复制代码
package models

import (
	"errors"
	"strconv"
)

// 用户结构体
type User struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
	Age   int    `json:"age"`
}

// 模拟数据库
var users = []User{
	{ID: 1, Name: "Alice", Email: "alice@example.com", Age: 25},
	{ID: 2, Name: "Bob", Email: "bob@example.com", Age: 30},
}

// 获取所有用户
func GetAllUsers() []User {
	return users
}

// 根据 ID 获取单个用户
func GetUserByID(id int) (*User, error) {
	for _, user := range users {
		if user.ID == id {
			return &user, nil
		}
	}
	return nil, errors.New("user not found")
}

// 创建新用户
func CreateUser(user User) User {
	// 模拟生成自增 ID
	user.ID = len(users) + 1
	users = append(users, user)
	return user
}

// 更新用户
func UpdateUser(id int, updatedUser User) (*User, error) {
	for i, user := range users {
		if user.ID == id {
			users[i].Name = updatedUser.Name
			users[i].Email = updatedUser.Email
			users[i].Age = updatedUser.Age
			return &users[i], nil
		}
	}
	return nil, errors.New("user not found")
}

// 删除用户
func DeleteUser(id int) error {
	for i, user := range users {
		if user.ID == id {
			users = append(users[:i], users[i+1:]...)
			return nil
		}
	}
	return errors.New("user not found")
}

// 将字符串 ID 转为整数
func ParseID(param string) (int, error) {
	return strconv.Atoi(param)
}
3.3.2 路由与控制器

创建 main.go

go 复制代码
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"project/models"
)

func main() {
	r := gin.Default()

	// 用户管理路由组
	userGroup := r.Group("/api/v1/users")
	{
		// 获取用户列表
		userGroup.GET("/", func(c *gin.Context) {
			users := models.GetAllUsers()
			c.JSON(http.StatusOK, gin.H{"users": users})
		})

		// 获取单个用户
		userGroup.GET("/:id", func(c *gin.Context) {
			id, err := models.ParseID(c.Param("id"))
			if err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
				return
			}

			user, err := models.GetUserByID(id)
			if err != nil {
				c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
				return
			}

			c.JSON(http.StatusOK, gin.H{"user": user})
		})

		// 创建用户
		userGroup.POST("/", func(c *gin.Context) {
			var newUser models.User
			if err := c.ShouldBindJSON(&newUser); err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
				return
			}

			createdUser := models.CreateUser(newUser)
			c.JSON(http.StatusCreated, gin.H{"user": createdUser})
		})

		// 更新用户
		userGroup.PUT("/:id", func(c *gin.Context) {
			id, err := models.ParseID(c.Param("id"))
			if err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
				return
			}

			var updatedUser models.User
			if err := c.ShouldBindJSON(&updatedUser); err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
				return
			}

			user, err := models.UpdateUser(id, updatedUser)
			if err != nil {
				c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
				return
			}

			c.JSON(http.StatusOK, gin.H{"user": user})
		})

		// 删除用户
		userGroup.DELETE("/:id", func(c *gin.Context) {
			id, err := models.ParseID(c.Param("id"))
			if err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
				return
			}

			if err := models.DeleteUser(id); err != nil {
				c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
				return
			}

			c.JSON(http.StatusOK, gin.H{"message": "User deleted successfully"})
		})
	}

	// 启动服务器
	r.Run(":8080")
}

3.4 功能验证

以下是各个 API 的请求和响应示例:

1. 获取用户列表
  • 请求

    doc 复制代码
    curl -X GET http://localhost:8080/api/v1/users/
  • 响应

    json 复制代码
    {
      "users": [
        {
          "id": 1,
          "name": "Alice",
          "email": "alice@example.com",
          "age": 25
        },
        {
          "id": 2,
          "name": "Bob",
          "email": "bob@example.com",
          "age": 30
        }
      ]
    }

2. 获取单个用户
  • 请求

    doc 复制代码
    curl -X GET http://localhost:8080/api/v1/users/1
  • 响应

    json 复制代码
    {
      "user": {
        "id": 1,
        "name": "Alice",
        "email": "alice@example.com",
        "age": 25
      }
    }
  • 错误响应(无效 ID):

    json 复制代码
    {
      "error": "user not found"
    }

3. 创建用户
  • 请求

    doc 复制代码
    curl -X POST http://localhost:8080/api/v1/users/ -H "Content-Type: application/json" -d "{\"name\": \"Charlie\",\"email\": \"charlie@example.com\",\"age\": 28}"
  • 响应

    json 复制代码
    {
      "user": {
        "id": 3,
        "name": "Charlie",
        "email": "charlie@example.com",
        "age": 28
      }
    }

4. 更新用户
  • 请求

    doc 复制代码
    curl -X PUT http://localhost:8080/api/v1/users/1 -H "Content-Type: application/json" -d "{\"name\": \"Alice Updated\",\"email\": \"alice.updated@example.com\",\"age\": 26}"
  • 响应

    json 复制代码
    {
      "user": {
        "id": 1,
        "name": "Alice Updated",
        "email": "alice.updated@example.com",
        "age": 26
      }
    }

5. 删除用户
  • 请求

    doc 复制代码
    curl -X DELETE http://localhost:8080/api/v1/users/1
  • 响应

    json 复制代码
    {
      "message": "User deleted successfully"
    }

四、总结

通过本篇文章,我们学习了 Gin 的基本用法,包括路由、中间件、请求与响应等,并通过实践构建了一个简单的 RESTful API。Gin 是一个非常高效且易用的框架,适合快速开发 Web 应用和服务,本章只是对Gin框架的快速入门,想要深入理解得多实战。

相关推荐
果粒chenl几秒前
css+js提问
前端·javascript·css
~kiss~1 分钟前
Rust~二刷异步逻辑
开发语言·后端·rust
memorycx1 分钟前
Vue02
前端·javascript·vue.js
SomeB1oody9 分钟前
【Rust中级教程】2.7. API设计原则之灵活性(flexible) Pt.3:借用 vs. 拥有、`Cow`类型、可失败和阻塞的析构函数及解决办法
开发语言·后端·性能优化·rust
LUCIAZZZ11 分钟前
Https解决了Http的哪些问题
java·网络·网络协议·spring·http·rpc·https
larance18 分钟前
Flask 发送邮件
后端·python·flask
m0_7482402521 分钟前
python轻量级框架-flask
开发语言·python·flask
Aska_Lv24 分钟前
从零到一写组件库-日志组件库
后端
hxung29 分钟前
MySQL面试学习
学习·mysql·面试
论迹33 分钟前
【JavaEE】-- 多线程(初阶)2
java·开发语言·java-ee