Skip to content
清晨的一缕阳光
返回

GoFrame 全栈框架实战指南

GoFrame 是一款国产的、高性能的、全功能的 Go 语言 Web 框架,提供 ORM、依赖注入、验证器、缓存、日志等完整的企业级开发组件。本文将深入探讨 GoFrame 的核心特性和实战应用。

一、GoFrame 简介

1.1 框架特点

特性说明
模块化设计按需引入,灵活组合
高性能优化路由、连接池、序列化
完整生态ORM、Cache、Log、Config 等
中文文档完善的中文文档和社区支持
企业级适合中大型项目开发

1.2 安装与初始化

# 安装 gf 命令行工具
go install github.com/gogf/gf/cmd/gf/v2@latest

# 创建项目
gf init myproject

# 进入项目目录
cd myproject

# 安装依赖
go mod tidy

项目结构

myproject/
├── api/           # API 定义
├── logic/         # 业务逻辑
├── dao/           # 数据访问层
├── model/         # 数据模型
├── service/       # 服务接口
├── controller/    # 控制器
├── config/        # 配置文件
├── resource/      # 静态资源
└── main.go        # 入口文件

二、核心组件详解

2.1 路由与控制器

package main

import (
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/net/ghttp"
)

func main() {
    s := g.Server()
    
    // 基础路由
    s.GET("/", func(r *ghttp.Request) {
        r.Response.Write("Hello World")
    })
    
    // 分组路由
    s.Group("/api", func(group *ghttp.RouterGroup) {
        group.GET("/users", GetUsers)
        group.POST("/users", CreateUser)
        group.GET("/users/:id", GetUser)
        group.PUT("/users/:id", UpdateUser)
        group.DELETE("/users/:id", DeleteUser)
    })
    
    // 中间件
    s.Use(MiddlewareAuth, MiddlewareLog)
    
    s.Run()
}

控制器示例

package controller

import (
    "github.com/gogf/gf/v2/net/ghttp"
    "myproject/api"
    "myproject/service"
)

var User = cUser{}

type cUser struct{}

func (c *cUser) List(r *ghttp.Request) {
    var req api.UserListReq
    if err := r.Parse(&req); err != nil {
        r.Response.WriteJsonExit(err)
    }
    
    res, err := service.User.List(r.Context(), &req)
    if err != nil {
        r.Response.WriteJsonExit(err)
    }
    
    r.Response.WriteJsonExit(res)
}

2.2 ORM 数据库操作

模型定义

package model

import "github.com/gogf/gf/v2/database/gdb"

// User 用户模型
type User struct {
    g.Meta   `orm:"table:user, do:true"`
    ID       interface{} // 用户 ID
    Username interface{} // 用户名
    Password interface{} // 密码
    Email    interface{} // 邮箱
    Age      interface{} // 年龄
    Status   interface{} // 状态
}

// UserDO 数据对象
type UserDO struct {
    g.Meta   `orm:"table:user"`
    ID       int    // 用户 ID
    Username string // 用户名
    Password string // 密码
    Email    string // 邮箱
    Age      int    // 年龄
    Status   int    // 状态
}

DAO 层操作

package dao

import (
    "context"
    "github.com/gogf/gf/v2/database/gdb"
    "github.com/gogf/gf/v2/frame/g"
    "myproject/model"
)

var User = userDao{}

type userDao struct {
    table   string
    columns map[string]*gdb.Column
}

func init() {
    table := "user"
    User = userDao{
        table:   table,
        columns: g.DB().GetCore().GetTables().Get(table, nil).Fields,
    }
}

// 插入数据
func (d *userDao) Insert(ctx context.Context, data *model.UserDO) (int64, error) {
    result, err := g.Model(d.table).Data(data).Insert()
    if err != nil {
        return 0, err
    }
    return result.LastInsertId()
}

// 查询单个
func (d *userDao) GetByID(ctx context.Context, id int) (*model.UserDO, error) {
    var user *model.UserDO
    err := g.Model(d.table).Where("id", id).Scan(&user)
    return user, err
}

// 条件查询
func (d *userDao) Search(ctx context.Context, condition *model.User) ([]*model.UserDO, error) {
    var users []*model.UserDO
    m := g.Model(d.table)
    
    if condition.Username != nil {
        m = m.Where("username", condition.Username)
    }
    if condition.Email != nil {
        m = m.Where("email", condition.Email)
    }
    if condition.Age != nil {
        m = m.Where("age", condition.Age)
    }
    
    err := m.Scan(&users)
    return users, err
}

// 分页查询
func (d *userDao) Page(ctx context.Context, page, pageSize int) ([]*model.UserDO, int, error) {
    var users []*model.UserDO
    m := g.Model(d.table)
    
    total, err := m.Count()
    if err != nil {
        return nil, 0, err
    }
    
    err = m.Page(page, pageSize).Scan(&users)
    return users, total, err
}

// 更新数据
func (d *userDao) Update(ctx context.Context, id int, data map[string]interface{}) error {
    _, err := g.Model(d.table).Where("id", id).Data(data).Update()
    return err
}

