package httper import ( "encoding/base64" "encoding/json" "fmt" "reflect" "strconv" "strings" "github.com/astaxie/beego/context" "go.uber.org/zap" ) var ( Debug = false DebugLog *zap.Logger ) func FillRequireParams(ctx *context.Context, param interface{}, logID string) { v := reflect.ValueOf(param) if v.Kind() == reflect.Ptr { v = v.Elem() } if v.Kind() != reflect.Struct { SystemError("query is not a struct") } numField := v.NumField() for i := 0; i < numField; i++ { fillParams(ctx, v.Type().Field(i), v.Field(i)) } if Debug && DebugLog != nil { data, _ := json.Marshal(param) DebugLog.Debug(logID, zap.String("request", string(data))) } } func furtherFillRequireParams(ctx *context.Context, param interface{}) { v := reflect.ValueOf(param) if v.Kind() == reflect.Ptr { v = v.Elem() } if v.Kind() != reflect.Struct { SystemError("query is not a struct") } numField := v.NumField() for i := 0; i < numField; i++ { fillParams(ctx, v.Type().Field(i), v.Field(i)) } } func fillParams(ctx *context.Context, field reflect.StructField, val reflect.Value) { //fmt.Println(ctx.Input.Context.Request.Header) switch field.Tag.Get("in") { case "header": fillHeaderParams(ctx, field, val) case "body": fillBodyParams(ctx, field, val) case "path": fillPathParams(ctx, field, val) case "formData": fallthrough case "query": fillQueryParams(ctx, field, val) default: if !val.IsValid() || !val.CanAddr() || !val.CanSet() { SystemError("value can not set") } furtherFillRequireParams(ctx, val.Addr().Interface()) } } func fillBodyParams(ctx *context.Context, field reflect.StructField, val reflect.Value) { if !val.IsValid() || !val.CanAddr() || !val.CanSet() { SystemError("value can not set") } if val.Kind() == reflect.Ptr { val = val.Elem() } body := ctx.Input.RequestBody switch field.Tag.Get("decode") { case "base64": body, _ = base64.StdEncoding.DecodeString(string(body)) } if err := json.Unmarshal(body, val.Addr().Interface()); err != nil { BadParamer(fmt.Sprintf("%s is not json error:%s", "body", err)) } CheckBodyFiled(val.Addr().Interface()) } func CheckBodyFiled(param interface{}, logID ...interface{}) { v := reflect.ValueOf(param) if v.Kind() == reflect.Ptr { v = v.Elem() } if v.Kind() != reflect.Struct { SystemError("body is not a struct") } numField := v.NumField() for i := 0; i < numField; i++ { if v.Field(i).Kind() == reflect.Struct { //递归检查 CheckBodyFiled(v.Field(i).Addr().Interface()) } field := v.Type().Field(i) val := v.Field(i) if reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface()) { if field.Tag.Get("required") == "true" { jsonTag := field.Tag.Get("json") if jsonTag == "" { jsonTag = field.Name } def := field.Tag.Get("default") fillValue(v.Field(i), def, true, jsonTag) } } } } func fillHeaderParams(ctx *context.Context, field reflect.StructField, val reflect.Value) { jsonTag := field.Tag.Get("json") if jsonTag == "" { // 没有json标记,取变量的名称 jsonTag = field.Name } var v string if v = ctx.Input.Header(jsonTag); v == "" { // 尝试将第一个字母转换为大写 测试环境使用 beego Swagger的bug firstUpperJsonTag := strings.ToUpper(jsonTag[0:1]) + string(jsonTag[1:]) if v = ctx.Input.Header(firstUpperJsonTag); v == "" { v = field.Tag.Get("default") } } required := field.Tag.Get("required") == "true" if v == "" && required { BadParamer(fmt.Sprintf("%s is not exists in header", jsonTag)) } fmt.Printf("header:%v\n", v) fillValue(val, v, required, jsonTag) } func fillPathParams(ctx *context.Context, field reflect.StructField, val reflect.Value) { jsonTag := field.Tag.Get("json") if jsonTag == "" { // 没有json标记,取变量的名称 jsonTag = field.Name } var v string if v = ctx.Input.Param(fmt.Sprintf(":%s", jsonTag)); v == "" { v = field.Tag.Get("default") } required := field.Tag.Get("required") == "true" if v == "" && required { BadParamer(fmt.Sprintf("%s is not exists in path", jsonTag)) } fillValue(val, v, required, jsonTag) } func fillQueryParams(ctx *context.Context, field reflect.StructField, val reflect.Value) { jsonTag := field.Tag.Get("json") if jsonTag == "" { // 没有json标记,取变量的名称 jsonTag = field.Name } var v string if v = ctx.Input.Query(jsonTag); v == "" { v = field.Tag.Get("default") } required := field.Tag.Get("required") == "true" if v == "" && required { BadParamer(fmt.Sprintf("%s is not exists in query", jsonTag)) } fillValue(val, v, required, jsonTag) } func fillValue(val reflect.Value, requestVal string, required bool, jsonTag string) { if val.Kind() == reflect.Ptr { val = val.Elem() } kind := val.Kind() switch { case kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64: if requestVal == "" && !required { requestVal = "0" } v, err := strconv.ParseUint(requestVal, 10, 64) if err != nil { BadParamer(fmt.Sprintf("%s is not uint", jsonTag)) } if !val.IsValid() || !val.CanSet() { SystemError("value can not set") } val.SetUint(v) case kind == reflect.Int || kind == reflect.Int64: if requestVal == "" && !required { requestVal = "0" } v, err := strconv.ParseInt(requestVal, 10, 64) if err != nil { BadParamer(fmt.Sprintf("%s is not uint", jsonTag)) } if !val.IsValid() || !val.CanSet() { SystemError("value can not set") } val.SetInt(v) case kind == reflect.Float64 || kind == reflect.Float32: if requestVal == "" && !required { requestVal = "0" } v, err := strconv.ParseFloat(requestVal, 64) if err != nil { BadParamer(fmt.Sprintf("%s is not uint", jsonTag)) } if !val.IsValid() || !val.CanSet() { SystemError("value can not set") } val.SetFloat(v) case kind == reflect.String: val.SetString(requestVal) case kind == reflect.Bool: if requestVal == "" { requestVal = "false" } v, err := strconv.ParseBool(requestVal) if err != nil { BadParamer(fmt.Sprintf("%s is not bool", jsonTag)) } val.SetBool(v) default: BadParamer("type is not support") } }