mirror of
https://gitee.com/XM-GO/PandaX.git
synced 2026-04-23 02:48:34 +08:00
15
kit/restfulx/log_handler.go
Normal file
15
kit/restfulx/log_handler.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package restfulx
|
||||
|
||||
type LogInfo struct {
|
||||
LogResp bool // 是否记录返回结果
|
||||
Description string // 请求描述
|
||||
}
|
||||
|
||||
func NewLogInfo(description string) *LogInfo {
|
||||
return &LogInfo{Description: description, LogResp: false}
|
||||
}
|
||||
|
||||
func (i *LogInfo) WithLogResp(logResp bool) *LogInfo {
|
||||
i.LogResp = logResp
|
||||
return i
|
||||
}
|
||||
16
kit/restfulx/permission_handler.go
Normal file
16
kit/restfulx/permission_handler.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package restfulx
|
||||
|
||||
type Permission struct {
|
||||
NeedToken bool // 是否需要token
|
||||
NeedCasbin bool // 是否进行权限 api路径权限验证
|
||||
}
|
||||
|
||||
func (p *Permission) WithNeedToken(needToken bool) *Permission {
|
||||
p.NeedToken = needToken
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Permission) WithNeedCasBin(needCasBin bool) *Permission {
|
||||
p.NeedCasbin = needCasBin
|
||||
return p
|
||||
}
|
||||
135
kit/restfulx/req_ctx.go
Normal file
135
kit/restfulx/req_ctx.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package restfulx
|
||||
|
||||
import (
|
||||
"pandax/kit/biz"
|
||||
"pandax/kit/token"
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
// 处理函数
|
||||
type HandlerFunc func(*ReqCtx)
|
||||
|
||||
type ReqCtx struct {
|
||||
Request *restful.Request
|
||||
Response *restful.Response
|
||||
// NeedToken bool // 是否需要token
|
||||
RequiredPermission *Permission // 需要的权限信息,默认为nil,需要校验token
|
||||
LoginAccount *token.Claims // 登录账号信息,只有校验token后才会有值
|
||||
|
||||
LogInfo *LogInfo // 日志相关信息
|
||||
ReqParam any // 请求参数,主要用于记录日志
|
||||
ResData any // 响应结果
|
||||
Err any // 请求错误
|
||||
Validate *validator.Validate
|
||||
Timed int64 // 执行时间
|
||||
NoRes bool // 无需返回结果,即文件下载等
|
||||
}
|
||||
|
||||
func (rc *ReqCtx) Handle(handler HandlerFunc) {
|
||||
request := rc.Response
|
||||
defer func() {
|
||||
var err any
|
||||
err = recover()
|
||||
if err != nil {
|
||||
rc.Err = err
|
||||
ErrorRes(request, err)
|
||||
}
|
||||
// 应用所有请求后置处理器
|
||||
ApplyHandlerInterceptor(afterHandlers, rc)
|
||||
}()
|
||||
biz.IsTrue(rc.Request != nil, "Request == nil")
|
||||
|
||||
// 默认为不记录请求参数,可在handler回调函数中覆盖赋值
|
||||
rc.ReqParam = 0
|
||||
// 默认响应结果为nil,可在handler中赋值
|
||||
rc.ResData = nil
|
||||
|
||||
// 调用请求前所有处理器
|
||||
err := ApplyHandlerInterceptor(beforeHandlers, rc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
begin := time.Now()
|
||||
handler(rc)
|
||||
rc.Timed = time.Now().Sub(begin).Milliseconds()
|
||||
if !rc.NoRes {
|
||||
SuccessRes(rc.Response, rc.ResData)
|
||||
}
|
||||
}
|
||||
|
||||
func (rc *ReqCtx) Download(filename string) {
|
||||
rc.NoRes = true
|
||||
Download(rc, filename)
|
||||
}
|
||||
|
||||
func NewReqCtx(request *restful.Request, response *restful.Response) *ReqCtx {
|
||||
return &ReqCtx{
|
||||
Request: request,
|
||||
Response: response,
|
||||
LogInfo: NewLogInfo("默认日志信息"),
|
||||
Validate: validator.New(),
|
||||
RequiredPermission: &Permission{NeedToken: true, NeedCasbin: true},
|
||||
}
|
||||
}
|
||||
|
||||
// 调用该方法设置请求描述,则默认记录日志,并不记录响应结果
|
||||
func (r *ReqCtx) WithLog(model string) *ReqCtx {
|
||||
r.LogInfo.Description = model
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ReqCtx) NoAppend() *ReqCtx {
|
||||
r.NoRes = true
|
||||
return r
|
||||
}
|
||||
|
||||
// 设置请求上下文需要的权限信息
|
||||
func (r *ReqCtx) WithRequiredPermission(permission *Permission) *ReqCtx {
|
||||
r.RequiredPermission = permission
|
||||
return r
|
||||
}
|
||||
|
||||
// 是否需要token
|
||||
func (r *ReqCtx) WithNeedToken(needToken bool) *ReqCtx {
|
||||
r.RequiredPermission.NeedToken = needToken
|
||||
return r
|
||||
}
|
||||
|
||||
// 是否需要Casbin
|
||||
func (r *ReqCtx) WithNeedCasbin(needCasbin bool) *ReqCtx {
|
||||
r.RequiredPermission.NeedCasbin = needCasbin
|
||||
return r
|
||||
}
|
||||
|
||||
// 处理器拦截器函数
|
||||
type HandlerInterceptorFunc func(*ReqCtx) error
|
||||
type HandlerInterceptors []HandlerInterceptorFunc
|
||||
|
||||
var (
|
||||
beforeHandlers HandlerInterceptors
|
||||
afterHandlers HandlerInterceptors
|
||||
)
|
||||
|
||||
// 使用前置处理器函数
|
||||
func UseBeforeHandlerInterceptor(b HandlerInterceptorFunc) {
|
||||
beforeHandlers = append(beforeHandlers, b)
|
||||
}
|
||||
|
||||
// 使用后置处理器函数
|
||||
func UseAfterHandlerInterceptor(b HandlerInterceptorFunc) {
|
||||
afterHandlers = append(afterHandlers, b)
|
||||
}
|
||||
|
||||
// 应用指定处理器拦截器,如果有一个错误则直接返回错误
|
||||
func ApplyHandlerInterceptor(his HandlerInterceptors, rc *ReqCtx) any {
|
||||
for _, handler := range his {
|
||||
if err := handler(rc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
116
kit/restfulx/restfulx.go
Normal file
116
kit/restfulx/restfulx.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package restfulx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"pandax/kit/biz"
|
||||
"pandax/kit/logger"
|
||||
"pandax/kit/model"
|
||||
"strconv"
|
||||
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"github.com/gorilla/schema"
|
||||
)
|
||||
|
||||
// 绑定并校验请求结构体参数 结构体添加 例如: validate:"required" validate:"required,gt=10"
|
||||
func BindJsonAndValid(rc *ReqCtx, data any) {
|
||||
if err := rc.Request.ReadEntity(data); err != nil {
|
||||
panic(any(biz.NewBizErr(err.Error())))
|
||||
}
|
||||
if err := rc.Validate.Struct(data); err != nil {
|
||||
panic(any(biz.NewBizErr("传参格式错误:" + err.Error())))
|
||||
}
|
||||
}
|
||||
|
||||
// BindQuery 绑定查询字符串到
|
||||
func BindQuery(rc *ReqCtx, data any) {
|
||||
if err := rc.Request.ReadEntity(data); err != nil {
|
||||
panic(any(biz.NewBizErr(err.Error())))
|
||||
}
|
||||
}
|
||||
|
||||
// PathParamsToAny 获取虽有路径中的参数
|
||||
func PathParamsToAny(rc *ReqCtx, in any) {
|
||||
vars := make(map[string]any)
|
||||
for k, v := range rc.Request.PathParameters() {
|
||||
vars[k] = v
|
||||
}
|
||||
marshal, _ := json.Marshal(vars)
|
||||
err := json.Unmarshal(marshal, in)
|
||||
biz.ErrIsNil(err, "error get path value encoding unmarshal")
|
||||
return
|
||||
}
|
||||
|
||||
// QueryParamsToAny 获取所有Query的参数
|
||||
func QueryParamsToAny(rc *ReqCtx, in any) {
|
||||
err := rc.Request.Request.ParseForm()
|
||||
biz.ErrIsNil(err, "error get ParseForm value encoding unmarshal")
|
||||
decoder := schema.NewDecoder()
|
||||
err = decoder.Decode(in, rc.Request.Request.Form)
|
||||
biz.ErrIsNil(err, "error get path value encoding unmarshal")
|
||||
return
|
||||
}
|
||||
|
||||
// GetPageQueryParam 获取分页参数
|
||||
func GetPageQueryParam(rc *ReqCtx) *model.PageParam {
|
||||
return &model.PageParam{PageNum: QueryInt(rc, "pageNum", 1), PageSize: QueryInt(rc, "pageSize", 10)}
|
||||
}
|
||||
|
||||
// QueryInt 获取查询参数中指定参数值,并转为int
|
||||
func QueryInt(rc *ReqCtx, qm string, defaultInt int) int {
|
||||
qv := rc.Request.QueryParameter(qm)
|
||||
if qv == "" {
|
||||
return defaultInt
|
||||
}
|
||||
qvi, err := strconv.Atoi(qv)
|
||||
biz.ErrIsNil(err, "query param not int")
|
||||
return qvi
|
||||
}
|
||||
|
||||
// QueryParam QueryParam
|
||||
func QueryParam(rc *ReqCtx, key string) string {
|
||||
return rc.Request.QueryParameter(key)
|
||||
}
|
||||
|
||||
// PathParamInt 获取路径参数
|
||||
func PathParamInt(rc *ReqCtx, pm string) int {
|
||||
value, _ := strconv.Atoi(rc.Request.PathParameter(pm))
|
||||
return value
|
||||
}
|
||||
func PathParam(rc *ReqCtx, pm string) string {
|
||||
return rc.Request.PathParameter(pm)
|
||||
}
|
||||
|
||||
// 文件下载
|
||||
func Download(rc *ReqCtx, filename string) {
|
||||
rc.Response.Header().Add("success", "true")
|
||||
rc.Response.Header().Set("Content-Length", "-1")
|
||||
rc.Response.Header().Set("Content-Disposition", "attachment; filename="+filename)
|
||||
http.ServeFile(
|
||||
rc.Response.ResponseWriter,
|
||||
rc.Request.Request, filename)
|
||||
}
|
||||
|
||||
// 返回统一成功结果
|
||||
func SuccessRes(response *restful.Response, data any) {
|
||||
response.WriteEntity(model.Success(data))
|
||||
}
|
||||
|
||||
// 返回失败结果集
|
||||
func ErrorRes(response *restful.Response, err any) {
|
||||
switch t := err.(type) {
|
||||
case *biz.BizError:
|
||||
response.WriteEntity(model.Error(t))
|
||||
break
|
||||
case error:
|
||||
response.WriteEntity(model.ServerError())
|
||||
logger.Log.Error(t)
|
||||
break
|
||||
case string:
|
||||
response.WriteEntity(model.ServerError())
|
||||
logger.Log.Error(t)
|
||||
break
|
||||
default:
|
||||
logger.Log.Error(t)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user