// 删除数据
func (d *userDao) Delete(ctx context.Context, id int) error {
    _, err := g.Model(d.table).Where("id", id).Delete()
    return err
}

事务操作

func TransferMoney(ctx context.Context, fromID, toID int, amount float64) error {
    return g.DB().Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error {
        // 扣款
        _, err := tx.Model("user").Where("id", fromID).
            Dec("balance", amount).
            WhereGT("balance", amount).
            Update()
        if err != nil {
            return err
        }
        
        // 收款
        _, err = tx.Model("user").Where("id", toID).
            Inc("balance", amount).
            Update()
        if err != nil {
            return err
        }
        
        return nil
    })
}

2.3 依赖注入

package service

import (
    "context"
    "github.com/gogf/gf/v2/frame/g"
    "myproject/api"
    "myproject/model"
)

var User = userService{}

type userService struct{}

// 获取列表
func (s *userService) List(ctx context.Context, req *api.UserListReq) (*api.UserListRes, error) {
    var users []*model.UserDO
    var total int
    
    m := g.Model("user")
    
    if req.Keyword != "" {
        m = m.Where("username LIKE ?", "%"+req.Keyword+"%")
    }
    
    total, _ = m.Count()
    m.Page(req.Page, req.PageSize).Scan(&users)
    
    return &api.UserListRes{
        Users: users,
        Total: total,
    }, nil
}

// 创建用户
func (s *userService) Create(ctx context.Context, req *api.CreateUserReq) error {
    // 验证数据
    if err := g.Validate().Data(req).Run(); err != nil {
        return err
    }
    
    // 检查用户名是否存在
    count, _ := g.Model("user").Where("username", req.Username).Count()
    if count > 0 {
        return errors.New("用户名已存在")
    }
    
    // 插入数据
    _, err := g.Model("user").Data(g.Map{
        "username": req.Username,
        "password": req.Password,
        "email":    req.Email,
        "age":      req.Age,
    }).Insert()
    
    return err
}

2.4 验证器

package api

import "github.com/gogf/gf/v2/frame/g"

// CreateUserReq 创建用户请求
type CreateUserReq struct {
    g.Meta   `path:"/users" method:"post" tags:"用户管理" summary:"创建用户"`
    Username string `dc:"用户名" v:"required|length:3,20"`
    Password string `dc:"密码" v:"required|length:6,20"`
    Email    string `dc:"邮箱" v:"required|email"`
    Age      int    `dc:"年龄" v:"required|between:1,150"`
}

// UpdateUserReq 更新用户请求
type UpdateUserReq struct {
    g.Meta   `path:"/users/{id}" method:"put" tags:"用户管理" summary:"更新用户"`
    ID       int    `dc:"用户 ID" v:"required|min:1"`
    Email    string `dc:"邮箱" v:"required|email"`
    Age      int    `dc:"年龄" v:"required|between:1,150"`
}

// 自定义验证规则
func init() {
    g.Validator().RegisterRule("phone", func(ctx context.Context, in g.ValidatorRuleInput) {
        // 验证手机号格式
        phone := in.Value.String()
        if len(phone) != 11 || phone[0:3] != "138" {
            in.Error.SetError("手机号格式不正确")
        }
    })
}

2.5 缓存使用

package service

import (
    "context"
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gcache"
    "myproject/model"
)

// 带缓存的查询
func (s *userService) GetUserWithCache(ctx context.Context, id int) (*model.UserDO, error) {
    cacheKey := "user:" + strconv.Itoa(id)
    
    // 先从缓存获取
    if v, err := gcache.Get(ctx, cacheKey); err == nil && v != nil {
        var user model.UserDO
        v.Scan(&user)
        return &user, nil
    }
    
    // 缓存未命中,查询数据库
    var user *model.UserDO
    err := g.Model("user").Where("id", id).Scan(&user)
    if err != nil {
        return nil, err
    }
    
    // 写入缓存,5 分钟过期
    gcache.Set(ctx, cacheKey, user, 300*time.Second)
    
    return user, nil
}

// 缓存更新
func (s *userService) UpdateUser(ctx context.Context, id int, data map[string]interface{}) error {
    // 更新数据库
    err := g.Model("user").Where("id", id).Data(data).Update()
    if err != nil {
        return err
    }
    
    // 删除缓存
    gcache.Remove(ctx, "user:"+strconv.Itoa(id))
    
    return nil
}

2.6 日志配置

package main

import (
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/glog"
)

func init() {
    // 日志配置
    glog.SetConfig(glog.Config{
        Path:   "./logs",
        File:   "Y-m-d.log",
        Level:  glog.LEVEL_ALL,
        Stdout: true,
    })
}

func handler(r *ghttp.Request) {
    // 记录日志
    g.Log().Info(r.Context(), "用户访问", r.URL.Path)
    
    // 错误日志
    if err := someOperation(); err != nil {
        g.Log().Error(r.Context(), "操作失败", err)
    }
    
    // 调试日志
    g.Log().Debug(r.Context(), "请求参数", r.AllParams())
}

