diff --git a/README.md b/README.md index 93fa148..1812ad6 100644 --- a/README.md +++ b/README.md @@ -1 +1,259 @@ # starter-gin + +基于`github.com/gin-gonic/gin`封装的http服务组件 + +--- + +#### 功能说明 + +屏蔽其他原始框架细节,提供统一的http服务注册方法,用户只需要关心Request/Response即可 + +- 初始化 + ```go + loader := parent.NewStarterLoader([]parent.Starter{ + &ginstarter.GinStarter{ + ListenAddress: ":8080", + DebugModule: true, + Routers: []ginstarter.Router{ + &router.DemoRouter{}, + &router.ParamRouter{}, + &router.AbortRouter{}, + &router.BasicAuthRouter{}, + &router.MyRestRouter{}, + }, + InitFunc: func(instance *gin.Engine) { + instance.GET("/ping", func(context *gin.Context) { + context.String(http.StatusOK, "alive") + }) + instance.GET("/err", func(context *gin.Context) { + context.Status(500) + }) + }, + DisabledDefaultIgnoreHttpStatusCode: true, + DisableMethodNotAllowedError: true, + RecoverHandlerResponse: func(ctx *gin.Context, err any) ginstarter.Response { + logger.Logrus().Errorln("Request catch exception", err) + return ginstarter.RespTextPlain("something error", http.StatusOK) + }, + DisableHttpStatusCodeHandler: true, + }, + }) + + err := loader.Start() + if err != nil { + fmt.Printf("%+v\n", err) + return + } + + sys.ShutdownHolding() + ``` + +- 注册路由 + ```go + type RouterInfo struct { + // GroupPath 路由分组路径 + GroupPath string + + // BasicAuthAccount 如果指定基于BasicAuth认证的账户,则该GroupPath下资源将需要权限认证 + BasicAuthAccount *BasicAuthAccount + } + ``` + + 然后在初始化时指定将自动完成注册 + + ```go + type AbortRouter struct { // 业务路由 + } + + func (a *AbortRouter) Info() *ginstarter.RouterInfo { + return &ginstarter.RouterInfo{ // 配置路由信息 + GroupPath: "abort", // + } + } + + // Handlers 路由功能 + func (a *AbortRouter) Handlers(router *ginstarter.RouterWrapper) { + // 注册一个GET方法处理器 + router.GET("invoke", a.invoke()) + } + + func (a *AbortRouter) invoke() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { + + // TODO: 完成业务 + + // 响应一个http状态码203 + return ginstarter.RespAbortWithStatus(203), nil + } + } + ``` +- 请求 + 框架已封装常用的参数获取方法,在Handler中直接通过request执行,以`Must`开始的方法将在参数不满足条件时直接触发Panic,快速实现验参数不通过中断请求 + + ```go + // HttpMethod 获取请求方法 + HttpMethod() string + + // FullPath 获取请求全路径 + FullPath() string + + // RawGinContext 获取原始Gin上下文 + RawGinContext() *gin.Context + + // RequestIP 尝试获取请求方客户端IP + RequestIP() string + + + // GetPathParam 获取path路径参数 /:id/ + GetPathParam(name string) string + + // GetPathParams 获取path路径参数 /:id/ 多个参数 + GetPathParams(names ...string) map[string]string + + // BindPathParams /:id/ 绑定结构体用于接收UriPath参数 结构体标签格式 `uri:""` + BindPathParams(object any) error + + // MustBindPathParams /:id/ 绑定结构体用于接收UriPath参数 结构体标签格式 `uri:""` + // 任何错误将触发Panic流程中断 + MustBindPathParams(object any) + ... + ``` +- 响应 框架已封装常用响应体方法,方法均以`Resp`开始 + + ```go + // RespJson 响应Json数据 + func RespJson(data any, httpStatusCode ...int) Response + + // RespXml 响应Xml数据 + func RespXml(data any, httpStatusCode ...int) Response + + // RespYaml 响应Yaml数据 + func RespYaml(data any, httpStatusCode ...int) Response + + // RespToml 响应Toml数据 + func RespToml(data any, httpStatusCode ...int) Response + + // RespTextPlain 响应Json数据 + func RespTextPlain(data string, httpStatusCode ...int) Response + + // RespRedirect 响应重定向 + func RespRedirect(url string, httpStatusCode ...int) Response + ``` + #### 特别的Rest响应,默认框架已定制一套Rest响应标准 + ```go + // RestRespStatusStruct 框架默认的Rest请求状态结构 + type RestRespStatusStruct struct { + + // 标识请求系统状态 200 标识网络请求层面的成功 见StatusCode + StatusCode StatusCode `json:"statusCode"` + StatusMessage StatusMessage `json:"statusMessage"` + + // 业务错误码 仅当StatusCode为200时进入业务错误判断 + BizErrorCode *BizErrorCode `json:"bizErrorCode"` + BizErrorMessage *BizErrorMessage `json:"bizErrorMessage"` + + // 系统响应时间戳 + Timestamp int64 `json:"timestamp"` + } + + // RestRespStruct 框架默认的Rest请求结构 + type RestRespStruct struct { + + // 请求状态描述 + Status *RestRespStatusStruct `json:"status"` + + // 仅当StatusCode为200 无业务错误码BizErrorCode 响应成功数据 + Data any `json:"data"` + } + ``` + 通过`RespRest`开始的方法名执行该结构体的Rest风格响应,如果需要在此基础上响应更多信息,则可以使用`NewRespRest()`创建Rest响应实例,设置head、cookie等其他信息 + + > 如果你要自定义Rest结构体响应风格 + + 参考test/router/myrest.go + + 方法1 通过NewRespRest()实例,每次传输自定义的Rest结构体响应 + + ```go + ginstarter.NewRespRest().SetDataResponse(&RestStruct{ + Code: 200, + Msg: "success", + Data: "invoke", + }) + ``` + + 方法2 实现`Response`接口,参照NewRespRest方法设计,定制并使用自定义Response数据响应 + + ```go// 自实现Response响应数据 + // 自实现Response响应数据 + func (m *MyRestRouter) m3() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { + response := &MyRestResponse{} + response.setData("my rest impl") + return response, nil + } + } + + type MyRestResponse struct { + responseData *ginstarter.ResponseData + } + + func (m *MyRestResponse) Data() *ginstarter.ResponseData { + return m.responseData + } + + func (m *MyRestResponse) setData(data any) { + m.responseData = ginstarter.NewResponseData() + m.responseData.SetData(json.ToJsonBytes(&RestStruct{ + Code: 200, + Msg: "success", + Data: data, + })) + } + ``` + +#### 高级用法 + +```go +type GinStarter struct { + ... + // 模块组件在启动时执行初始化 + InitFunc func(instance *gin.Engine) + + // 自定义异常响应处理 如果不指定则使用默认方式 + RecoverHandlerResponse RecoverHandlerResponse + + // 禁用错误包装处理器 在出现非200响应码或者异常时,将自动进行转化 + DisableHttpStatusCodeHandler bool + // 在启用非200响应码自动处理后,指定忽略需要自动包裹响应码 + IgnoreHttpStatusCode []int + // 关闭系统内置的忽略的http状态码 + DisabledDefaultIgnoreHttpStatusCode bool + // 在出现非200响应码或者异常时具体响应策略 如果不指定则使用默认处理器 仅在UseHttpStatusCodeHandler = true 生效 + HttpStatusCodeCodeHandlerResponse HttpStatusCodeCodeHandlerResponse + + // 响应数据的结构体解码器 默认为JSON方式解码 + // 在使用NewRespRest响应结构体数据时解码为[]byte数据的解码器 + // 如果自实现Response接口将不使用解码器 + ResponseDataStructDecoder ResponseDataStructDecoder + + // 关闭包裹405错误展示,使用404代替 + DisableMethodNotAllowedError bool + + // 禁用尝试获取真实IP + DisableForwardedByClientIP bool + ... +} +``` + +- RecoverHandlerResponse + + 框架自动捕获Panic异常,并执行默认处理方案,如果你想替换默认处理逻辑,可以注册该方法的具体实现逻辑 + +- DisableHttpStatusCodeHandler + + 默认情况,当遇到非200响应码时,会自动进行响应处理,如果你不想使用默认处理方案,可以禁用该功能。IgnoreHttpStatusCode允许配置非200的例外错误码,不触发此逻辑 + +- HttpStatusCodeCodeHandlerResponse + + 在DisableHttpStatusCodeHandler为false时,如果你想替换默认的非200错误码响应处理方案,可以注册该方法的具体实现逻辑 diff --git a/ginmodule/ginloader.go b/ginstarter/ginloader.go similarity index 68% rename from ginmodule/ginloader.go rename to ginstarter/ginloader.go index c76ad47..34d57e9 100644 --- a/ginmodule/ginloader.go +++ b/ginstarter/ginloader.go @@ -1,16 +1,18 @@ -package ginmodule +package ginstarter import ( "context" "github.com/acexy/golang-toolkit/logger" + "github.com/acexy/golang-toolkit/util/net" "github.com/gin-gonic/gin" - "github.com/golang-acexy/starter-parent/parentmodule/declaration" + "github.com/golang-acexy/starter-parent/parent" "github.com/sirupsen/logrus" "net/http" "time" ) var server *http.Server +var ginEngine *gin.Engine const ( defaultListenAddress = ":8080" @@ -21,16 +23,17 @@ var ( ignoreHttpStatusCode []int ) -type GinModule struct { +type GinStarter struct { // 自定义Gin模块的组件属性 - GinModuleConfig *declaration.ModuleConfig + GinSetting *parent.Setting // 模块组件在启动时执行初始化 - GinInterceptor func(instance *gin.Engine) + InitFunc func(instance *gin.Engine) // * 注册业务路由 Routers []Router + // * 注册服务监听地址 :8080 (默认) ListenAddress string // ip:port @@ -58,29 +61,27 @@ type GinModule struct { // 关闭包裹405错误展示,使用404代替 DisableMethodNotAllowedError bool - // 开启尝试获取真实IP - ForwardedByClientIP bool + // 禁用尝试获取真实IP + DisableForwardedByClientIP bool } -func (g *GinModule) ModuleConfig() *declaration.ModuleConfig { - if g.GinModuleConfig != nil { - return g.GinModuleConfig +func (g *GinStarter) Setting() *parent.Setting { + if g.GinSetting != nil { + return g.GinSetting } - return &declaration.ModuleConfig{ - ModuleName: "Gin", - UnregisterPriority: 0, - UnregisterAllowAsync: true, - UnregisterMaxWaitSeconds: 30, - LoadInterceptor: func(instance interface{}) { - if g.GinInterceptor != nil { - g.GinInterceptor(instance.(*gin.Engine)) + return parent.NewSetting( + "Gin-Starter", + 0, + true, + time.Second*30, + func(instance interface{}) { + if g.InitFunc != nil { + g.InitFunc(instance.(*gin.Engine)) } - }, - } + }) } -func (g *GinModule) Register() (interface{}, error) { - +func (g *GinStarter) Start() (interface{}, error) { var err error if g.DebugModule { gin.SetMode(gin.DebugMode) @@ -90,26 +91,26 @@ func (g *GinModule) Register() (interface{}, error) { gin.DefaultWriter = &logrusLogger{log: logger.Logrus(), level: logrus.DebugLevel} gin.DefaultErrorWriter = &logrusLogger{log: logger.Logrus(), level: logrus.ErrorLevel} - ginEngin := gin.New() + ginEngine = gin.New() - ginEngin.Use(recoverHandler()) + ginEngine.Use(recoverHandler()) if g.RecoverHandlerResponse != nil { defaultRecoverHandlerResponse = g.RecoverHandlerResponse } if g.MaxMultipartMemory > 0 { - ginEngin.MaxMultipartMemory = g.MaxMultipartMemory + ginEngine.MaxMultipartMemory = g.MaxMultipartMemory } - ginEngin.ForwardedByClientIP = g.ForwardedByClientIP + ginEngine.ForwardedByClientIP = !g.DisableForwardedByClientIP if !g.DisableMethodNotAllowedError { - ginEngin.HandleMethodNotAllowed = true + ginEngine.HandleMethodNotAllowed = true } if !g.DisableHttpStatusCodeHandler { - ginEngin.Use(responseRewriteHandler()) - ginEngin.Use(httpStatusCodeHandler()) + ginEngine.Use(responseRewriteHandler()) + ginEngine.Use(httpStatusCodeHandler()) disabledDefaultIgnoreHttpStatusCode = g.DisabledDefaultIgnoreHttpStatusCode ignoreHttpStatusCode = g.IgnoreHttpStatusCode if g.HttpStatusCodeCodeHandlerResponse != nil { @@ -122,7 +123,7 @@ func (g *GinModule) Register() (interface{}, error) { } if len(g.Routers) > 0 { - registerRouter(ginEngin, g.Routers) + registerRouter(ginEngine, g.Routers) } if g.ListenAddress == "" { @@ -131,30 +132,37 @@ func (g *GinModule) Register() (interface{}, error) { server = &http.Server{ Addr: g.ListenAddress, - Handler: ginEngin, + Handler: ginEngine, } + status := make(chan error) go func() { - logger.Logrus().Traceln(g.ModuleConfig().ModuleName, "started") if err = server.ListenAndServe(); err != nil { status <- err } }() + select { case <-time.After(time.Second): - return ginEngin, nil + return ginEngine, nil case err = <-status: - return ginEngin, err + return ginEngine, err } } -func (g *GinModule) Unregister(maxWaitSeconds uint) (gracefully bool, err error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(maxWaitSeconds)*time.Second) +func (g *GinStarter) Stop(maxWaitTime time.Duration) (gracefully, stopped bool, err error) { + ctx, cancel := context.WithTimeout(context.Background(), maxWaitTime) defer cancel() if err = server.Shutdown(ctx); err != nil { gracefully = false } else { gracefully = true } + stopped = !net.Telnet(g.ListenAddress, time.Second) return } + +// RawGinEngine 获取原始的gin引擎实例 +func RawGinEngine() *gin.Engine { + return ginEngine +} diff --git a/ginmodule/logruslogger.go b/ginstarter/logruslogger.go similarity index 92% rename from ginmodule/logruslogger.go rename to ginstarter/logruslogger.go index 9c857c6..4be06ed 100644 --- a/ginmodule/logruslogger.go +++ b/ginstarter/logruslogger.go @@ -1,4 +1,4 @@ -package ginmodule +package ginstarter import "github.com/sirupsen/logrus" diff --git a/ginmodule/middleware.go b/ginstarter/middleware.go similarity index 99% rename from ginmodule/middleware.go rename to ginstarter/middleware.go index a4ebbcc..7f9da91 100644 --- a/ginmodule/middleware.go +++ b/ginstarter/middleware.go @@ -1,4 +1,4 @@ -package ginmodule +package ginstarter import ( "bytes" diff --git a/ginmodule/request.go b/ginstarter/request.go similarity index 99% rename from ginmodule/request.go rename to ginstarter/request.go index 1976593..9323c81 100644 --- a/ginmodule/request.go +++ b/ginstarter/request.go @@ -1,4 +1,4 @@ -package ginmodule +package ginstarter import ( "errors" diff --git a/ginmodule/response.go b/ginstarter/response.go similarity index 97% rename from ginmodule/response.go rename to ginstarter/response.go index 315084d..a991b98 100644 --- a/ginmodule/response.go +++ b/ginstarter/response.go @@ -1,4 +1,4 @@ -package ginmodule +package ginstarter import ( "github.com/acexy/golang-toolkit/logger" @@ -186,8 +186,8 @@ func RespHttpStatusCode(statusCode int) Response { }} } -// RespAbortWithStatus 设置响应状态码并设置忽略执行后续handler -func RespAbortWithStatus(statusCode int) Response { +// RespAbortWithHttpStatusCode 设置响应状态码并设置忽略执行后续handler +func RespAbortWithHttpStatusCode(statusCode int) Response { return &commonResp{ginFn: func(context *gin.Context) { context.AbortWithStatus(statusCode) }} diff --git a/ginmodule/rest.go b/ginstarter/rest.go similarity index 99% rename from ginmodule/rest.go rename to ginstarter/rest.go index 51ebc6c..620756e 100644 --- a/ginmodule/rest.go +++ b/ginstarter/rest.go @@ -1,4 +1,4 @@ -package ginmodule +package ginstarter type StatusCode int type StatusMessage string diff --git a/ginmodule/router.go b/ginstarter/router.go similarity index 96% rename from ginmodule/router.go rename to ginstarter/router.go index 1c5293f..7937cab 100644 --- a/ginmodule/router.go +++ b/ginstarter/router.go @@ -1,4 +1,4 @@ -package ginmodule +package ginstarter import ( "github.com/gin-gonic/gin" diff --git a/ginmodule/wrapper.go b/ginstarter/wrapper.go similarity index 99% rename from ginmodule/wrapper.go rename to ginstarter/wrapper.go index cfa0056..97f97ea 100644 --- a/ginmodule/wrapper.go +++ b/ginstarter/wrapper.go @@ -1,4 +1,4 @@ -package ginmodule +package ginstarter import ( "bytes" diff --git a/go.mod b/go.mod index 3c788c3..3a395a1 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/golang-acexy/starter-gin go 1.20 require ( - github.com/acexy/golang-toolkit v0.0.10 + github.com/acexy/golang-toolkit v0.0.11 github.com/gin-gonic/gin v1.10.0 - github.com/golang-acexy/starter-parent v0.0.6 + github.com/golang-acexy/starter-parent v0.1.1 github.com/sirupsen/logrus v1.9.3 ) diff --git a/go.sum b/go.sum index f870afe..cad047c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/acexy/golang-toolkit v0.0.10 h1:XwToFSGz0zQr6DNBWuVJlv91YihQZ5SyFa/AdKwC9mo= -github.com/acexy/golang-toolkit v0.0.10/go.mod h1:2xhHYl8xxybJx4q6/ZzcqVbRZtl0MW9ytxUdkjxJp7A= +github.com/acexy/golang-toolkit v0.0.11 h1:RxZ6rY9GSvH7JqfbSNoUd2IEBGJjJ7XWdcovFDxSmj0= +github.com/acexy/golang-toolkit v0.0.11/go.mod h1:lZn+XmM/H0Y3AQ3G4BiDwkiKbBXCgGVeTCz02ILhc0s= github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= @@ -26,8 +26,8 @@ github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4 github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/golang-acexy/starter-parent v0.0.6 h1:NtnCykpaQj1MxbIyk0FwuTrSZ1W7qWXvOJ2lNxprg60= -github.com/golang-acexy/starter-parent v0.0.6/go.mod h1:ogG+h4P2lt/opG3laeNg6Q75KFryvct0g/k9JZGPODU= +github.com/golang-acexy/starter-parent v0.1.1 h1:KSf57ItnJfXhP9WZ6Yq9nRLzVsoWr8gOA4qS4CC3wiU= +github.com/golang-acexy/starter-parent v0.1.1/go.mod h1:lp09SvT0Rsd27M0Zpd+pzKIHjspvKnczAH0TxFfmFLA= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= diff --git a/test/ginstarter_test.go b/test/ginstarter_test.go index f828d0b..3584765 100644 --- a/test/ginstarter_test.go +++ b/test/ginstarter_test.go @@ -4,51 +4,48 @@ import ( "fmt" "github.com/acexy/golang-toolkit/logger" "github.com/acexy/golang-toolkit/sys" + "github.com/acexy/golang-toolkit/util/json" "github.com/gin-gonic/gin" - "github.com/golang-acexy/starter-gin/ginmodule" + "github.com/golang-acexy/starter-gin/ginstarter" "github.com/golang-acexy/starter-gin/test/router" - "github.com/golang-acexy/starter-parent/parentmodule/declaration" + "github.com/golang-acexy/starter-parent/parent" "net/http" "testing" "time" ) -var moduleLoaders []declaration.ModuleLoader +var starterLoader *parent.StarterLoader func init() { - interceptor := func(instance *gin.Engine) { - // 使用interceptor的形式,获取原始gin实例 注册一个伪探活服务 - instance.GET("/ping", func(context *gin.Context) { - context.String(http.StatusOK, "alive") - }) - instance.GET("/err", func(context *gin.Context) { - context.Status(500) - }) - } - moduleLoaders = []declaration.ModuleLoader{&ginmodule.GinModule{ - ListenAddress: ":8080", - DebugModule: true, - Routers: []ginmodule.Router{ - &router.DemoRouter{}, - &router.ParamRouter{}, - &router.AbortRouter{}, - &router.BasicAuthRouter{}, - &router.MyRestRouter{}, + starterLoader = parent.NewStarterLoader([]parent.Starter{ + &ginstarter.GinStarter{ + ListenAddress: ":8080", + DebugModule: true, + Routers: []ginstarter.Router{ + &router.DemoRouter{}, + &router.ParamRouter{}, + &router.AbortRouter{}, + &router.BasicAuthRouter{}, + &router.MyRestRouter{}, + }, + InitFunc: func(instance *gin.Engine) { + instance.GET("/ping", func(context *gin.Context) { + context.String(http.StatusOK, "alive") + }) + instance.GET("/err", func(context *gin.Context) { + context.Status(500) + }) + }, + DisabledDefaultIgnoreHttpStatusCode: true, }, - GinInterceptor: interceptor, - DisabledDefaultIgnoreHttpStatusCode: true, - }} - + }) } // 默认Gin表现行为 // 启用了非200状态码自动包裹响应 func TestGinDefault(t *testing.T) { - module := declaration.Module{ - ModuleLoaders: moduleLoaders, - } - err := module.Load() + err := starterLoader.Start() if err != nil { fmt.Printf("%+v\n", err) return @@ -62,19 +59,36 @@ func TestGinDefault(t *testing.T) { // 自定义panic异常响应 func TestGinCustomer(t *testing.T) { - ginModule := moduleLoaders[0] - ginConfig, _ := ginModule.(*ginmodule.GinModule) - ginConfig.DisableMethodNotAllowedError = true - ginConfig.RecoverHandlerResponse = func(ctx *gin.Context, err any) ginmodule.Response { - logger.Logrus().Errorln("Request catch exception", err) - return ginmodule.RespTextPlain("something error", http.StatusOK) - } - ginConfig.DisableHttpStatusCodeHandler = true - module := declaration.Module{ - ModuleLoaders: moduleLoaders, - } + loader := parent.NewStarterLoader([]parent.Starter{ + &ginstarter.GinStarter{ + ListenAddress: ":8080", + DebugModule: true, + Routers: []ginstarter.Router{ + &router.DemoRouter{}, + &router.ParamRouter{}, + &router.AbortRouter{}, + &router.BasicAuthRouter{}, + &router.MyRestRouter{}, + }, + InitFunc: func(instance *gin.Engine) { + instance.GET("/ping", func(context *gin.Context) { + context.String(http.StatusOK, "alive") + }) + instance.GET("/err", func(context *gin.Context) { + context.Status(500) + }) + }, + DisabledDefaultIgnoreHttpStatusCode: true, + DisableMethodNotAllowedError: true, + RecoverHandlerResponse: func(ctx *gin.Context, err any) ginstarter.Response { + logger.Logrus().Errorln("Request catch exception", err) + return ginstarter.RespTextPlain("something error", http.StatusOK) + }, + DisableHttpStatusCodeHandler: true, + }, + }) - err := module.Load() + err := loader.Start() if err != nil { fmt.Printf("%+v\n", err) return @@ -84,18 +98,16 @@ func TestGinCustomer(t *testing.T) { } func TestGinLoadAndUnload(t *testing.T) { - module := declaration.Module{ - ModuleLoaders: moduleLoaders, - } - - err := module.Load() + err := starterLoader.Start() if err != nil { fmt.Printf("%+v\n", err) return } - time.Sleep(time.Second * 5) - - shutdownResult := module.UnloadByConfig() - fmt.Printf("%+v\n", shutdownResult) + stopResult, err := starterLoader.StopBySetting() + if err != nil { + fmt.Printf("%+v\n", err) + return + } + fmt.Println(json.ToJsonFormat(stopResult)) } diff --git a/test/router/abort.go b/test/router/abort.go index a5d3fd8..b0f3dad 100644 --- a/test/router/abort.go +++ b/test/router/abort.go @@ -1,24 +1,24 @@ package router import ( - "github.com/golang-acexy/starter-gin/ginmodule" + "github.com/golang-acexy/starter-gin/ginstarter" ) type AbortRouter struct { } -func (a *AbortRouter) Info() *ginmodule.RouterInfo { - return &ginmodule.RouterInfo{ +func (a *AbortRouter) Info() *ginstarter.RouterInfo { + return &ginstarter.RouterInfo{ GroupPath: "abort", } } -func (a *AbortRouter) Handlers(router *ginmodule.RouterWrapper) { +func (a *AbortRouter) Handlers(router *ginstarter.RouterWrapper) { router.GET("invoke", a.invoke()) } -func (a *AbortRouter) invoke() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { - return ginmodule.RespAbortWithStatus(203), nil +func (a *AbortRouter) invoke() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { + return ginstarter.RespAbortWithHttpStatusCode(203), nil } } diff --git a/test/router/basicauth.go b/test/router/basicauth.go index 3fe916b..5a25f06 100644 --- a/test/router/basicauth.go +++ b/test/router/basicauth.go @@ -1,26 +1,26 @@ package router -import "github.com/golang-acexy/starter-gin/ginmodule" +import "github.com/golang-acexy/starter-gin/ginstarter" type BasicAuthRouter struct { } -func (a *BasicAuthRouter) Info() *ginmodule.RouterInfo { - return &ginmodule.RouterInfo{ +func (a *BasicAuthRouter) Info() *ginstarter.RouterInfo { + return &ginstarter.RouterInfo{ GroupPath: "auth", - BasicAuthAccount: &ginmodule.BasicAuthAccount{ + BasicAuthAccount: &ginstarter.BasicAuthAccount{ Username: "acexy", Password: "acexy", }, } } -func (a *BasicAuthRouter) Handlers(router *ginmodule.RouterWrapper) { +func (a *BasicAuthRouter) Handlers(router *ginstarter.RouterWrapper) { router.GET("invoke", a.invoke()) } -func (a *BasicAuthRouter) invoke() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { - return ginmodule.RespTextPlain("request auth success"), nil +func (a *BasicAuthRouter) invoke() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { + return ginstarter.RespTextPlain("request auth success"), nil } } diff --git a/test/router/demo.go b/test/router/demo.go index 11db47a..309212f 100644 --- a/test/router/demo.go +++ b/test/router/demo.go @@ -3,7 +3,7 @@ package router import ( "errors" "fmt" - "github.com/golang-acexy/starter-gin/ginmodule" + "github.com/golang-acexy/starter-gin/ginstarter" "net/http" "time" ) @@ -11,13 +11,13 @@ import ( type DemoRouter struct { } -func (d *DemoRouter) Info() *ginmodule.RouterInfo { - return &ginmodule.RouterInfo{ +func (d *DemoRouter) Info() *ginstarter.RouterInfo { + return &ginstarter.RouterInfo{ GroupPath: "demo", } } -func (d *DemoRouter) Handlers(router *ginmodule.RouterWrapper) { +func (d *DemoRouter) Handlers(router *ginstarter.RouterWrapper) { router.MATCH([]string{http.MethodGet, http.MethodPost}, "more", d.more()) @@ -33,46 +33,46 @@ func (d *DemoRouter) Handlers(router *ginmodule.RouterWrapper) { router.GET("redirect", d.redirect()) } -func (d *DemoRouter) more() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *DemoRouter) more() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { fmt.Println("invoke") // 通过Builder来响应自定义Rest数据 并设置其他http属性 - return ginmodule.NewRespRest().DataBuilder(func(data *ginmodule.ResponseData) { - data.SetStatusCode(http.StatusAccepted).SetData([]byte("success")).AddHeader(ginmodule.NewHeader("test", "test")) + return ginstarter.NewRespRest().DataBuilder(func(data *ginstarter.ResponseData) { + data.SetStatusCode(http.StatusAccepted).SetData([]byte("success")).AddHeader(ginstarter.NewHeader("test", "test")) }), nil } } -func (d *DemoRouter) error1() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *DemoRouter) error1() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { // 通过error响应异常请求 return nil, errors.New("return error") } } -func (d *DemoRouter) error2() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *DemoRouter) error2() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { // 通过未处理的崩溃触发异常 panic("panic exception") } } -func (d *DemoRouter) hold() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *DemoRouter) hold() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { fmt.Println("invoke") time.Sleep(time.Second * 5) - return ginmodule.RespTextPlain("text"), nil + return ginstarter.RespTextPlain("text"), nil } } -func (d *DemoRouter) empty() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *DemoRouter) empty() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { return nil, nil } } -func (d *DemoRouter) redirect() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { - return ginmodule.RespRedirect("https://google.com"), nil +func (d *DemoRouter) redirect() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { + return ginstarter.RespRedirect("https://google.com"), nil } } diff --git a/test/router/myrest.go b/test/router/myrest.go index f5bc709..4fc12f5 100644 --- a/test/router/myrest.go +++ b/test/router/myrest.go @@ -2,7 +2,7 @@ package router import ( "github.com/acexy/golang-toolkit/util/json" - "github.com/golang-acexy/starter-gin/ginmodule" + "github.com/golang-acexy/starter-gin/ginstarter" ) // RestStruct 自定义的Rest结构体 @@ -15,29 +15,29 @@ type RestStruct struct { type MyRestRouter struct { } -func (m *MyRestRouter) Info() *ginmodule.RouterInfo { - return &ginmodule.RouterInfo{ +func (m *MyRestRouter) Info() *ginstarter.RouterInfo { + return &ginstarter.RouterInfo{ GroupPath: "my-rest", } } -func (m *MyRestRouter) Handlers(router *ginmodule.RouterWrapper) { +func (m *MyRestRouter) Handlers(router *ginstarter.RouterWrapper) { router.GET("m1", m.m1()) router.GET("m2", m.m2()) router.GET("m3", m.m3()) } // 使用框架自带的Rest响应默认Rest结构体 -func (m *MyRestRouter) m1() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { - return ginmodule.RespRestSuccess("data part"), nil +func (m *MyRestRouter) m1() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { + return ginstarter.RespRestSuccess("data part"), nil } } // 使用框架自带的Rest响应自定义结构体 -func (m *MyRestRouter) m2() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { - return ginmodule.NewRespRest().SetDataResponse(&RestStruct{ +func (m *MyRestRouter) m2() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { + return ginstarter.NewRespRest().SetDataResponse(&RestStruct{ Code: 200, Msg: "success", Data: "invoke", @@ -46,27 +46,27 @@ func (m *MyRestRouter) m2() ginmodule.HandlerWrapper { } // 自实现Response响应数据 -func (m *MyRestRouter) m3() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (m *MyRestRouter) m3() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { response := &MyRestResponse{} - response.setData(&RestStruct{ - Code: 200, - Msg: "success", - Data: "my rest impl", - }) + response.setData("my rest impl") return response, nil } } type MyRestResponse struct { - responseData *ginmodule.ResponseData + responseData *ginstarter.ResponseData } -func (m *MyRestResponse) Data() *ginmodule.ResponseData { +func (m *MyRestResponse) Data() *ginstarter.ResponseData { return m.responseData } -func (m *MyRestResponse) setData(data *RestStruct) { - m.responseData = ginmodule.NewResponseData() - m.responseData.SetData(json.ToJsonBytes(data)) +func (m *MyRestResponse) setData(data any) { + m.responseData = ginstarter.NewResponseData() + m.responseData.SetData(json.ToJsonBytes(&RestStruct{ + Code: 200, + Msg: "success", + Data: data, + })) } diff --git a/test/router/param.go b/test/router/param.go index ea0ea85..2d20497 100644 --- a/test/router/param.go +++ b/test/router/param.go @@ -2,19 +2,19 @@ package router import ( "fmt" - "github.com/golang-acexy/starter-gin/ginmodule" + "github.com/golang-acexy/starter-gin/ginstarter" ) type ParamRouter struct { } -func (d *ParamRouter) Info() *ginmodule.RouterInfo { - return &ginmodule.RouterInfo{ +func (d *ParamRouter) Info() *ginstarter.RouterInfo { + return &ginstarter.RouterInfo{ GroupPath: "param", } } -func (d *ParamRouter) Handlers(router *ginmodule.RouterWrapper) { +func (d *ParamRouter) Handlers(router *ginstarter.RouterWrapper) { // demo path /param/uri-path/101/acexy router.GET("uri-path/:id/:name", d.path()) // demo path /param/uri-path/query?id=1&name=acexy @@ -45,8 +45,8 @@ type BodyFormUser struct { Name string `form:"name" binding:"required"` } -func (d *ParamRouter) path() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *ParamRouter) path() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { fmt.Println("Request Ip", request.RequestIP()) // 获取url路径参数 uriParams := request.GetPathParams("id", "name", "unknown") @@ -55,34 +55,34 @@ func (d *ParamRouter) path() ginmodule.HandlerWrapper { user := new(UriPathUser) request.MustBindPathParams(user) fmt.Printf("%+v\n", user) - return ginmodule.RespRestSuccess(), nil + return ginstarter.RespRestSuccess(), nil } } -func (d *ParamRouter) query() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *ParamRouter) query() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { user := new(UriQueryUser) // demo path /param/uri-path/query?name=acexy 触发参数错误 request.BindQueryParams(user) fmt.Printf("%+v\n", user) - return ginmodule.RespRestSuccess(), nil + return ginstarter.RespRestSuccess(), nil } } -func (d *ParamRouter) json() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *ParamRouter) json() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { user := BodyJsonUser{} request.BindBodyJson(&user) fmt.Printf("%+v\n", user) - return ginmodule.RespRestSuccess(), nil + return ginstarter.RespRestSuccess(), nil } } -func (d *ParamRouter) form() ginmodule.HandlerWrapper { - return func(request *ginmodule.Request) (ginmodule.Response, error) { +func (d *ParamRouter) form() ginstarter.HandlerWrapper { + return func(request *ginstarter.Request) (ginstarter.Response, error) { user := BodyFormUser{} request.BindBodyForm(&user) fmt.Printf("%+v\n", user) - return ginmodule.RespRestSuccess(), nil + return ginstarter.RespRestSuccess(), nil } } diff --git a/test/test.http b/test/test.http deleted file mode 100644 index 68d0bd1..0000000 --- a/test/test.http +++ /dev/null @@ -1,12 +0,0 @@ -### Basic Authorization鉴权 不通过 -GET http://localhost:8080/auth/invoke - -### Basic Authorization鉴权 通过 -GET http://localhost:8080/auth/invoke -Authorization: Basic YWNleHk6YWNleHk= - -### 404 -GET localhost:8080/auth/invoke1 - -### demo/more -GET localhost:8080/demo/more \ No newline at end of file