http_binding.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. func NewBinding(apiVersion string, middlewares ...middleware.Func) *Binding {
  20. apiPrefix := urlPrefix + "/api"
  21. if utils.IsStringNotEmpty(apiVersion) && apiVersion != "root" {
  22. apiPrefix += "/" + apiVersion
  23. }
  24. ginMiddlewares := make([]gin.HandlerFunc, 0)
  25. for _, m := range middlewares {
  26. ginMiddlewares = append(ginMiddlewares, func(c *gin.Context) {
  27. m(&binding_context.Context{Context: c})
  28. })
  29. }
  30. return &Binding{routerGroup: routerInstance.Group(apiPrefix, ginMiddlewares...)}
  31. }
  32. func PostBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
  33. item.bind(b.routerGroup, http.MethodPost, middlewares...)
  34. }
  35. func DeleteBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
  36. item.bind(b.routerGroup, http.MethodDelete, middlewares...)
  37. }
  38. func PutBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
  39. item.bind(b.routerGroup, http.MethodPut, middlewares...)
  40. }
  41. func GetBind[I any, O any](b *Binding, item *SimpleBindItem[I, O], middlewares ...middleware.Func) {
  42. item.bind(b.routerGroup, http.MethodGet, middlewares...)
  43. }
  44. func Bind[I any, O any](b *Binding, item *BindItem[I, O], middlewares ...middleware.Func) {
  45. item.bind(b.routerGroup, middlewares...)
  46. }
  47. func Static(b *Binding, item *StaticBindItem) {
  48. item.bind(b.routerGroup)
  49. }
  50. type SimpleBindItem[I any, O any] struct {
  51. Path string
  52. ResponseFunc response.SendFunc[O]
  53. BusinessFunc BusinessFunc[I, O]
  54. OptionalBindingFunc BindingFunc[O]
  55. }
  56. func (item *SimpleBindItem[I, O]) bind(routerGroup *gin.RouterGroup, method string, middlewares ...middleware.Func) {
  57. bindingItem := &BindItem[I, O]{
  58. Method: method,
  59. SimpleBindItem: item,
  60. }
  61. bindingItem.bind(routerGroup, middlewares...)
  62. }
  63. type BindItem[I any, O any] struct {
  64. Method string
  65. *SimpleBindItem[I, O]
  66. }
  67. func (item *BindItem[I, O]) bind(routerGroup *gin.RouterGroup, middlewares ...middleware.Func) {
  68. if utils.IsStringEmpty(item.Path) {
  69. panic("需要指定路径")
  70. }
  71. if utils.IsStringEmpty(item.Method) {
  72. panic("需要指定方法")
  73. }
  74. if item.ResponseFunc == nil {
  75. panic("需要指定响应函数")
  76. }
  77. var inputModel I
  78. inputType := reflect.TypeOf(inputModel)
  79. if inputType != nil {
  80. if inputType.Kind() == reflect.Pointer {
  81. panic("输入对象不能使用指针类型")
  82. }
  83. if inputType.Kind() != reflect.Struct {
  84. panic("输入对象必须是结构")
  85. }
  86. }
  87. ginHandleFunctions := make([]gin.HandlerFunc, 0)
  88. for _, m := range middlewares {
  89. ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
  90. m(&binding_context.Context{Context: c})
  91. })
  92. }
  93. ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
  94. bindingContext := &binding_context.Context{Context: c}
  95. if inputType != nil {
  96. if item.OptionalBindingFunc != nil {
  97. ok := item.OptionalBindingFunc(bindingContext, &inputModel, item.ResponseFunc)
  98. if !ok {
  99. return
  100. }
  101. } else {
  102. switch item.Method {
  103. case http.MethodPost:
  104. fallthrough
  105. case http.MethodPut:
  106. ok := request.BindingJson(bindingContext, &inputModel, item.ResponseFunc)
  107. if !ok {
  108. return
  109. }
  110. case http.MethodGet:
  111. fallthrough
  112. case http.MethodDelete:
  113. ok := request.BindingQuery(bindingContext, &inputModel, item.ResponseFunc)
  114. if !ok {
  115. return
  116. }
  117. }
  118. }
  119. }
  120. if item.BusinessFunc != nil {
  121. statusCode := http.StatusOK
  122. outputModel, err := item.BusinessFunc(bindingContext, inputModel)
  123. if err != nil {
  124. statusCode = fserr.ParseCode(err).HttpCode
  125. }
  126. item.ResponseFunc(bindingContext, statusCode, outputModel, err)
  127. return
  128. }
  129. })
  130. routerGroup.Handle(item.Method, item.Path, ginHandleFunctions...)
  131. }
  132. type StaticBindItem struct {
  133. RelativePath string
  134. Root string
  135. WithBasePath bool
  136. }
  137. func (item *StaticBindItem) bind(routerGroup *gin.RouterGroup) {
  138. if item.WithBasePath {
  139. routerGroup.Static(strings.TrimPrefix(item.RelativePath, routerGroup.BasePath()), item.Root)
  140. } else {
  141. routerGroup.Static(item.RelativePath, item.Root)
  142. }
  143. }