package wrap import ( "context" "fmt" "log/slog" "reflect" "taotie-api/common" "time" "github.com/duke-git/lancet/v2/xerror" "github.com/gin-gonic/gin" "github.com/gookit/validate" ) func Wrap[R, P any](fn func(context.Context, *R) (*P, error)) func(c *gin.Context) { return func(c *gin.Context) { // defer func() { // if r := recover(); r != nil { // Err(c, errors.New(fmt.Sprintf("panic: %v", r))) // c.Abort() // } // }() // 绑定请求参数 var req = new(R) // 检查请求结构体是否为空结构体 reqType := reflect.TypeOf(req).Elem() isEmptyStruct := reqType.NumField() == 0 if !isEmptyStruct { if c.Request.ContentLength != 0 { // 绑定请求参数 if err := c.ShouldBindJSON(req); err != nil { er := common.ErrSysValidationFailed.Wrap(err) Err(c, er) c.Abort() return } } // 校验请求参数 v := validate.New(req) if !v.Validate() { er := common.ErrSysValidationFailed.Wrap(v.Errors.OneError()) Err(c, er) c.Abort() return } } // 调用业务逻辑 res, err := fn(c, req) if err != nil { Err(c, err) c.Abort() return } Ok(c, res) } } type Resp struct { Code string `json:"code"` Msg string `json:"msg"` Data any `json:"data"` Ok bool `json:"ok"` Time int64 `json:"time"` } func Ok(c *gin.Context, data any) { c.JSON(200, Resp{ Code: common.ErrSysOk.Info().Id, Msg: common.ErrSysOk.Info().Message, Data: data, Ok: true, Time: time.Now().Unix(), }) } // Err 处理错误 // // 注意⚠️:这里需要想想是不是所有的错误都要返回给 web 端 func Err(c *gin.Context, err error) { // 返回给 web 端的错误 var weberr = common.ErrSysInternal // 提取最底层的错误 causeErr := xerror.Unwrap(err) // 如果是自定义错误,解析错误,返回给 web 端 if causeErr != nil { weberr = causeErr } else { slog.Error("【SRV-ERR】", "ERR", fmt.Errorf("%+v", err)) } // 系统内部错误的话,就不返回给 web 端,只记录。 // 记录日志 // slog.Error("【WEB-ERR】", "ERR", weberr) // slog.Error("【SRV-ERR】", "ERR", fmt.Errorf("%+v", err)) c.JSON(200, Resp{ Code: weberr.Info().Id, Msg: weberr.Info().Message, Ok: false, Time: time.Now().Unix(), }) }