①. 三层架构模式,并不是MVC,在go-kit中也有使用了.
a. 功能比较简单的项目可以不使用这种模式.
b. 适合项目移植.
②. 考虑到可扩展性:
a. 整个业务代码写完后,框架都变化了,使用其它的框架,需要快速修改和切换.
b. 需要有一定的模式.
c. 有了一定的架构后,代码基本上不用变,只要改相关的接口部分.
d. gin web框架的代码,如果换成微服务框架grpc,使用proto文件生成对应的文件,移植起来比较方便.
v1.Handle("GET", "/prods", func(context *gin.Context) {
// result := []*Models.Books{}
// 另一种写法:如果加了*指针,下面就不用加&
result := Models.BookList{}
Init.GetDB().Limit(10).Order("book_id desc").Find(&result)
context.JSON(http.StatusOK, result)
})
注:
①. Handle的第三个参数,这个函数最终是要返回一个func,只要有context *gin.Context这个参数就可以(v1才能识别).
=> 关键是要返回一个func(context *gin.Context)
②. 如果有参数,怎么获取?
=> 参数包括url形式的、form形式的、json形式的.
③. result := Models.BookList{}
Init.GetDB().Limit(10).Order("book_id desc").Find(&result)
=> 这两句代码用面向对象来讲就是属于哪一个类的方法,属于哪个struct.
④. result获取出来了,一定是用json返回吗?是否还有其它方式,并不仅仅是输出字符串.
⑤. 以上都需要相关机制来控制的,并不是直接在函数中写死.
func RegisterHandler(怎么取参数, 业务最终函数, 怎么处理业务结果) func(context *gin.Context) {
return func(context *gin.Context) {
// 参数到底是url、form、json的?是否需要做验证?也不一定会有参数.
1. 参数 := 怎么取参数()
// 到底怎么取?取什么?比如在数据库中取值.
2. 业务结果 := 业务最终函数(context, 参数)
// 执行完成了返回什么?返回json只是一种方式,保存文件也是一种方式.
3. 怎么处理业务结果(业务结果)
}
}
注:
①. 3个形参都是函数,最终只要返回一个context *gin.Context的func,v1路由就能识别.
②. 为了和业务进行解耦,这3个函数不能写死,是一个通用的.并不是某个产品、订单的函数.
④. 约定所有使用到对象都使用指针. => 为了统一规范.
⑤. 不过过渡依赖gin的封装的便捷方法. => 尽量与框架无关,可移值性比较高的方式.
(1). BsyErp\Contract\App\Lib\ServiceHelper.go:
package Lib
import (
"context"
"net/http"
)
// 怎么取参数
// 为了兼容不同的业务,统一使用interface,而不使用业务的struct
type EncodeRequestFunc func(*gin.Context) (interface{}, error)
// 业务最终函数,request是参数
// 业务结果 := 业务最终函数(参数)
type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
// 怎么处理响应
type DecodeResponseFunc func(*gin.Context, interface{}) error
func RegisterHandler(encodeFunc EncodeRequestFunc, endpoint Endpoint, decodeFunc DecodeResponseFunc) func(context *gin.Context) {
return func(ctx *gin.Context) {
// 获取参数
req, err := encodeFunc(ctx)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"ServerNo": "SN500", "ResultData": "参数错误:" + err.Error()})
return
}
// 执行业务过程
res, err := endpoint(ctx, req)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"ServerNo": "SN500", "ResultData": "执行错误:" + err.Error()})
return
}
// 处理业务执行结果
err = decodeFunc(ctx, res)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"ServerNo": "SN500", "ResultData": "返回错误:" + err.Error()})
}
}
}
注:
①. 三个参数都是函数类型,传入函数,最终执行函数.