-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
772 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--- | ||
slug: '/quick/scaffold-api-sql' | ||
title: 'Step1 - 设计数据表' | ||
hide_title: true | ||
sidebar_position: 0 | ||
--- | ||
|
||
|
||
我们先定义一个数据表,以下是本章节示例会用到的数据表`SQL`文件: | ||
|
||
```sql | ||
CREATE TABLE `user` ( | ||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'user id', | ||
`name` varchar(45) DEFAULT NULL COMMENT 'user name', | ||
`status` tinyint DEFAULT NULL COMMENT 'user status', | ||
`age` tinyint unsigned DEFAULT NULL COMMENT 'user age', | ||
PRIMARY KEY (`id`) | ||
) ENGINE=InnoDB DEFAULT CHARSET=utf8; | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
--- | ||
slug: '/quick/scaffold-api-gen-dao' | ||
title: 'Step2 - 生成/dao/do/entity' | ||
hide_title: true | ||
sidebar_position: 2 | ||
--- | ||
|
||
|
||
|
||
## 检查工具配置 | ||
在使用脚手架工具之前,请检查本地的`cli`工具配置是否正确。默认的配置如下: | ||
```yaml title="hack/config.yaml" | ||
# CLI tool, only in development environment. | ||
# https://goframe.org/docs/cli | ||
gfcli: | ||
gen: | ||
dao: | ||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test" | ||
|
||
docker: | ||
build: "-a amd64 -s linux -p temp -ew" | ||
tagPrefixes: | ||
- my.image.pub/my-app | ||
``` | ||
- 其中的`dao`部分配置即本次将要执行的命令的配置,其中的`link`为需要连接的数据库配置。 | ||
关于数据库的配置详细请参考章节 [ORM使用配置-配置文件](../../../docs/核心组件/数据库ORM/ORM使用配置/ORM使用配置-配置文件.md)。我们需要将此`link`配置改为我们的数据库连接地址。 | ||
- 其中`docker`配置项是模板默认提供的配置,用于镜像编译。这里不做详解,感兴趣可以参考开发手册中开发工具相关章节。 | ||
|
||
## 执行代码生成 | ||
将数据表创建好后,我们在项目根目录下执行`make dao`自动生成对应的`dao/do/entity`文件。 | ||
|
||
```text | ||
$ make dao | ||
generated: /Users/john/Temp/demo/internal/dao/user.go | ||
generated: /Users/john/Temp/demo/internal/dao/internal/user.go | ||
generated: /Users/john/Temp/demo/internal/model/do/user.go | ||
generated: /Users/john/Temp/demo/internal/model/entity/user.go | ||
done! | ||
``` | ||
|
||
:::tip | ||
`make`命令是在`*nix`系统下默认提供的指令,包括`Linux/MacOS`系统。如果是其他系统,例如`Windows`,默认不支持`make`命令,可以使用`gf gen dao`命令来替换。 | ||
::: | ||
|
||
![goframe dao、do、entity](QQ_1731675850748.png) | ||
|
||
每张表将会生成`4`个`Go`文件: | ||
- `dao`:通过对象方式访问底层数据源,底层基于`ORM`组件实现。 | ||
- `do`:数据转换模型,用于业务模型到数据模型的转换,由工具维护,用户不能修改。工具每次生成代码文件将会覆盖该目录。 | ||
- `entity`:数据模型,由工具维护,用户不能修改。工具每次生成代码文件将会覆盖该目录。 | ||
|
||
更详细的介绍请参考章节 [数据规范-gen dao](../../../docs/开发工具/代码生成-gen/数据规范-gen%20dao.md) | ||
|
||
### dao | ||
生成的`dao`文件有两个: | ||
- `internal/dao/internal/user.go`用于封装对数据表`user`的访问。该文件自动生成了一些数据结构和方法,简化对数据表的`CURD`操作。该文件每次生成都会覆盖,由开发工具自动维护。 | ||
- `internal/dao/user.go`其实对`internal/dao/internal/user.go`的进一步封装,用于供其他模块直接调用访问。该文件开发者可以随意修改,或者扩展`dao`的能力。 | ||
|
||
```go title="internal/dao/user.go" | ||
// ================================================================================= | ||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. | ||
// ================================================================================= | ||
package dao | ||
import ( | ||
"demo/internal/dao/internal" | ||
) | ||
// internalUserDao is internal type for wrapping internal DAO implements. | ||
type internalUserDao = *internal.UserDao | ||
// userDao is the data access object for table user. | ||
// You can define custom methods on it to extend its functionality as you wish. | ||
type userDao struct { | ||
internalUserDao | ||
} | ||
var ( | ||
// User is globally public accessible object for table user operations. | ||
User = userDao{ | ||
internal.NewUserDao(), | ||
} | ||
) | ||
// Fill with you ideas below. | ||
``` | ||
|
||
|
||
```go title="internal/dao/internal/user.go" | ||
// ========================================================================== | ||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. | ||
// ========================================================================== | ||
package internal | ||
import ( | ||
"context" | ||
"github.com/gogf/gf/v2/database/gdb" | ||
"github.com/gogf/gf/v2/frame/g" | ||
) | ||
// UserDao is the data access object for table user. | ||
type UserDao struct { | ||
table string // table is the underlying table name of the DAO. | ||
group string // group is the database configuration group name of current DAO. | ||
columns UserColumns // columns contains all the column names of Table for convenient usage. | ||
} | ||
// UserColumns defines and stores column names for table user. | ||
type UserColumns struct { | ||
Id string // user id | ||
Name string // user name | ||
Status string // user status | ||
Age string // user age | ||
} | ||
// userColumns holds the columns for table user. | ||
var userColumns = UserColumns{ | ||
Id: "id", | ||
Name: "name", | ||
Status: "status", | ||
Age: "age", | ||
} | ||
// NewUserDao creates and returns a new DAO object for table data access. | ||
func NewUserDao() *UserDao { | ||
return &UserDao{ | ||
group: "default", | ||
table: "user", | ||
columns: userColumns, | ||
} | ||
} | ||
// DB retrieves and returns the underlying raw database management object of current DAO. | ||
func (dao *UserDao) DB() gdb.DB { | ||
return g.DB(dao.group) | ||
} | ||
// Table returns the table name of current dao. | ||
func (dao *UserDao) Table() string { | ||
return dao.table | ||
} | ||
// Columns returns all column names of current dao. | ||
func (dao *UserDao) Columns() UserColumns { | ||
return dao.columns | ||
} | ||
// Group returns the configuration group name of database of current dao. | ||
func (dao *UserDao) Group() string { | ||
return dao.group | ||
} | ||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. | ||
func (dao *UserDao) Ctx(ctx context.Context) *gdb.Model { | ||
return dao.DB().Model(dao.table).Safe().Ctx(ctx) | ||
} | ||
// Transaction wraps the transaction logic using function f. | ||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error. | ||
// It commits the transaction and returns nil if function f returns nil. | ||
// | ||
// Note that, you should not Commit or Rollback the transaction in function f | ||
// as it is automatically handled by this function. | ||
func (dao *UserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { | ||
return dao.Ctx(ctx).Transaction(ctx, f) | ||
} | ||
``` | ||
|
||
|
||
|
||
### do | ||
```go title="internal/model/do/user.go" | ||
// ================================================================================= | ||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. | ||
// ================================================================================= | ||
package do | ||
import ( | ||
"github.com/gogf/gf/v2/frame/g" | ||
) | ||
// User is the golang structure of table user for DAO operations like Where/Data. | ||
type User struct { | ||
g.Meta `orm:"table:user, do:true"` | ||
Id interface{} // user id | ||
Name interface{} // user name | ||
Status interface{} // user status | ||
Age interface{} // user age | ||
} | ||
``` | ||
关于`do`数据转换模型的使用,我们将在后续代码逻辑中做展示。 | ||
|
||
### entity | ||
```go title="internal/model/entity/user.go" | ||
// ================================================================================= | ||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. | ||
// ================================================================================= | ||
|
||
package entity | ||
|
||
// User is the golang structure for table user. | ||
type User struct { | ||
Id uint `json:"id" orm:"id" ` // user id | ||
Name string `json:"name" orm:"name" ` // user name | ||
Status int `json:"status" orm:"status" ` // user status | ||
Age uint `json:"age" orm:"age" ` // user age | ||
} | ||
``` | ||
|
||
可以看到该`entity`数据结构定义与数据表字段一一对应。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
--- | ||
slug: '/quick/scaffold-api-definition' | ||
title: 'Step3 - 编写api接口定义' | ||
hide_title: true | ||
sidebar_position: 3 | ||
--- | ||
|
||
在项目的`api`目录下,我们开始定义我们的`CURD`接口。 | ||
同样的,我们默认开始使用`v1`版本。使用版本号做为良好的开发习惯,有利于未来接口的兼容性维护。 | ||
|
||
![user api definition](QQ_1731675921090.png) | ||
|
||
## 创建接口 | ||
```go title="api/user/v1/user.go" | ||
type CreateReq struct { | ||
g.Meta `path:"/user" method:"put" tags:"User" summary:"Create user"` | ||
Name string `v:"required|length:3,10" dc:"user name"` | ||
Age uint `v:"required|between:18,200" dc:"user age"` | ||
} | ||
type CreateRes struct { | ||
Id int64 `json:"id" dc:"user id"` | ||
} | ||
``` | ||
简要介绍: | ||
- 接口定义中,使用`g.Meta`来管理接口的元数据信息,这些元数据信息通过标签的形式定义在`g.Meta`属性上。这里的元数据信息包括:`path`路由地址、`method`请求方式、`tags`接口分组(用于生成接口文档)、`summary`接口描述。这些元数据信息都是`OpenAPIv3`里面的东西,我们这里不做详细介绍,大家了解即可,感兴趣可以参考开发手册相关章节。 | ||
- 这里的`Name`和`Age`属性即是咱们接口的参数定义。其中`dc`标签是`description`的缩写,表示参数的含义;`v`标签是`valid`得缩写,表示参数的校验规则。我们这里使用到了3条内置的校验规则: | ||
- `required`:该参数是必需参数。 | ||
- `length`:参数的长度校验。 | ||
- `between`:参数的大小校验。 | ||
- 更多的校验规则请参考章节 [数据校验-校验规则](../../../docs/核心组件/数据校验/数据校验-校验规则.md)。 | ||
- 请求的参数结构体`CreateReq`中,我们并没有定义参数的接收方式,因为`GoFrame`框架支持非常强大灵活的参数接收方式,能够自动识别`Query String/Form/Json/Xml`等提交方式,并将提交参数自动映射到请求参数接收对象上。 | ||
- 只有返回的参数结构体中带有`json`标签,因为返回的数据往往需要转换为`json`格式给前端使用,通过`snake`的参数命名的方式更符合前端命名习惯。 | ||
|
||
## 删除接口 | ||
|
||
```go title="api/user/v1/user.go" | ||
type DeleteReq struct { | ||
g.Meta `path:"/user/{id}" method:"delete" tags:"User" summary:"Delete user"` | ||
Id int64 `v:"required" dc:"user id"` | ||
} | ||
type DeleteRes struct{} | ||
``` | ||
|
||
删除的`HTTP Method`使用的是`delete`,可以看得出来,我们定义的接口是使用的`RESTful`风格。 | ||
|
||
## 更新接口 | ||
|
||
```go title="api/user/v1/user.go" | ||
// Status marks user status. | ||
type Status int | ||
|
||
const ( | ||
StatusOK Status = 0 // User is OK. | ||
StatusDisabled Status = 1 // User is disabled. | ||
) | ||
|
||
type UpdateReq struct { | ||
g.Meta `path:"/user/{id}" method:"post" tags:"User" summary:"Update user"` | ||
Id int64 `v:"required" dc:"user id"` | ||
Name *string `v:"length:3,10" dc:"user name"` | ||
Age *uint `v:"between:18,200" dc:"user age"` | ||
Status *Status `v:"enums" dc:"user status"` | ||
} | ||
type UpdateRes struct{} | ||
``` | ||
|
||
在这里: | ||
- 我们这里定义了一个用户状态类型`Status`,采用的是`Golang`里面约定俗成的`enums`定义方式。 | ||
- 对`Status`参数的校验使用了`enums`校验规则,该规则将会校验传递的`Status`的值必需是我们定义的常量的两个值`StatusOK/StatusDisabled`,即`0/1`。具体的使用,后续会介绍。 | ||
- 接口参数我们使用了指针来接收,目的是避免类型默认值对我们修改接口的影响。举个例子,假如`Status`不定义为指针,那么它就会有默认值`0`的影响,那么在处理逻辑中,很难判断到底调用端有没有传递该参数,是否要真正修改数值为`0`。但我们使用指针后,当用户没有传递该参数时,该参数的默认值就是`nil`,处理逻辑便很好做判断。 | ||
|
||
## 查询接口(单个) | ||
|
||
```go title="api/user/v1/user.go" | ||
type GetOneReq struct { | ||
g.Meta `path:"/user/{id}" method:"get" tags:"User" summary:"Get one user"` | ||
Id int64 `v:"required" dc:"user id"` | ||
} | ||
type GetOneRes struct { | ||
*entity.User `dc:"user"` | ||
} | ||
``` | ||
|
||
这里的返回结果我们使用了`*entity.User`结构体,该结构是前面我们通过`make dao`命令生成的`entity`,该数据结构与数据表字段一一对应。 | ||
|
||
## 查询接口(列表) | ||
|
||
```go title="api/user/v1/user.go" | ||
type GetListReq struct { | ||
g.Meta `path:"/user" method:"get" tags:"User" summary:"Get users"` | ||
Age *uint `v:"between:18,200" dc:"user age"` | ||
Status *Status `v:"enums" dc:"user age"` | ||
} | ||
type GetListRes struct { | ||
List []*entity.User `json:"list" dc:"user list"` | ||
} | ||
``` | ||
该接口可以根据`Age`和`Status`进行查询,返回的是多条记录`List []*entity.User`。 |
Oops, something went wrong.