前置要求: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",
},
}
}
学习建议
- 先跑通Hello World,理解请求-响应流程
- 掌握路由和中间件,这是Gin的核心
- 学习GORM,Go最流行的ORM库
- 理解项目结构,做好代码分层
- 做一个完整项目,如用户管理系统或博客API
下一步学习
- gRPC — 高性能RPC框架
- Go Kit — 微服务工具包
- Java Spring Boot