GF框架:https://www.topgoer.cn/docs/goframe
如果是业务类型项目,GoFrame
官方推荐的Go
项目目录结构如下:
/
├── app
│ ├── api
│ ├── model
│ └── service
├── boot
├── config
├── docker
├── document
├── i18n
├── library
├── packed
├── public
├── router
├── template
├── vendor
├── Dockerfile
├── go.mod
└── main.go
称 | 说明 | 描述 |
---|---|---|
app |
业务逻辑层 | 所有的业务逻辑存放目录。 |
- api |
业务接口 | 接收/解析用户输入参数的入口/接口层。 |
- model |
数据模型 | 数据管理层,仅用于操作管理数据,如数据库操作。 |
- service |
逻辑封装 | 业务逻辑封装层,实现特定的业务需求,可供不同的包调用。 |
boot |
初始化包 | 用于项目初始化参数设置,往往作为main.go 中第一个被import 的包。 |
config |
配置管理 | 所有的配置文件存放目录。 |
docker |
镜像文件 | Docker镜像相关依赖文件,脚本文件等等。 |
document |
项目文档 | Documentation项目文档,如: 设计文档、帮助文档等等。 |
i18n |
I18N国际化 | I18N国际化配置文件目录。 |
library |
公共库包 | 公共的功能封装包,往往不包含业务需求实现。 |
packed |
打包目录 | 将资源文件打包的Go 文件存放在这里,boot 包初始化时会自动调用。 |
public |
静态目录 | 仅有该目录下的文件才能对外提供静态服务访问。 |
router |
路由注册 | 用于路由统一的注册管理。 |
template |
模板文件 | MVC模板文件存放的目录。 |
vendor |
第三方包 | 第三方依赖包存放目录(可选, 未来会被淘汰)。 |
Dockerfile |
镜像描述 | 云原生时代用于编译生成Docker镜像的描述文件。 |
go.mod |
依赖管理 | 使用Go Module 包管理的依赖描述文件。 |
main.go |
入口文件 | 程序入口文件。 |
GF
官方推荐的项目目录结构采用的是MVC
设计模式,准确的说是”MVCS
“模式。
- 控制器代码位于
/app/api
。控制器负责接收并响应客户端的输入与输出,包括对输入参数的过滤、转换、校验,对输出数据结构的维护,并调用service
实现业务逻辑处理。 app/api就是对应php的Yii框架的Controller层。 - 逻辑封装的代码位于
/app/service
。业务逻辑是需要封装的,特别是一些可复用的业务逻辑,并被控制器调用实现业务逻辑处理。 - 数据模型的代码位于
/app/model
。数据模型负责维护所有的数据操作,特别是对数据库的访问控制。数据模型往往是被service
调用,不推荐通过控制器直接访问数据模型。 - 模板解析是可选的,模板文件的存放于
/template
。在实践中往往可以采用MVVM
的模式,例如使用vue
/react
等框架实现模板解析。如果使用经典的模板解析,可以通过GF
框架强大的模板引擎实现模板解析。这个/template相当于是view层。
开发约束:
包名定义,言简意赅,且推荐通过不同的
import
路径来区分相同包名的包引入。控制器。
- 结构体定义用来约束控制器的输入输出,比如虽然仅有一个参数,但也采用了结构化定义,我们直接查看该结构体便可得知该接口的输入参数格式,而不用进入代码中去分析,从而极大提高维护效率。结构体转换可以使用
GetStruct
或者Parse
方法,其中Parse
同时可以执行数据校验。结构体转换方法的参数都可以给定一个结构体的空指针,内部会自动初始化结构体对象,转换失败(例如提交参数不存在)不会执行初始化。可以通过给结构体绑定v
的标签进行设定校验规则以及定义的错误提示。例如:
// 账号唯一性检测请求参数,用于前后端交互参数格式约定 type CheckPassportRequest struct { Passport string }
// 结构体转换
var data *SignUpRequest
// 这里没有使用Parse而是仅用GetStruct获取对象, // 数据校验交给后续的service层统一处理。 if err := r.GetStruct(&data); err != nil { response.JsonExit(r, 1, err.Error()) }
// 登录请求参数,用于前后端交互参数格式约定。 这个就是提示下吧?会直接拦截校验空了吗? type SignInRequest struct { Passport string `v:"required#账号不能为空"` Password string `v:"required#密码不能为空"` }
- 控制器负责接收、转换、校验、处理请求参数后,将所需的参数传递给调用的
service
层一个或者多个包方法,而不是直接将Request
对象传递给service
。例如:// 用户登录接口 func (c *C) SignIn(r *ghttp.Request) { var data *SignInRequest if err := r.Parse(&data); err != nil { //请求参数解析到结构化对象data中 response.JsonExit(r, 1, err.Error()) } //仅仅把service层需要的参数传递给service,注意这里Session也是通过控制器传过去的 if err := user.SignIn(data.Passport, data.Password, r.Session); err != nil { response.JsonExit(r, 1, err.Error()) } else { response.JsonExit(r, 0, "ok") } }
.......api层和service层,请求参数输入结构体以及简单的校验规则的放置于控制器api
中管理,然后往往通过gconv.Struct
方法转换为service
对应方法需要的输入参数
.......api
的输入参数与service
的输入参数数据结构往往比较类似,但不是完全一致,但两者相同属性的数据类型往往需要一一对应,以方便转换。api
层请求输入参数:// 注册请求参数,用于前后端交互参数格式约定 type SignUpRequest struct { Passport string `v:"required|length:6,16#账号不能为空|账号长度应当在:min到:max之间"` Password string `v:"required|length:6,16#请输入确认密码|密码长度应当在:min到:max之间"` Password2 string `v:"required|length:6,16|same:Password#密码不能为空|密码长度应当在:min到:max之间|两次密码输入不相等"` Nickname string }
service
层对应方法输入参数:// 注册输入参数 type SignUpParam struct { Passport string Password string Password2 string Nickname string }
api
请求参数到service
输入参数的转换:func (c *C) SignUp(r *ghttp.Request) { var ( data *SignUpRequest signUpParam *user.SignUpParam ) if err := r.Parse(&data); err != nil { response.JsonExit(r, 1, err.Error()) } if err := gconv.Struct(data, &signUpParam); err != nil { response.JsonExit(r, 1, err.Error()) } if err := user.SignUp(signUpParam); err != nil { response.JsonExit(r, 1, err.Error()) } else { response.JsonExit(r, 0, "ok") } }
在
Go
的HTTP请求流程中,不存在”全局变量”获取请求参数的方式,只有根据service
的需要按需传递参数。 - 中间件使用,middleware? https://www.topgoer.cn/docs/goframe/goframe-1cm3sofvosh6l ???看视频再学习下
- 基础类库,主要固定返回数据格式及数据结构。其中
JsonExit
与Json
的区别在于,JsonExit
调用时会输出JSON
数据后直接退出当前的路由方法;而Json
在执行输出后会继续执行后续的路由方法逻辑。JsonExit 会多出来r.Exit()的逻辑。
- 启动执行,引入包。boot包、router包需要在最开始引入,可以在包前加上_ 。https://www.topgoer.cn/docs/goframe/goframe-1cm3spkv6ak16
- 路由注册https://www.topgoer.cn/docs/goframe/goframe-1cm3spemitknf ???看视频再学习下
- 配置文件config.toml。在
boot
包中执行代码层级的初始化,比如一些组件模块的设置。 -
- 任何时候,您都可以通过
g.Server()
方法获得一个默认的Server
对象,该方法采用单例模式
设计,也就是说,多次调用该方法,返回的是同一个Server
对象。通过Run()
方法执行Server
的监听运行,在没有任何额外设置的情况下,它默认监听80
端口。 - 一些web操作等,看