http_binding.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package http_binding
  2. import (
  3. "git.sxidc.com/go-tools/api_binding/http_binding/binding_context"
  4. "git.sxidc.com/go-tools/api_binding/http_binding/middleware"
  5. "git.sxidc.com/go-tools/api_binding/http_binding/request"
  6. "git.sxidc.com/go-tools/api_binding/http_binding/response"
  7. "git.sxidc.com/go-tools/api_binding/utils"
  8. "git.sxidc.com/service-supports/fserr"
  9. "github.com/gin-gonic/gin"
  10. "net/http"
  11. "reflect"
  12. "strings"
  13. )
  14. type BusinessFunc[I any, O any] func(c *binding_context.Context, inputModel I) (O, error)
  15. type BindingFunc[O any] func(c *binding_context.Context, request any, sendFunc response.SendFunc[O]) bool
  16. type Binding struct {
  17. routerGroup *gin.RouterGroup
  18. }
  19. // NewBinding 创建版本对应的binding
  20. func NewBinding(apiVersion string, middlewares ...middleware.Func) *Binding {
  21. apiPrefix := urlPrefix + "/api"
  22. if utils.IsStringNotEmpty(apiVersion) && apiVersion != "root" {
  23. apiPrefix += "/" + apiVersion
  24. }
  25. // 把binding.Middleware转换为gin的中间件函数
  26. ginMiddlewares := make([]gin.HandlerFunc, 0)
  27. for _, m := range middlewares {
  28. innerM := m
  29. ginMiddlewares = append(ginMiddlewares, func(c *gin.Context) {
  30. innerM(&binding_context.Context{Context: c})
  31. })
  32. }
  33. // 返回创建的路由组
  34. return &Binding{routerGroup: routerInstance.Group(apiPrefix, ginMiddlewares...)}
  35. }
  36. func (binding *Binding) GetRouterGroup() *gin.RouterGroup {
  37. return binding.routerGroup
  38. }
  39. func PostBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
  40. item.bind(b.routerGroup, http.MethodPost, middlewares...)
  41. }
  42. func DeleteBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
  43. item.bind(b.routerGroup, http.MethodDelete, middlewares...)
  44. }
  45. func PutBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
  46. item.bind(b.routerGroup, http.MethodPut, middlewares...)
  47. }
  48. func GetBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
  49. item.bind(b.routerGroup, http.MethodGet, middlewares...)
  50. }
  51. func Bind[I any, O any](b *Binding, item *BindItem[I, O], middlewares ...middleware.Func) {
  52. item.bind(b.routerGroup, middlewares...)
  53. }
  54. func Static(b *Binding, item *StaticBindItem) {
  55. item.bind(b.routerGroup)
  56. }
  57. // SimpleBindItem 路由条目
  58. type SimpleBindItem[I any, O any] struct {
  59. Path string // 请求路径
  60. ResponseFunc response.SendFunc[O] // 响应泛型函数
  61. BusinessFunc BusinessFunc[I, O] // 业务泛型函数
  62. OptionalBindingFunc BindingFunc[O] //
  63. }
  64. func (item *SimpleBindItem[I, O]) bind(routerGroup *gin.RouterGroup, method string, middlewares ...middleware.Func) {
  65. bindingItem := &BindItem[I, O]{
  66. Method: method,
  67. SimpleBindItem: item,
  68. }
  69. bindingItem.bind(routerGroup, middlewares...)
  70. }
  71. // BindItem 路由条目结构
  72. type BindItem[I any, O any] struct {
  73. Method string
  74. *SimpleBindItem[I, O]
  75. }
  76. func (item *BindItem[I, O]) bind(routerGroup *gin.RouterGroup, middlewares ...middleware.Func) {
  77. if utils.IsStringEmpty(item.Path) {
  78. panic("需要指定路径")
  79. }
  80. if utils.IsStringEmpty(item.Method) {
  81. panic("需要指定方法")
  82. }
  83. if item.ResponseFunc == nil {
  84. panic("需要指定响应函数")
  85. }
  86. var inputCheckModel I
  87. inputType := reflect.TypeOf(inputCheckModel)
  88. if inputType != nil {
  89. if inputType.Kind() == reflect.Pointer {
  90. panic("输入对象不能使用指针类型")
  91. }
  92. if inputType.Kind() != reflect.Struct {
  93. panic("输入对象必须是结构")
  94. }
  95. }
  96. // 给单个路由增加中间件
  97. ginHandleFunctions := make([]gin.HandlerFunc, 0)
  98. for _, m := range middlewares {
  99. innerM := m
  100. ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
  101. innerM(&binding_context.Context{Context: c})
  102. })
  103. }
  104. ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
  105. bindingContext := &binding_context.Context{Context: c}
  106. var inputModel I
  107. // 请求的结构类型不为any
  108. if inputType != nil {
  109. // 将请求数据解析到inputModel中
  110. if item.OptionalBindingFunc != nil {
  111. ok := item.OptionalBindingFunc(bindingContext, &inputModel, item.ResponseFunc)
  112. if !ok {
  113. return
  114. }
  115. } else {
  116. switch item.Method {
  117. case http.MethodPost:
  118. fallthrough
  119. case http.MethodPut:
  120. ok := request.BindingJson(bindingContext, &inputModel, item.ResponseFunc)
  121. if !ok {
  122. return
  123. }
  124. case http.MethodGet:
  125. fallthrough
  126. case http.MethodDelete:
  127. ok := request.BindingQuery(bindingContext, &inputModel, item.ResponseFunc)
  128. if !ok {
  129. return
  130. }
  131. }
  132. }
  133. }
  134. // 执行业务函数
  135. if item.BusinessFunc != nil {
  136. statusCode := http.StatusOK
  137. outputModel, err := item.BusinessFunc(bindingContext, inputModel)
  138. if err != nil {
  139. statusCode = fserr.ParseCode(err).HttpCode
  140. }
  141. item.ResponseFunc(bindingContext, statusCode, outputModel, err)
  142. return
  143. }
  144. })
  145. // 所有的函数加入到执行链中
  146. routerGroup.Handle(item.Method, item.Path, ginHandleFunctions...)
  147. }
  148. // StaticBindItem 静态路由item
  149. type StaticBindItem struct {
  150. RelativePath string
  151. Root string
  152. WithBasePath bool
  153. }
  154. func (item *StaticBindItem) bind(routerGroup *gin.RouterGroup) {
  155. if item.WithBasePath {
  156. routerGroup.Static(strings.TrimPrefix(item.RelativePath, routerGroup.BasePath()), item.Root)
  157. } else {
  158. routerGroup.Static(item.RelativePath, item.Root)
  159. }
  160. }