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 等开箱即用 |
| 性能优秀 | 优化的路由、连接池、序列化 |
| 中文友好 | 完善的中文文档和社区 |
| 企业级 | 适合中大型项目快速开发 |
适用场景
- ✅ 企业级后台管理系统
- ✅ API 服务开发
- ✅ 微服务架构
- ✅ 快速原型开发