|
@@ -0,0 +1,172 @@
|
|
|
|
+package http_binding
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "git.sxidc.com/service-supports/fserr"
|
|
|
|
+ "github.com/gin-gonic/gin"
|
|
|
|
+ "lcp/api/binding/http_binding/binding_context"
|
|
|
|
+ "lcp/api/binding/http_binding/middleware"
|
|
|
|
+ "lcp/api/binding/http_binding/request"
|
|
|
|
+ "lcp/api/binding/http_binding/response"
|
|
|
|
+ "lcp/utils"
|
|
|
|
+ "net/http"
|
|
|
|
+ "reflect"
|
|
|
|
+ "strings"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+type BusinessFunc[I any, O any] func(c *binding_context.Context, inputModel I) (O, error)
|
|
|
|
+type BindingFunc[O any] func(c *binding_context.Context, request any, sendFunc response.SendFunc[O]) bool
|
|
|
|
+
|
|
|
|
+type Binding struct {
|
|
|
|
+ RouterGroup *gin.RouterGroup
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func NewBinding(apiVersion string, middlewares ...middleware.Func) *Binding {
|
|
|
|
+ apiPrefix := urlPrefix + "/api"
|
|
|
|
+ if utils.IsStringNotEmpty(apiVersion) && apiVersion != "root" {
|
|
|
|
+ apiPrefix += "/" + apiVersion
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ginMiddlewares := make([]gin.HandlerFunc, 0)
|
|
|
|
+ for _, m := range middlewares {
|
|
|
|
+ ginMiddlewares = append(ginMiddlewares, func(c *gin.Context) {
|
|
|
|
+ m(&binding_context.Context{Context: c})
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return &Binding{RouterGroup: routerInstance.Group(apiPrefix, ginMiddlewares...)}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func PostBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
|
|
|
|
+ item.bind(b.RouterGroup, http.MethodPost, middlewares...)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func DeleteBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
|
|
|
|
+ item.bind(b.RouterGroup, http.MethodDelete, middlewares...)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func PutBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
|
|
|
|
+ item.bind(b.RouterGroup, http.MethodPut, middlewares...)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func GetBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
|
|
|
|
+ item.bind(b.RouterGroup, http.MethodGet, middlewares...)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func Bind[I any, O any](b *Binding, item *BindItem[I, O], middlewares ...middleware.Func) {
|
|
|
|
+ item.bind(b.RouterGroup, middlewares...)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func Static(b *Binding, item *StaticBindItem) {
|
|
|
|
+ item.bind(b.RouterGroup)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+type SimpleBindItem[I any, O any] struct {
|
|
|
|
+ Path string
|
|
|
|
+ ResponseFunc response.SendFunc[O]
|
|
|
|
+ BusinessFunc BusinessFunc[I, O]
|
|
|
|
+ OptionalBindingFunc BindingFunc[O]
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (item *SimpleBindItem[I, O]) bind(routerGroup *gin.RouterGroup, method string, middlewares ...middleware.Func) {
|
|
|
|
+ bindingItem := &BindItem[I, O]{
|
|
|
|
+ Method: method,
|
|
|
|
+ SimpleBindItem: item,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bindingItem.bind(routerGroup, middlewares...)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+type BindItem[I any, O any] struct {
|
|
|
|
+ Method string
|
|
|
|
+ *SimpleBindItem[I, O]
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (item *BindItem[I, O]) bind(routerGroup *gin.RouterGroup, middlewares ...middleware.Func) {
|
|
|
|
+ if utils.IsStringEmpty(item.Path) {
|
|
|
|
+ panic("需要指定路径")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if utils.IsStringEmpty(item.Method) {
|
|
|
|
+ panic("需要指定方法")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if item.ResponseFunc == nil {
|
|
|
|
+ panic("需要指定响应函数")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var inputModel I
|
|
|
|
+ inputType := reflect.TypeOf(inputModel)
|
|
|
|
+ if inputType != nil {
|
|
|
|
+ if inputType.Kind() == reflect.Pointer {
|
|
|
|
+ panic("输入对象不能使用指针类型")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if inputType.Kind() != reflect.Struct {
|
|
|
|
+ panic("输入对象必须是结构")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ginHandleFunctions := make([]gin.HandlerFunc, 0)
|
|
|
|
+ for _, m := range middlewares {
|
|
|
|
+ ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
|
|
|
|
+ m(&binding_context.Context{Context: c})
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
|
|
|
|
+ bindingContext := &binding_context.Context{Context: c}
|
|
|
|
+
|
|
|
|
+ if inputType != nil {
|
|
|
|
+ if item.OptionalBindingFunc != nil {
|
|
|
|
+ ok := item.OptionalBindingFunc(bindingContext, &inputModel, item.ResponseFunc)
|
|
|
|
+ if !ok {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ switch item.Method {
|
|
|
|
+ case http.MethodPost:
|
|
|
|
+ fallthrough
|
|
|
|
+ case http.MethodPut:
|
|
|
|
+ ok := request.BindingJson(bindingContext, &inputModel, item.ResponseFunc)
|
|
|
|
+ if !ok {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ case http.MethodGet:
|
|
|
|
+ fallthrough
|
|
|
|
+ case http.MethodDelete:
|
|
|
|
+ ok := request.BindingQuery(bindingContext, &inputModel, item.ResponseFunc)
|
|
|
|
+ if !ok {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if item.BusinessFunc != nil {
|
|
|
|
+ statusCode := http.StatusOK
|
|
|
|
+ outputModel, err := item.BusinessFunc(bindingContext, inputModel)
|
|
|
|
+ if err != nil {
|
|
|
|
+ statusCode = fserr.ParseCode(err).HttpCode
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ item.ResponseFunc(bindingContext, statusCode, outputModel, err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ routerGroup.Handle(item.Method, item.Path, ginHandleFunctions...)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+type StaticBindItem struct {
|
|
|
|
+ RelativePath string
|
|
|
|
+ Root string
|
|
|
|
+ WithBasePath bool
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (item *StaticBindItem) bind(routerGroup *gin.RouterGroup) {
|
|
|
|
+ if item.WithBasePath {
|
|
|
|
+ routerGroup.Static(strings.TrimPrefix(item.RelativePath, routerGroup.BasePath()), item.Root)
|
|
|
|
+ } else {
|
|
|
|
+ routerGroup.Static(item.RelativePath, item.Root)
|
|
|
|
+ }
|
|
|
|
+}
|