123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- package http_binding
- import (
- "errors"
- "git.sxidc.com/go-tools/api_binding/http_binding/binding_context"
- "git.sxidc.com/go-tools/api_binding/http_binding/middleware"
- "git.sxidc.com/go-tools/api_binding/http_binding/request"
- "git.sxidc.com/go-tools/api_binding/http_binding/response"
- "git.sxidc.com/go-tools/utils/strutils"
- "git.sxidc.com/service-supports/fserr"
- "git.sxidc.com/service-supports/fslog"
- "github.com/gin-gonic/gin"
- "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
- }
- // NewBinding 创建版本对应的binding
- func NewBinding(apiVersion string, middlewares ...middleware.Func) *Binding {
- apiPrefix := urlPrefix + "/api"
- if strutils.IsStringNotEmpty(apiVersion) && apiVersion != "root" {
- apiPrefix += "/" + apiVersion
- }
- // 把binding.Middleware转换为gin的中间件函数
- ginMiddlewares := make([]gin.HandlerFunc, 0)
- for _, m := range middlewares {
- innerM := m
- ginMiddlewares = append(ginMiddlewares, func(c *gin.Context) {
- innerM(&binding_context.Context{Context: c})
- })
- }
- // 返回创建的路由组
- return &Binding{routerGroup: routerInstance.Group(apiPrefix, ginMiddlewares...)}
- }
- type HandleFunc func(c *binding_context.Context)
- func (binding *Binding) AddHandler(method string, relativePath string, handleFunctions ...HandleFunc) error {
- if strutils.IsStringEmpty(method) {
- return errors.New("没有传递方法名")
- }
- if strutils.IsStringEmpty(relativePath) {
- return errors.New("没有传递相对路径")
- }
- if handleFunctions == nil || len(handleFunctions) == 0 {
- return errors.New("没有传递处理函数")
- }
- routeInfos := routerInstance.Routes()
- for _, routeInfo := range routeInfos {
- if routeInfo.Method == method && strings.TrimPrefix(routeInfo.Path, binding.routerGroup.BasePath()+"/") == relativePath {
- fslog.Error("添加的路径已存在: " + routeInfo.Path)
- return nil
- }
- }
- // 给单个路由增加中间件
- ginHandleFunctions := make([]gin.HandlerFunc, 0)
- for _, handleFunction := range handleFunctions {
- innerFunction := handleFunction
- ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
- innerFunction(&binding_context.Context{Context: c})
- })
- }
- binding.routerGroup.Handle(method, relativePath, ginHandleFunctions...)
- return nil
- }
- 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)
- }
- func StaticFile(b *Binding, item *StaticFileBindItem) {
- item.bind(b.routerGroup)
- }
- // SimpleBindItem 路由条目
- 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...)
- }
- // BindItem 路由条目结构
- 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 strutils.IsStringEmpty(item.Path) {
- panic("需要指定路径")
- }
- if strutils.IsStringEmpty(item.Method) {
- panic("需要指定方法")
- }
- if item.ResponseFunc == nil {
- panic("需要指定响应函数")
- }
- var inputCheckModel I
- inputType := reflect.TypeOf(inputCheckModel)
- if inputType != nil {
- if inputType.Kind() == reflect.Pointer {
- panic("输入对象不能使用指针类型")
- }
- if inputType.Kind() != reflect.Struct {
- panic("输入对象必须是结构")
- }
- }
- // 给单个路由增加中间件
- ginHandleFunctions := make([]gin.HandlerFunc, 0)
- for _, m := range middlewares {
- innerM := m
- ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
- innerM(&binding_context.Context{Context: c})
- })
- }
- ginHandleFunctions = append(ginHandleFunctions, func(c *gin.Context) {
- bindingContext := &binding_context.Context{Context: c}
- var inputModel I
- // 请求的结构类型不为any
- if inputType != nil {
- // 将请求数据解析到inputModel中
- 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...)
- }
- // StaticBindItem 静态路由item
- 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)
- }
- }
- type StaticFileBindItem struct {
- RelativePath string
- FilePath string
- WithBasePath bool
- }
- func (item *StaticFileBindItem) bind(routerGroup *gin.RouterGroup) {
- if item.WithBasePath {
- routerGroup.StaticFile(strings.TrimPrefix(item.RelativePath, routerGroup.BasePath()), item.FilePath)
- } else {
- routerGroup.StaticFile(item.RelativePath, item.FilePath)
- }
- }
|