crud demo

脚手架

安装

go install github.com/gogf/gf/cmd/gf/v2@latest

查看是否安装成功

$ gf -v
v2.9.0
Welcome to GoFrame!
Env Detail:
  Go Version: go1.24.3 windows/amd64
  GF Version(go.mod): cannot find go.mod
CLI Detail:
  Installed At: C:\Users\JT\go\bin\gf.exe
  Built Go Version: go1.24.3
  Built GF Version: v2.9.0
Others Detail:
  Docs: https://goframe.org
  Now : 2025-08-27T15:18:41+08:00

模板

gf init demo -u
# demo 项目名称
# -u 使用最新版

目录结构

demo
├── api
├── hack
├── internal
│   ├── cmd
│   ├── consts
│   ├── controller
│   ├── dao
│   ├── model
│   |   ├── do
│   │   └── entity
│   └── service
├── manifest
├── resource
├── utility
├── go.mod
└── main.go

目录说明

目录/文件名称 说明 描述
api 对外接口 对外提供服务的输入/输出数据结构定义。考虑到版本管理需要,往往以 api/xxx/v1... 存在
hack 工具脚本 存放项目开发工具、脚本等内容。例如, CLI 工具的配置,各种 shell/bat 脚本等文件
internal 内部逻辑 业务逻辑存放目录。通过 Golang internal 特性对外部隐藏可见性。
- cmd 入口指令 命令行管理目录。可以管理维护多个命令行。
- consts 常量定义 项目所有常量定义。
- controller 接口处理 接收/解析用户输入参数的入口/接口层。
- dao 数据访问 数据访问对象,这是一层抽象对象,用于和底层数据库交互,仅包含最基础的 CRUD 方法
- model 结构模型 数据结构管理模块,管理数据实体对象,以及输入与输出数据结构定义。
- do 领域对象 用于 dao 数据操作中业务模型与实例模型转换,由工具维护,用户不能修改。
- entity 数据模型 数据模型是模型与数据集合的一对一关系,由工具维护,用户不能修改。
- service 业务实现 业务逻辑的具体实现和封装。往往是项目中最复杂的部分。
manifest 交付清单 包含程序编译、部署、运行、配置的文件。常见内容如下:
- config 配置管理 配置文件存放目录。
- docker 镜像文件 Docker 镜像相关依赖文件,脚本文件等等。
- deploy 部署文件 部署相关的文件。默认提供了 Kubernetes 集群化部署的 Yaml 模板,通过 kustomize
resource 静态资源 静态资源文件。这些文件往往可以通过 资源打包/镜像编译 的形式注入到发布文件中。
utility 工具包 项目的工具包,提供了一些常用的工具函数。
go.mod 依赖管理 使用 Go Module 包管理的依赖描述文件。
main.go 入口文件 程序入口文件。

创建数据表

CREATE TABLE `gf_user` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '账号',
  `nickname` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '昵称',
  `password` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码',
  `status` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '0=正常,1=禁用',
  `registTime` datetime DEFAULT NULL COMMENT '注册时间',
  `lastLoginTime` datetime DEFAULT NULL COMMENT '最后登录时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

配置数据库

hack/config.yaml

# CLI tool, only in development environment.
# https://goframe.org/docs/cli
gfcli:
  gen:
    dao:
    # mysql=数据库类型  root=数据库账号 123456=数据库密码  127.0.0.1=数据库host 3306=端口 gf_admin = 所选数据库名称
      - link: "mysql:root:123456@tcp(127.0.0.1:3306)/gf_admin"
        descriptionTag: true

  docker:
    build: "-a amd64 -s linux -p temp -ew"
    tagPrefixes:
      - my.image.pub/my-app

mainfest/config/config.yaml

# https://goframe.org/docs/web/server-config-file-template
server:
  address:     ":8000"
  openapiPath: "/api.json"
  swaggerPath: "/swagger"

# https://goframe.org/docs/core/glog-config
logger:
  level : "all"
  stdout: true

# https://goframe.org/docs/core/gdb-config-file
database:
  default:
    link:  "mysql:root:123456@tcp(127.0.0.1:3306)/gf_admin"

添加接口定义

api/user/va/user.go

package v1

import (
	"demo/internal/model/entity"
	"github.com/gogf/gf/v2/frame/g"
)

// 创建用户请求
type CreateReq struct {
	g.Meta   `path:"/user" method:"post" tags:"User" summary:"CreateUser"`
	Username string `v:"required|length:6,12" dc:"username"`
	Nickname string `v:"required|length:3,12" dc:"nickname"`
	Password string `v:"required" dc:"password"`
}

// 创建用户返回
type CreateRes struct {
	Id int64 `json:"id" dc:"user id"`
}

// 用户更新请求
type UpdateReq struct {
	g.Meta   `path:"/user/{id}" method:"put" tags:"User" summary:"UpdateUser"`
	Id       int64  `v:"required" dc:"user id"`
	Nickname string `v:"required" dc:"user nickname"`
	Password string `v:"required" dc:"user password"`
}

// 更新用户返回
type UpdateRes struct {
}

// 删除用户请求
type DeleteReq struct {
	g.Meta `path:"/user/{id}" method:"delete" tags:"User" summary:"DeleteUser"`
	Id     int64 `v:"required" dc:"user id"`
}

