| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- package binding
- import (
- "git.sxidc.com/go-framework/baize/api"
- "git.sxidc.com/go-framework/baize/domain"
- "git.sxidc.com/go-tools/utils/strutils"
- "git.sxidc.com/service-supports/fserr"
- "net/http"
- "strings"
- )
- func PostBind[O any](router api.Router, item *SimpleBindItem[O], middlewares ...api.Handler) {
- item.bind(router, http.MethodPost, middlewares...)
- }
- func DeleteBind[O any](router api.Router, item *SimpleBindItem[O], middlewares ...api.Handler) {
- item.bind(router, http.MethodDelete, middlewares...)
- }
- func PutBind[O any](router api.Router, item *SimpleBindItem[O], middlewares ...api.Handler) {
- item.bind(router, http.MethodPut, middlewares...)
- }
- func GetBind[O any](router api.Router, item *SimpleBindItem[O], middlewares ...api.Handler) {
- item.bind(router, http.MethodGet, middlewares...)
- }
- func Bind[O any](router api.Router, item *BindItem[O], middlewares ...api.Handler) {
- item.bind(router, middlewares...)
- }
- func Static(router api.Router, item *StaticBindItem) {
- item.bind(router)
- }
- func StaticFile(router api.Router, item *StaticFileBindItem) {
- item.bind(router)
- }
- type DTOBindFunc func(c *api.Context, dto DTO) error
- type FormDomainObjectsFunc func(c *api.Context, dto DTO) ([]domain.Object, error)
- type ServiceFunc[O any] func(c *api.Context, dto DTO, objects []domain.Object) (O, error)
- type ResponseFunc[O any] func(c *api.Context, statusCode int, data O, err error)
- // SimpleBindItem 路由条目
- type SimpleBindItem[O any] struct {
- // URL相对路径
- Path string
- // 使用的dto,非必传,当dto为nil时,说明该接口没有参数
- DTO DTO
- // 可选的dto绑定函数
- // 非必传,POST和PUT请求默认为JsonBody,DELETE默认为PathParams,GET默认为QueryParams
- // 额外还提供了一些转化函数:
- // MultipartForm: 绑定multipart form
- // FormBody: 绑定form body
- // XMLBody: 绑定XML body
- DTOBindFunc DTOBindFunc
- // 通过DTO构造使用的领域对象,之后在ServiceFunc中会按照构造实体的顺序进行回调
- // 非必传,如果为nil,则说明没有领域对象
- // 与Objects字段二选一使用,如果都指定,会按照该字段处理
- FormDomainObjectsFunc FormDomainObjectsFunc
- // 使用的领域对象,当使用Tag对实体进行标注后,可以直接通过该字段给定实体,之后在ServiceFunc中会按照给定实体的顺序进行回调
- // 非必传,如果为nil或长度为0,则说明没有领域对象
- // 与FormObjectsFunc字段二选一使用,如果都指定,会按照FormObjectsFunc字段处理
- Objects []domain.Object
- // 应用服务泛型函数
- ServiceFunc ServiceFunc[O]
- // 响应泛型函数,如果不响应,需要使用NoResponse零值占位
- ResponseFunc ResponseFunc[O]
- }
- func (item *SimpleBindItem[O]) bind(router api.Router, method string, middlewares ...api.Handler) {
- bindingItem := &BindItem[O]{
- Method: method,
- SimpleBindItem: item,
- }
- bindingItem.bind(router, middlewares...)
- }
- // BindItem 路由条目结构
- type BindItem[O any] struct {
- Method string
- *SimpleBindItem[O]
- }
- func (item *BindItem[O]) bind(router api.Router, middlewares ...api.Handler) {
- if strutils.IsStringEmpty(item.Path) {
- panic("需要指定路径")
- }
- if strutils.IsStringEmpty(item.Method) {
- panic("需要指定方法")
- }
- if item.ResponseFunc == nil {
- panic("需要指定响应函数")
- }
- if item.ServiceFunc == nil {
- panic("需要指定应用服务函数")
- }
- // 给单个路由增加中间件
- handlers := []api.Handler{
- func(c *api.Context) {
- dto := item.DTO
- // 有请求数据
- if dto != nil {
- // 将请求数据解析到dto中
- if item.DTOBindFunc != nil {
- err := item.DTOBindFunc(c, dto)
- if err != nil {
- var outputZero O
- item.ResponseFunc(c, http.StatusBadRequest, outputZero, err)
- return
- }
- } else {
- switch item.Method {
- case http.MethodPost:
- fallthrough
- case http.MethodPut:
- err := JsonBody(c, dto)
- if err != nil {
- var outputZero O
- item.ResponseFunc(c, http.StatusBadRequest, outputZero, err)
- return
- }
- case http.MethodGet:
- err := QueryParams(c, dto)
- if err != nil {
- var outputZero O
- item.ResponseFunc(c, http.StatusBadRequest, outputZero, err)
- return
- }
- case http.MethodDelete:
- err := PathParams(c, dto)
- if err != nil {
- var outputZero O
- item.ResponseFunc(c, http.StatusBadRequest, outputZero, err)
- return
- }
- }
- }
- }
- // 进行领域对象转化
- var domainObjects []domain.Object
- if item.FormDomainObjectsFunc != nil {
- innerDomainObjects, err := item.FormDomainObjectsFunc(c, dto)
- if err != nil {
- var outputZero O
- item.ResponseFunc(c, http.StatusOK, outputZero, err)
- return
- }
- domainObjects = innerDomainObjects
- } else {
- // TODO Tag处理
- }
- // 执行业务函数
- statusCode := http.StatusOK
- outputModel, err := item.ServiceFunc(c, dto, domainObjects)
- if err != nil {
- statusCode = fserr.ParseCode(err).HttpCode
- }
- item.ResponseFunc(c, statusCode, outputModel, err)
- return
- },
- }
- handlers = append(handlers, middlewares...)
- // 所有的函数加入到执行链中
- router.AddRoute(item.Method, item.Path, handlers...)
- }
- // StaticBindItem 静态路由item
- type StaticBindItem struct {
- RelativePath string
- Root string
- WithBasePath bool
- }
- func (item *StaticBindItem) bind(router api.Router) {
- if item.WithBasePath {
- router.Static(strings.TrimPrefix(item.RelativePath, router.BasePath()), item.Root)
- } else {
- router.Static(item.RelativePath, item.Root)
- }
- }
- type StaticFileBindItem struct {
- RelativePath string
- FilePath string
- WithBasePath bool
- }
- func (item *StaticFileBindItem) bind(router api.Router) {
- if item.WithBasePath {
- router.StaticFile(strings.TrimPrefix(item.RelativePath, router.BasePath()), item.FilePath)
- } else {
- router.StaticFile(item.RelativePath, item.FilePath)
- }
- }
|