1 Star 0 Fork 0

hongzhaomin / ginplus

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
resolver.go 10.55 KB
一键复制 编辑 原始数据 按行查看 历史
package ginplus
import (
"errors"
"fmt"
"gitee.com/hongzhaomin/hzm-common-go/slice"
"gitee.com/hongzhaomin/hzm-common-go/strutil"
"github.com/gin-gonic/gin"
"mime/multipart"
"net/http"
"reflect"
)
// RestController名称和全路径类名
var _, fullPathRestCtrlName = getTypeName(new(RestController))
// Controller名称和全路径类名
var _, fullPathCtrlName = getTypeName(new(Controller))
// gin.Context名称和全路径类名
var _, fullPathGinCtxName = getTypeName(new(gin.Context))
// multipart.FileHeader名称和全路径类名 - 单文件
var _, fullPathMulFileName = getTypeName(new(multipart.FileHeader))
// multipart.Form名称和全路径类名 - 多文件
var _, fullPathMulFormName = getTypeName(new(multipart.Form))
// IControllerType IController反射类型
var IControllerType = reflect.TypeOf((*IController)(nil)).Elem()
// controller类tag,代表整个controller的统一属性
const (
Path = "Path"
Permission = "Permission" // 权限tag,支持整个controller类和属性
Default = "default" // 默认值tag
)
// controller字段tag,这里表示的是方法的属性
const (
GetMapping = "GetMapping"
PostMapping = "PostMapping"
PutMapping = "PutMapping"
DeleteMapping = "DeleteMapping"
MappingHandler = "MappingHandler"
RequestParam = "RequestParam"
)
// 解析Controller
func resolveIcList(register IGinConfiguration) []*handlerMappingChain {
mappingChains := make([]*handlerMappingChain, 0, len(register.RegisControllers()))
for _, ic := range register.RegisControllers() {
mappings := doResolveSingle(ic)
if len(mappings) > 0 {
mappingChains = append(mappingChains,
&handlerMappingChain{
controller: ic,
mappings: mappings,
})
}
}
return mappingChains
}
func doResolveSingle(ic IController) []*handlerMapping {
mustPoint(ic)
var mappings []*handlerMapping
rvIc := reflect.Indirect(reflect.ValueOf(ic))
rtIc := rvIc.Type()
if rtIc.Kind() != reflect.Struct {
return mappings
}
for i := 0; i < rtIc.NumField(); i++ {
rtField := rtIc.Field(i)
if rtField.Anonymous {
// 内嵌字段,即继承字段,忽略
continue
}
fieldTag := rtField.Tag
if funcName, ok := fieldTag.Lookup(MappingHandler); ok {
var rvFun reflect.Value
if fun, ok2 := rtIc.MethodByName(funcName); ok2 {
if strutil.IsNotBlank(fun.PkgPath) {
msg := fmt.Sprintf("[%s]方法[%s]不可导出", rtIc.Name(), funcName)
panic(msg)
}
rvFun = rvIc.MethodByName(funcName)
} else {
rvIcPtr := rvIc.Addr()
fun, ok3 := rvIcPtr.Type().MethodByName(funcName)
if !ok3 {
msg := fmt.Sprintf("[%s]找不到方法[%s]", rtIc.Name(), funcName)
panic(msg)
}
if strutil.IsNotBlank(fun.PkgPath) {
msg := fmt.Sprintf("[%s]方法[%s]不可导出", rtIc.Name(), funcName)
panic(msg)
}
rvFun = rvIcPtr.MethodByName(funcName)
}
mapping, pNames := resolveFieldTag(fieldTag)
mapping.fun = resolveFun(funcName, rvFun, pNames)
mappings = append(mappings, mapping)
}
}
resolveControllerTag(rvIc, mappings)
return mappings
}
func resolveControllerTag(rvIc reflect.Value, mappings []*handlerMapping) {
rvIc = reflect.Indirect(rvIc)
rtIc := rvIc.Type()
structFields := make([]reflect.StructField, 0, 1)
for i := 0; i < rtIc.NumField(); i++ {
rtField := rtIc.Field(i)
if !rtField.Anonymous {
continue
}
rt := rtField.Type
if rt.Kind() == reflect.Ptr {
panic(errors.New("内嵌(继承)字段不允许为指针类型"))
}
rtFieldFullName := getFullPathTypeName(rt)
if rtFieldFullName == fullPathRestCtrlName || rtFieldFullName == fullPathCtrlName {
structFields = append(structFields, rtField)
continue
}
if rt.Implements(IControllerType) || reflect.New(rt).Type().Implements(IControllerType) {
// 指针类型或者值类型实现了IController接口,可能是开发者自定义了controller我们也允许
structFields = append(structFields, rtField)
continue
}
}
if len(structFields) > 1 {
panic(errors.New("父类控制器controller能且只能继承一个"))
}
rtParent := structFields[0]
ctrlType := getCtrlType(getFullPathTypeName(rtParent.Type))
for _, mapping := range mappings {
// 赋值控制器类型
mapping.ctrlType = ctrlType
}
parentTag := rtParent.Tag
if !unknown.is(ctrlType) {
if path := parentTag.Get(Path); strutil.IsNotBlank(path) {
rvParent := rvIc.FieldByName(rtParent.Name)
rvPath := rvParent.FieldByName(Path)
if rvPath.CanSet() {
rvPath.SetString(path)
}
}
}
// 解析权限tag
if permissionVal, ok := parentTag.Lookup(Permission); ok {
permissionList := strutil.SpitNotLetterAndNumber(permissionVal)
// 遍历每个handlerMapping
for _, mapping := range mappings {
permissions := mapping.permissions
// 解析出来的权限值逐个加入到mapping中
for _, ele := range permissionList {
if !slice.Contains(permissions, permissionVal) {
permissions = append(permissions, ele)
}
}
// 添加完之后放入结构体中
mapping.permissions = permissions
}
}
}
func resolveFieldTag(fieldTag reflect.StructTag) (mapping *handlerMapping, pNames []string) {
mapping = new(handlerMapping)
existTag := func(requestMethod string) bool {
_, ok := fieldTag.Lookup(requestMethod)
return ok
}
// 解析http请求类型和url
var method, url string
switch {
case existTag(GetMapping):
method = http.MethodGet
url = fieldTag.Get(GetMapping)
case existTag(PostMapping):
method = http.MethodPost
url = fieldTag.Get(PostMapping)
case existTag(PutMapping):
method = http.MethodPut
url = fieldTag.Get(PutMapping)
case existTag(DeleteMapping):
method = http.MethodDelete
url = fieldTag.Get(DeleteMapping)
default:
method = http.MethodGet
}
mapping.method = method
mapping.url = url
// 解析请求参数名称(RequestParam)
// 如果是路径参数,也需要在该tag中声明参数名
if pNameStr, ok := fieldTag.Lookup(RequestParam); ok {
pNames = strutil.SpitNotLetterAndNumber(pNameStr)
}
// 解析权限tag(Permission)
if permissionVal, ok := fieldTag.Lookup(Permission); ok {
mapping.permissions = strutil.SpitNotLetterAndNumber(permissionVal)
}
return
}
// 解析方法结构体类型入参的tag
func resolveFunInParamsTag(rtStruct reflect.Type, fieldName string, defaultValMap map[string]string) {
// 解析默认值tag(default)
for i := 0; i < rtStruct.NumField(); i++ {
field := rtStruct.Field(i)
if strutil.IsNotBlank(field.PkgPath) {
// 字段不可导出
continue
}
var key string
if strutil.IsNotBlank(fieldName) {
key = fieldName + strutil.Dot + field.Name
} else {
key = field.Name
}
rtField := field.Type
if rtField.Kind() == reflect.Ptr {
rtField = rtField.Elem()
}
if rtField.Kind() == reflect.Struct {
resolveFunInParamsTag(rtField, field.Name, defaultValMap)
}
if defaultVal, ok := field.Tag.Lookup(Default); ok {
defaultValMap[key] = defaultVal
}
}
}
func resolveFun(funName string, rvFun reflect.Value, pNames []string) handlerFun {
rtFun := rvFun.Type()
outNum := rtFun.NumOut()
if outNum > 1 {
msg := fmt.Sprintf("方法[%s]的返回结果个数不能大于1", funName)
panic(errors.New(msg))
}
inNum := rtFun.NumIn()
if len(pNames) > inNum {
msg := fmt.Sprintf("方法[%s]的参数名个数大于参数列表个数", funName)
panic(errors.New(msg))
}
// 利用管道FIFO(先进先出)的特性,将参数名称放入管道,方便后面获取
pNameChan := make(chan string, 1)
go putParamName2Chan(pNameChan, pNames)
funParams := make([]handlerFunParam, 0)
for i := 0; i < inNum; i++ {
var funParam handlerFunParam
rtParam := rtFun.In(i)
// 该方法定义参数是否为指针类型
definedParamIsPtr := rtParam.Kind() == reflect.Ptr
if definedParamIsPtr {
rtParam = rtParam.Elem()
}
funParam.definedParamIsPtr = definedParamIsPtr
// 类型分别判断
switch rtParam.Kind() {
case reflect.Struct:
definedSpecialParamType := getDefinedSpecialParamType(getFullPathTypeName(rtParam))
// 赋值定义的特殊参数类型
funParam.definedSpecialParamType = definedSpecialParamType
if !omit.is(definedSpecialParamType) {
if !definedParamIsPtr {
msg := fmt.Sprintf("方法[%s]的[%s]类型参数必须声明为指针类型", funName, rtParam.Name())
panic(errors.New(msg))
}
// 参数类型为gin.Context或者文件
if mulFile.is(definedSpecialParamType) {
// 单文件要接收下参数名称
funParam.pName = <-pNameChan
}
break
}
// 如果参数为结构体,解析默认值tag,获取所有字段默认值
defaultValMap := make(map[string]string)
resolveFunInParamsTag(rtParam, strutil.Empty, defaultValMap)
funParam.defaultValMap = defaultValMap
case reflect.Map:
if definedParamIsPtr {
msg := fmt.Sprintf("方法[%s]map类型的入参不能声明为指针", funName)
panic(errors.New(msg))
}
if rtParam.Key().Kind() != reflect.String {
msg := fmt.Sprintf("方法[%s]的map入参'key'类型须定义为'string'", funName)
panic(errors.New(msg))
}
// 判断map类型的value类型
if rtParam.Elem().Kind() != reflect.String && rtParam.Elem().Kind() != reflect.Slice {
msg := fmt.Sprintf("方法[%s]的map入参'value'类型须定义为'string/[]string'", funName)
panic(errors.New(msg))
}
case reflect.Slice:
if definedParamIsPtr {
msg := fmt.Sprintf("方法[%s]slice类型的入参不能声明为指针", funName)
panic(errors.New(msg))
}
if rtParam.Elem().Kind() == reflect.Struct ||
rtParam.Elem().Kind() == reflect.Map ||
rtParam.Elem().Kind() == reflect.Slice ||
rtParam.Elem().Kind() == reflect.Array ||
rtParam.Elem().Kind() == reflect.Chan ||
rtParam.Elem().Kind() == reflect.Func ||
rtParam.Elem().Kind() == reflect.Interface ||
rtParam.Elem().Kind() == reflect.UnsafePointer ||
rtParam.Elem().Kind() == reflect.Ptr {
panic(errors.New("切片元素数据类型请定义为基本数据类型"))
}
funParam.pName = <-pNameChan
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
funParam.pName = <-pNameChan
default:
msg := fmt.Sprintf("方法[%s]入参无法解析,建议定义为 struct/map[string]string/map[string][]string", funName)
panic(msg)
}
funParam.rtParam = rtParam
funParams = append(funParams, funParam)
}
return handlerFun{rvFun, funParams}
}
func putParamName2Chan(pNameChan chan<- string, pNames []string) {
defer close(pNameChan)
for _, pName := range pNames {
pNameChan <- pName
}
}
Go
1
https://gitee.com/hongzhaomin/ginplus.git
git@gitee.com:hongzhaomin/ginplus.git
hongzhaomin
ginplus
ginplus
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891