type DeleteRes struct {
}

// 获取单个用户
type GetOneReq struct {
	g.Meta `path:"/user/{id}" method:"get" tags:"User" summary:"GetUserInfo"`
	Id     int64 `v:"required" dc:"user id"`
}

type GetOneRes struct {
	*entity.GfUser `dc:"user"`
}

type GetListReq struct {
	g.Meta `path:"/user" method:"get" tags:"User" summary:"Get User"`
	Status *uint8 `v:"in:0,1" dc:"user status"`
}

type GetListRes struct {
	List []*entity.GfUser `json:"list" dc:"user list"`
}

生成controller

$ gf gen ctrl
generated: demo/api/user/user.go
generated: demo/internal/controller/user/user.go
generated: demo/internal/controller/user/user_new.go
generated: demo/internal/controller/user/user_v1_create.go
generated: demo/internal/controller/user/user_v1_update.go
generated: demo/internal/controller/user/user_v1_delete.go
generated: demo/internal/controller/user/user_v1_get_one.go
generated: demo/internal/controller/user/user_v1_get_list.go

接口定义

# demo/api/user/user.go

package user

import (
	"context"

	"demo/api/user/v1"
)

type IUserV1 interface {
	Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error)
	Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error)
	Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error)
	GetOne(ctx context.Context, req *v1.GetOneReq) (res *v1.GetOneRes, err error)
	GetList(ctx context.Context, req *v1.GetListReq) (res *v1.GetListRes, err error)
}
# demo/internal/controller/user/user_new.go


package user

import (
	"demo/api/user"
)

type ControllerV1 struct{}

func NewV1() user.IUserV1 {
	return &ControllerV1{}
}

创建用户实现

# demo/internal/controller/user/user_v1_create.go

package user

import (
	"context"
	"demo/api/user/v1"
	"demo/internal/dao"
	"demo/internal/model/do"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/os/gtime"
)

// 创建用户
func (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {
	//查询账号是否已经注册过
	isExist, err := dao.GfUser.Ctx(ctx).Where("username", req.Username).Exist()
	if isExist != false {
		return nil, gerror.New("账号已注册")
	}
	//获取创建成功的ID
	insertId, err := dao.GfUser.Ctx(ctx).Data(do.GfUser{
		Nickname:      req.Nickname,
		Username:      req.Username,
		Password:      req.Password,
		RegistTime:    gtime.Now(),
		LastLoginTime: gtime.Now(),
	}).InsertAndGetId()
	if err != nil {
		return nil, err
	}
	//返回创建成功的用户ID
	res = &v1.CreateRes{
		Id: insertId,
	}
	return
}

删除用户实现

package user

import (
	"context"
	"demo/internal/dao"
	"demo/internal/model/do"
	"github.com/gogf/gf/v2/errors/gerror"

	"demo/api/user/v1"
)

func (c *ControllerV1) Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error) {
	//判断用户是否存在
	isExist, err := dao.GfUser.Ctx(ctx).Where(do.GfUser{Id: req.Id}).Exist()
	if isExist != true {
		return nil, gerror.Newf("用户ID:%d不存在", req.Id)
	}

	result, err := dao.GfUser.Ctx(ctx).Where(do.GfUser{Id: req.Id}).Delete()
	if err != nil {
		return nil, err
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return nil, err
	}
	if rowsAffected == 0 {
		return nil, gerror.Newf("用户ID:%d删除失败", req.Id)
	}
	return &v1.DeleteRes{}, nil

}


修改用户实现


package user

import (
	"context"
	"demo/internal/dao"
	"demo/internal/model/do"

	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"

	"demo/api/user/v1"
)

func (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) {
	_, err = dao.GfUser.Ctx(ctx).Data(do.GfUser{
		Password: req.Password,
		Nickname: req.Nickname,
	}).Where(do.GfUser{Id: req.Id}).Update()
	return nil, gerror.NewCode(gcode.CodeNotImplemented)
}

查询用户实现(单个)

package user

import (
	"context"
	"demo/internal/dao"
	"demo/internal/model/do"

	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"

	"demo/api/user/v1"
)

func (c *ControllerV1) GetOne(ctx context.Context, req *v1.GetOneReq) (res *v1.GetOneRes, err error) {
	res = &v1.GetOneRes{}
	err = dao.GfUser.Ctx(ctx).Where(do.GfUser{Id: req.Id}).Scan(&res.GfUser)
	if err != nil {
		return nil, err
	}
	if res.GfUser.Id == 0 {
		return nil, gerror.NewCode(gcode.CodeNotImplemented)
	}

	return
}

查询用户实现(列表)

package user

import (
	"context"
	"demo/api/user/v1"
	"demo/internal/dao"
	"demo/internal/model/do"
)

// 获取用户列表8464w4
func (c *ControllerV1) GetList(ctx context.Context, req *v1.GetListReq) (res *v1.GetListRes, err error) {
	res = &v1.GetListRes{}
	err = dao.GfUser.Ctx(ctx).Data(do.GfUser{Id: req.Status}).Scan(&res.List)
	if err != nil {
		return nil, err
	}
	return

}