Go Gin 框架入门教程 — 高性能Web框架

前置要求:Go语言基础、HTTP基础
学习时长:约2-3天(每天4小时)
Gin版本:1.9+
适用场景:高性能API、微服务、REST API、网关

一、Gin 是什么?

Gin 是 Go 语言最流行的 Web 框架,以高性能和简洁的API著称,适合构建高性能的后端服务。

特点说明
性能比其他Go框架快40倍
学习曲线★★☆☆☆(API简洁,文档清晰)
核心优势高性能、中间件丰富、路由灵活
适用场景REST API、微服务、网关、高并发服务
生态GORM(ORM)、JWT、Swagger

二、快速开始

# 初始化项目
mkdir myproject && cd myproject
go mod init myproject

# 安装Gin
go get -u github.com/gin-gonic/gin

// main.go
package main

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

func main() {
    r := gin.Default()  // 创建带默认中间件的引擎
    
    r.GET("/", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "Hello, Gin!",
        })
    })
    
    r.Run(":8080")  // 启动服务器
}

# 运行
go run main.go

# 访问 http://localhost:8080


三、路由系统

package main

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

func main() {
    r := gin.Default()
    
    // ====================
    // 基本路由
    // ====================
    r.GET("/get", func(c *gin.Context) {
        c.JSON(200, gin.H{"method": "GET"})
    })
    
    r.POST("/post", func(c *gin.Context) {
        c.JSON(200, gin.H{"method": "POST"})
    })
    
    r.PUT("/put", func(c *gin.Context) {
        c.JSON(200, gin.H{"method": "PUT"})
    })
    
    r.DELETE("/delete", func(c *gin.Context) {
        c.JSON(200, gin.H{"method": "DELETE"})
    })
    
    // ====================
    // 路径参数
    // ====================
    r.GET("/user/:id", func(c *gin.Context) {
        id := c.Param("id")
        c.JSON(200, gin.H{"user_id": id})
    })
    
    r.GET("/user/:id/post/:post_id", func(c *gin.Context) {
        id := c.Param("id")
        postId := c.Param("post_id")
        c.JSON(200, gin.H{"user_id": id, "post_id": postId})
    })
    
    // ====================
    // 查询参数
    // ====================
    r.GET("/search", func(c *gin.Context) {
        keyword := c.DefaultQuery("keyword", "")
        page := c.DefaultQuery("page", "1")
        c.JSON(200, gin.H{
            "keyword": keyword,
            "page":    page,
        })
    })
    
    // ====================
    // 路由组
    // ====================
    api := r.Group("/api")
    {
        api.GET("/users", getUsers)
        api.POST("/users", createUser)
        api.GET("/users/:id", getUser)
        api.PUT("/users/:id", updateUser)
        api.DELETE("/users/:id", deleteUser)
    }
    
    // 嵌套路由组
    v1 := r.Group("/api/v1")
    {
        v1.GET("/users", getUsers)
        v1.GET("/posts", getPosts)
    }
    
    r.Run(":8080")
}

func getUsers(c *gin.Context) {
    c.JSON(200, gin.H{"users": []string{}})
}

func createUser(c *gin.Context) {
    c.JSON(201, gin.H{"message": "创建成功"})
}

func getUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id})
}

func updateUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id, "message": "更新成功"})
}

func deleteUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id, "message": "删除成功"})
}


四、请求处理

package main

import (
    "fmt"
    "net/http"
    "github.com/gin-gonic/gin"
)

// 请求体结构体
type CreateUserRequest struct {
    Username string `json:"username" binding:"required,min=3,max=50"`
    Email    string `json:"email" binding:"required,email"`
    Age      int    `json:"age" binding:"required,gte=0,lte=150"`
    Password string `json:"password" binding:"required,min=6"`
}

type UpdateUserRequest struct {
    Username string `json:"username" binding:"omitempty,min=3,max=50"`
    Email    string `json:"email" binding:"omitempty,email"`
    Age      int    `json:"age" binding:"omitempty,gte=0,lte=150"`
}

