http_binding.go 6.5 KB

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