http_binding.go 7.3 KB

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