文档
Gin 毕设实战 — Go Web 开发从入门到上线
前言
Gin 是国内 Go 后端开发的事实标准。它性能极高、API 简洁,非常适合毕设中需要高性能接口的场景(如数据处理、实时计算)。
第一章:Gin 的 radix tree 路由
Gin 基于 httprouter 的压缩前缀树(radix tree),路由时间复杂度 O(log n):
GET /api/users
GET /api/users/:id
GET /api/users/:id/posts
POST /api/users
POST /api/posts
这些路由被组织成一棵树,查找效率极高。相比之下 Express 对每个路由遍历正则匹配。
第二章:请求验证
Gin 使用 validator 库做 struct tag 验证:
type CreateOrderReq struct {
UserID int `json:"userId" binding:"required,min=1"`
ProductID int `json:"productId" binding:"required"`
Quantity int `json:"quantity" binding:"required,min=1,max=100"`
Coupon string `json:"coupon" binding:"omitempty,len=6"`
Email string `json:"email" binding:"required,email"`
}
func createOrder(c *gin.Context) {
var req CreateOrderReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 验证通过,req 可直接使用
}
常用验证标签:required、min、max、len、email、url、oneof、gte、lte。
第三章:中间件开发
// 自定义 JWT 中间件
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" || !strings.HasPrefix(token, "Bearer ") {
c.AbortWithStatusJSON(401, gin.H{"error": "未登录"})
return
}
claims, err := parseToken(token[7:])
if err != nil {
c.AbortWithStatusJSON(401, gin.H{"error": "Token 无效"})
return
}
c.Set("userId", claims.UserID) // 存入上下文
c.Next()
}
}
// 使用
r.Group("/api").Use(AuthMiddleware())
{
// 此组内所有路由都需认证
}
第四章:使用 GORM 操作数据库
// 模型定义
type Article struct {
ID uint `gorm:"primaryKey"`
Title string `gorm:"size:200;not null"`
Content string `gorm:"type:text"`
UserID uint
CreatedAt time.Time
}
// 初始化
db, _ := gorm.Open(sqlite.Open("blog.db"), &gorm.Config{})
db.AutoMigrate(&Article{})
// 在 Handler 中使用
func listArticles(c *gin.Context) {
var articles []Article
db.Find(&articles)
c.JSON(200, articles)
}
第五章:优雅关停
srv := &http.Server{Addr: ":8080", Handler: r}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx) // 等待进行中的请求完成
思考题
- Gin 的
ShouldBindJSON和MustBindJSON区别是什么? - 如何在 Gin 中实现请求限流(rate limiting)?
- Go 的
context.Context在 Web 请求中有什么作用?