func main() {
    r := gin.Default()
    
    // JSON请求体
    r.POST("/users", func(c *gin.Context) {
        var req CreateUserRequest
        if err := c.ShouldBindJSON(&req); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        
        c.JSON(http.StatusCreated, gin.H{
            "message":  "创建成功",
            "username": req.Username,
            "email":    req.Email,
        })
    })
    
    // 表单请求
    r.POST("/login", func(c *gin.Context) {
        username := c.PostForm("username")
        password := c.PostForm("password")
        
        c.JSON(200, gin.H{
            "username": username,
            "password": password,
        })
    })
    
    // 文件上传
    r.POST("/upload", func(c *gin.Context) {
        file, err := c.FormFile("file")
        if err != nil {
            c.JSON(400, gin.H{"error": "文件上传失败"})
            return
        }
        
        filename := fmt.Sprintf("uploads/%s", file.Filename)
        if err := c.SaveUploadedFile(file, filename); err != nil {
            c.JSON(500, gin.H{"error": "保存文件失败"})
            return
        }
        
        c.JSON(200, gin.H{"filename": file.Filename, "size": file.Size})
    })
    
    // 获取请求头
    r.GET("/info", func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        userAgent := c.GetHeader("User-Agent")
        
        c.JSON(200, gin.H{
            "token":     token,
            "user_agent": userAgent,
        })
    })
    
    r.Run(":8080")
}


五、中间件

package main

import (
    "log"
    "time"
    "net/http"
    "github.com/gin-gonic/gin"
)

// ====================
// 自定义中间件
// ====================

// Logger中间件
func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        path := c.Request.URL.Path
        
        c.Next()  // 处理请求
        
        latency := time.Since(start)
        status := c.Writer.Status()
        
        log.Printf("[%d] %s %s %v", status, c.Request.Method, path, latency)
    }
}

// Auth中间件
func AuthRequired() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        
        if token == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权"})
            c.Abort()  // 终止请求
            return
        }
        
        // 验证token逻辑
        if token != "valid-token" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "token无效"})
            c.Abort()
            return
        }
        
        c.Set("user_id", 1)  // 设置用户信息
        c.Next()
    }
}

// CORS中间件
func CORS() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Header("Access-Control-Allow-Origin", "*")
        c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
        
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }
        
        c.Next()
    }
}

func main() {
    r := gin.New()  // 不带默认中间件
    
    // 使用中间件
    r.Use(Logger())
    r.Use(CORS())
    r.Use(gin.Recovery())  // Panic恢复
    
    // 公开路由
    r.POST("/login", func(c *gin.Context) {
        c.JSON(200, gin.H{"token": "valid-token"})
    })
    
    // 需要认证的路由
    auth := r.Group("/api")
    auth.Use(AuthRequired())
    {
        auth.GET("/profile", func(c *gin.Context) {
            userId, _ := c.Get("user_id")
            c.JSON(200, gin.H{"user_id": userId})
        })
        
        auth.PUT("/profile", func(c *gin.Context) {
            c.JSON(200, gin.H{"message": "更新成功"})
        })
    }
    
    r.Run(":8080")
}


六、GORM 数据库操作

# 安装GORM
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

package main