2.7 配置文件

config.yaml

server:
  address:     ":8080"
  openapiPath: "/api.json"
  swaggerPath: "/swagger"

database:
  default:
    link:  "mysql:user:password@tcp(127.0.0.1:3306)/dbname"
    debug: true

redis:
  default:
    address: "127.0.0.1:6379"
    db:      0

logger:
  path:   "./logs"
  file:   "Y-m-d.log"
  level:  "all"
  stdout: true

读取配置

package main

import (
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gctx"
)

func main() {
    ctx := gctx.New()
    
    // 读取配置
    dbConfig := g.Config().Get(ctx, "database.default.link")
    redisAddr := g.Config().Get(ctx, "redis.default.address")
    
    // 使用配置
    g.Log().Info(ctx, "DB:", dbConfig, "Redis:", redisAddr)
}

三、实战案例

3.1 用户认证系统

package service

import (
    "context"
    "errors"
    "github.com/gogf/gf/v2/crypto/gmd5"
    "github.com/gogf/gf/v2/encoding/gjwt"
    "github.com/gogf/gf/v2/frame/g"
    "myproject/model"
)

// 用户登录
func (s *userService) Login(ctx context.Context, username, password string) (string, error) {
    // 查询用户
    var user *model.UserDO
    err := g.Model("user").Where("username", username).Scan(&user)
    if err != nil {
        return "", err
    }
    if user == nil {
        return "", errors.New("用户不存在")
    }
    
    // 验证密码
    if user.Password != gmd5.MustEncryptString(password) {
        return "", errors.New("密码错误")
    }
    
    // 生成 Token
    token, err := gjwt.CreateToken(gjwt.Map{
        "user_id":  user.ID,
        "username": user.Username,
    })
    if err != nil {
        return "", err
    }
    
    return token, nil
}

// 中间件:JWT 认证
func MiddlewareAuth(r *ghttp.Request) {
    token := r.Get("Authorization").String()
    if token == "" {
        r.Response.WriteJsonExit(g.Map{
            "code": 401,
            "msg":  "未授权",
        })
    }
    
    claims, err := gjwt.ParseToken(token)
    if err != nil {
        r.Response.WriteJsonExit(g.Map{
            "code": 401,
            "msg":  "Token 无效",
        })
    }
    
    // 将用户信息存入上下文
    r.ContextVar.Set("user_id", claims["user_id"])
    r.ContextVar.Set("username", claims["username"])
    
    r.Middleware.Next()
}

3.2 文件上传

package controller

import (
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/net/ghttp"
    "github.com/gogf/gf/v2/os/gfile"
)

func (c *cUpload) File(r *ghttp.Request) {
    file := r.GetUploadFile("file")
    if file == nil {
        r.Response.WriteJsonExit(g.Map{
            "code": 400,
            "msg":  "文件不能为空",
        })
    }
    
    // 验证文件类型
    allowedTypes := []string{".jpg", ".png", ".gif", ".pdf"}
    ext := gfile.Ext(file.Filename)
    if !g.SliceStr(allowedTypes).Contains(ext) {
        r.Response.WriteJsonExit(g.Map{
            "code": 400,
            "msg":  "不支持的文件类型",
        })
    }
    
    // 保存文件
    savePath := "./uploads/" + gfile.Basename(file.Filename)
    if err := file.Save(savePath); err != nil {
        r.Response.WriteJsonExit(g.Map{
            "code": 500,
            "msg":  "上传失败:" + err.Error(),
        })
    }
    
    r.Response.WriteJsonExit(g.Map{
        "code": 0,
        "msg":  "上传成功",
        "data": g.Map{
            "url": "/uploads/" + gfile.Basename(file.Filename),
        },
    })
}

四、性能优化

4.1 连接池配置

database:
  default:
    link:  "mysql:user:pass@tcp(127.0.0.1:3306)/dbname"
    debug: true
    # 连接池配置
    maxIdle: 10
    maxOpen: 100
    maxLifetime: "30s"

4.2 路由优化

// 使用路由分组
s.Group("/api/v1", func(group *ghttp.RouterGroup) {
    // 公开路由
    group.Group("/public", func(g *ghttp.RouterGroup) {
        g.POST("/login", Login)
        g.POST("/register", Register)
    })
    
    // 需要认证的路由
    group.Group("/private", func(g *ghttp.RouterGroup) {
        g.BindMiddleware(MiddlewareAuth)
        g.GET("/users", GetUsers)
        g.POST("/users", CreateUser)
    })
})

五、总结

GoFrame 优势

优势说明
功能完整ORM、Cache、Log、Config 等开箱即用
性能优秀优化的路由、连接池、序列化
中文友好完善的中文文档和社区
企业级适合中大型项目快速开发

适用场景


参考资料


分享这篇文章到:

上一篇文章
Go Web 框架对比选型指南
下一篇文章
Kafka Streams 高级应用实战