1 Star 2 Fork 3

kristas/booting-go

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
dispatcher.go 5.36 KB
一键复制 编辑 原始数据 按行查看 历史
kristas 提交于 2021-10-23 15:23 +08:00 . fix: fix gen tool
package controller
import (
"gitee.com/kristas/booting-go/framework/common/util/lang"
"gitee.com/kristas/booting-go/framework/common/util/reflectx"
"gitee.com/kristas/booting-go/framework/web"
"gitee.com/kristas/booting-go/framework/web/resp"
"gitee.com/kristas/booting-go/framework/web/web_filter"
"github.com/go-playground/validator/v10"
"net/http"
"reflect"
)
type ApiInfo struct {
httpMethod string
url string
desc string
params []web.Param
methodName string
group string
field reflect.StructField
}
func NewApiInfo(group string, field reflect.StructField, svm *ServiceMethod) web.ApiInfo {
var api = &ApiInfo{
desc: getDescription(field),
group: group,
methodName: lang.NewString(field.Name).FirstLetterUpper().String(),
field: field,
}
api.httpMethod, api.url = findHttpMethodAndUrl(field)
if svm == nil {
api.params = buildParams(field.Tag.Get("param"), nil)
} else {
api.params = buildParams(field.Tag.Get("param"), svm.GetMethod().Type)
}
return api
}
func (a *ApiInfo) GetHttpMethod() string {
return a.httpMethod
}
func (a *ApiInfo) GetURL() string {
return a.group + a.url
}
func (a *ApiInfo) GetDescription() string {
return a.desc
}
func (a *ApiInfo) GetParams() []web.Param {
return a.params
}
func (a *ApiInfo) GetField() reflect.StructField {
return a.field
}
func (a *ApiInfo) GetMethodName() string {
return a.methodName
}
func (a *ApiInfo) GetMeta(tag string) string {
return a.GetField().Tag.Get(tag)
}
type Param struct {
name string
source string
specifyType string
typ reflect.Type
}
func (p *Param) GetName() string {
return p.name
}
func (p *Param) GetSource() string {
return p.source
}
func (p *Param) GetSpecifyType() string {
return p.specifyType
}
func (p *Param) GetType() reflect.Type {
return p.typ
}
func (p *Param) SetType(t reflect.Type) {
p.typ = t
}
type ServiceMethod struct {
Method *reflect.Method
Value *reflect.Value
}
func NewServiceMethod(method *reflect.Method, value *reflect.Value) *ServiceMethod {
return &ServiceMethod{Method: method, Value: value}
}
func (s *ServiceMethod) GetMethod() *reflect.Method {
return s.Method
}
func (s *ServiceMethod) GetValue() *reflect.Value {
return s.Value
}
type Endpoint struct {
web.ApiInfo
web.ServiceMethod
}
func NewEndpoint(controller web.Controller) []web.Endpoint {
endpoints := make([]web.Endpoint, 0)
RestApiExtract(controller, func(apiInfo web.ApiInfo, svm web.ServiceMethod) {
endpoints = append(endpoints, &Endpoint{
ApiInfo: apiInfo,
ServiceMethod: svm,
})
})
return endpoints
}
func (e *Endpoint) GetApiInfo() web.ApiInfo {
return e.ApiInfo
}
func (e *Endpoint) GetServiceMethod() web.ServiceMethod {
return e.ServiceMethod
}
func (e *Endpoint) Handler(adapter web.ParamAdapter, handler func(result interface{}) error) {
mapper := newParamMapper(adapter)
writer := mapper.GetResponseWriter()
result, err := dispatcherService(e.ServiceMethod, e.ApiInfo, mapper)
if err != nil {
handleErr(writer, err)
}
if result != nil {
err := resolveResponse(writer, result, handler)
if err != nil {
handleErr(writer, err)
}
}
}
func dispatcherService(svm web.ServiceMethod, apiInfo web.ApiInfo, mapper ParamMapper) (interface{}, error) {
var result interface{}
// start filter chain
err := web_filter.NewFilterChain(mapper.GetResponseWriter(), mapper.GetRequest(), func() error {
var err error
result, err = callFunc(svm, apiInfo.GetParams(), mapper)
return err
})
if err != nil {
return nil, err
}
return result, nil
}
func resolveResponse(w http.ResponseWriter, result interface{}, handler func(result interface{}) error) error {
// handle built-in resp.Response result
if res, ok := result.(resp.Response); ok {
res.Write(w)
return nil
}
// do web framework handler
return handler(result)
}
func handleErr(w http.ResponseWriter, err error) {
if respErr, ok := err.(resp.Response); ok {
respErr.Write(w)
} else {
resp.ErrInternalError(err).Write(w)
}
}
func callFunc(svm web.ServiceMethod, params []web.Param, mapper ParamMapper) (interface{}, error) {
paramValues, err := prepareParamValues(svm.GetMethod(), params, mapper)
if err != nil {
return nil, err
}
err = validateParamValues(paramValues)
if err != nil {
return nil, err
}
resultValue := svm.GetValue().Call(reflectx.Interfaces2Values(paramValues))
results := reflectx.Values2Interfaces(resultValue)
switch len(results) {
case 0:
return nil, nil
case 2:
if err, ok := results[1].(error); ok {
return nil, err
}
return results[0], nil
default:
return results[0], nil
}
}
func prepareParamValues(method *reflect.Method, params []web.Param, mapper ParamMapper) ([]interface{}, error) {
m := method.Type
var values []interface{}
for i := 0; i < m.NumIn()-1; i++ {
o, err := getValue(params[i], mapper)
if err != nil {
return nil, err
}
values = append(values, o)
}
return values, nil
}
func validateParamValues(params []interface{}) error {
for i := range params {
param := params[i]
err := validateParam(param)
if err != nil {
return err
}
}
return nil
}
func validateParam(param interface{}) error {
switch reflect.TypeOf(param).Kind() {
case reflect.Struct:
validate := validator.New()
err := validate.Struct(param)
if err != nil {
return err
}
case reflect.Ptr:
return validateParam(reflect.ValueOf(param).Elem().Interface())
}
return nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/kristas/booting-go.git
git@gitee.com:kristas/booting-go.git
kristas
booting-go
booting-go
v1.4.4

搜索帮助