import (
    "fmt"
    "log"
    "time"
    "net/http"
    
    "github.com/gin-gonic/gin"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

// ====================
// 模型定义
// ====================
type User struct {
    ID        uint      `json:"id" gorm:"primaryKey"`
    Username  string    `json:"username" gorm:"uniqueIndex;size:50;not null"`
    Email     string    `json:"email" gorm:"uniqueIndex;size:100;not null"`
    Password  string    `json:"-" gorm:"not null"`  // json:"-" 不返回密码
    Age       int       `json:"age"`
    IsActive  bool      `json:"is_active" gorm:"default:true"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}

// 表名
func (User) TableName() string {
    return "users"
}

// ====================
// 数据库连接
// ====================
var db *gorm.DB

func initDB() {
    var err error
    dsn := "root:password@tcp(127.0.0.1:3306)/mydb?charset=utf8mb4&parseTime=True&loc=Local"
    db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        log.Fatal("数据库连接失败:", err)
    }
    
    // 自动迁移
    db.AutoMigrate(&User{})
    
    fmt.Println("数据库连接成功")
}

// ====================
// Handler函数
// ====================

// 获取用户列表
func getUsers(c *gin.Context) {
    var users []User
    
    // 查询参数
    keyword := c.Query("keyword")
    page := c.DefaultQuery("page", "1")
    size := c.DefaultQuery("size", "10")
    
    query := db.Model(&User{})
    
    if keyword != "" {
        query = query.Where("username LIKE ? OR email LIKE ?", "%"+keyword+"%", "%"+keyword+"%")
    }
    
    // 分页
    var total int64
    query.Count(&total)
    
    var pageInt, sizeInt int
    fmt.Sscanf(page, "%d", &pageInt)
    fmt.Sscanf(size, "%d", &sizeInt)
    offset := (pageInt - 1) * sizeInt
    
    query.Offset(offset).Limit(sizeInt).Order("created_at desc").Find(&users)
    
    c.JSON(200, gin.H{
        "data":  users,
        "total": total,
        "page":  pageInt,
        "size":  sizeInt,
    })
}

// 获取单个用户
func getUser(c *gin.Context) {
    id := c.Param("id")
    var user User
    
    if err := db.First(&user, id).Error; err != nil {
        c.JSON(404, gin.H{"error": "用户不存在"})
        return
    }
    
    c.JSON(200, gin.H{"data": user})
}

// 创建用户
type CreateUserRequest struct {
    Username string `json:"username" binding:"required"`
    Email    string `json:"email" binding:"required,email"`
    Password string `json:"password" binding:"required,min=6"`
    Age      int    `json:"age"`
}

func createUser(c *gin.Context) {
    var req CreateUserRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    
    user := User{
        Username: req.Username,
        Email:    req.Email,
        Password: req.Password,  // 实际应加密
        Age:      req.Age,
    }
    
    if err := db.Create(&user).Error; err != nil {
        c.JSON(400, gin.H{"error": "创建失败: " + err.Error()})
        return
    }
    
    c.JSON(201, gin.H{"data": user})
}

// 更新用户
func updateUser(c *gin.Context) {
    id := c.Param("id")
    var user User
    
    if err := db.First(&user, id).Error; err != nil {
        c.JSON(404, gin.H{"error": "用户不存在"})
        return
    }
    
    var req CreateUserRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    
    user.Username = req.Username
    user.Email = req.Email
    user.Age = req.Age
    
    db.Save(&user)
    c.JSON(200, gin.H{"data": user})
}

// 删除用户
func deleteUser(c *gin.Context) {
    id := c.Param("id")
    
    if err := db.Delete(&User{}, id).Error; err != nil {
        c.JSON(400, gin.H{"error": "删除失败"})
        return
    }
    
    c.JSON(200, gin.H{"message": "删除成功"})
}

// ====================
// 主函数
// ====================
func main() {
    initDB()
    
    r := gin.Default()
    
    api := r.Group("/api")
    {
        api.GET("/users", getUsers)
        api.GET("/users/:id", getUser)
        api.POST("/users", createUser)
        api.PUT("/users/:id", updateUser)
        api.DELETE("/users/:id", deleteUser)
    }
    
    r.Run(":8080")
}


七、完整项目结构

myproject/
├── main.go              # 入口
├── go.mod
├── go.sum
├── config/
│   └── config.go        # 配置
├── models/
│   └── user.go          # 数据模型
├── handlers/
│   └── user.go          # 处理器
├── middleware/
│   ├── auth.go          # 认证中间件
│   └── cors.go          # CORS中间件
├── routes/
│   └── routes.go        # 路由配置
└── utils/
    └── response.go      # 工具函数

// config/config.go
package config

type Config struct {
    DB   DBConfig
    Server ServerConfig
}

type DBConfig struct {
    Host     string
    Port     int
    Username string
    Password string
    Database string
}

type ServerConfig struct {
    Port int
    Mode string  // debug, release, test
}

func Load() *Config {
    return &Config{
        DB: DBConfig{
            Host:     "127.0.0.1",
            Port:     3306,
            Username: "root",
            Password: "password",
            Database: "mydb",
        },
        Server: ServerConfig{
            Port: 8080,
            Mode: "debug",
        },
    }
}


学习建议

  1. 先跑通Hello World,理解请求-响应流程
  2. 掌握路由和中间件,这是Gin的核心
  3. 学习GORM,Go最流行的ORM库
  4. 理解项目结构,做好代码分层
  5. 做一个完整项目,如用户管理系统或博客API

下一步学习

返回首页