-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8677ee0
Showing
26 changed files
with
2,048 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package binding | ||
|
||
import "net/http" | ||
|
||
type Binding interface { | ||
Name() string | ||
Bind(*http.Request, interface{}) error | ||
} | ||
|
||
var ( | ||
JSON = jsonBinding{} | ||
XML = xmlBinding{} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package binding | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"reflect" | ||
) | ||
|
||
type jsonBinding struct { | ||
DisallowUnknownFields bool | ||
IsValidate bool | ||
} | ||
|
||
func (jsonBinding) Name() string { | ||
return "json" | ||
} | ||
|
||
func (b jsonBinding) Bind(r *http.Request, obj interface{}) error { | ||
body := r.Body | ||
// post传参的内容 是放在 body中的 | ||
if body == nil { | ||
return errors.New("invalid request") | ||
} | ||
decoder := json.NewDecoder(body) | ||
if b.DisallowUnknownFields { | ||
decoder.DisallowUnknownFields() | ||
} | ||
if b.IsValidate { | ||
err := validateParam(obj, decoder) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
err := decoder.Decode(obj) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return validate(obj) | ||
} | ||
|
||
func validateParam(obj interface{}, decoder *json.Decoder) error { | ||
|
||
// 反射 | ||
valueOf := reflect.ValueOf(obj) | ||
// 判断其是否为指针类型 | ||
if valueOf.Kind() != reflect.Ptr { | ||
return errors.New("This argument must have a pointer type") | ||
} | ||
elem := valueOf.Elem().Interface() | ||
of := reflect.ValueOf(elem) | ||
|
||
switch of.Kind() { | ||
case reflect.Struct: | ||
return checkParam(of, obj, decoder) | ||
case reflect.Slice, reflect.Array: | ||
elem := of.Type().Elem() | ||
if elem.Kind() == reflect.Struct { | ||
return checkParamSlice(elem, obj, decoder) | ||
} | ||
default: | ||
_ = decoder.Decode(obj) | ||
} | ||
return nil | ||
} | ||
|
||
func checkParamSlice(of reflect.Type, obj interface{}, decoder *json.Decoder) error { | ||
mapValue := make([]map[string]interface{}, 0) | ||
_ = decoder.Decode(&mapValue) | ||
for i := 0; i < of.NumField(); i++ { | ||
field := of.Field(i) | ||
name := field.Name | ||
jsonName := field.Tag.Get("json") | ||
if jsonName != "" { | ||
name = jsonName | ||
} | ||
required := field.Tag.Get("polevalidate") | ||
for _, v := range mapValue { | ||
value := v[name] | ||
if value == nil && required == "required" { | ||
return errors.New(fmt.Sprintf("filed [%s] is not exist,because [%s] is required", jsonName, jsonName)) | ||
} | ||
} | ||
} | ||
b, _ := json.Marshal(mapValue) | ||
_ = json.Unmarshal(b, obj) | ||
return nil | ||
} | ||
|
||
func checkParam(of reflect.Value, obj interface{}, decoder *json.Decoder) error { | ||
// 解析为map,然后根据map中的key 进行比对 | ||
// 判断类型 结构体 才能解析为map | ||
mapValue := make(map[string]interface{}) | ||
_ = decoder.Decode(&mapValue) | ||
for i := 0; i < of.NumField(); i++ { | ||
field := of.Type().Field(i) | ||
name := field.Name | ||
jsonName := field.Tag.Get("json") | ||
if jsonName != "" { | ||
name = jsonName | ||
} | ||
required := field.Tag.Get("polevalidate") | ||
value := mapValue[name] | ||
if value == nil && required == "required" { | ||
return errors.New(fmt.Sprintf("filed [%s] is not exist,because [%s] is required", jsonName, jsonName)) | ||
} | ||
} | ||
b, _ := json.Marshal(mapValue) | ||
_ = json.Unmarshal(b, obj) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package binding | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"strings" | ||
"sync" | ||
|
||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
type StructValidator interface { | ||
// 结构体验证,如果错误返回对应的错误信息 | ||
ValidateStruct(interface{}) error | ||
// 返回对应使用的验证器 | ||
Engine() interface{} | ||
} | ||
|
||
var Validator StructValidator = &defaultValidator{} | ||
|
||
type defaultValidator struct { | ||
one sync.Once | ||
validate *validator.Validate | ||
} | ||
|
||
type SliceValidationError []error | ||
|
||
func (err SliceValidationError) Error() string { | ||
n := len(err) | ||
switch n { | ||
case 0: | ||
return "" | ||
default: | ||
var b strings.Builder | ||
if err[0] != nil { | ||
fmt.Fprintf(&b, "[%d]: %s", 0, err[0].Error()) | ||
} | ||
if n > 1 { | ||
for i := 1; i < n; i++ { | ||
if err[i] != nil { | ||
b.WriteString("\n") | ||
fmt.Fprintf(&b, "[%d]: %s", i, err[i].Error()) | ||
} | ||
} | ||
} | ||
return b.String() | ||
} | ||
} | ||
|
||
func (d *defaultValidator) ValidateStruct(obj interface{}) error { | ||
of := reflect.ValueOf(obj) | ||
switch of.Kind() { | ||
case reflect.Ptr: | ||
return d.ValidateStruct(of.Elem().Interface()) | ||
case reflect.Struct: | ||
return d.validateStruct(obj) | ||
case reflect.Slice, reflect.Array: | ||
count := of.Len() | ||
sliceValidationError := make(SliceValidationError, 0) | ||
for i := 0; i < count; i++ { | ||
if err := d.validateStruct(of.Index(i).Interface()); err != nil { | ||
sliceValidationError = append(sliceValidationError, err) | ||
} | ||
} | ||
if len(sliceValidationError) == 0 { | ||
return nil | ||
} | ||
return sliceValidationError | ||
} | ||
return nil | ||
} | ||
|
||
func (d *defaultValidator) Engine() interface{} { | ||
d.lazyInit() | ||
return d.validate | ||
} | ||
|
||
func (d *defaultValidator) lazyInit() { | ||
d.one.Do(func() { | ||
d.validate = validator.New() | ||
}) | ||
} | ||
|
||
func (d *defaultValidator) validateStruct(obj interface{}) error { | ||
d.lazyInit() | ||
return d.validate.Struct(obj) | ||
} | ||
|
||
func validate(obj interface{}) error { | ||
return Validator.ValidateStruct(obj) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package binding | ||
|
||
import ( | ||
"encoding/xml" | ||
"net/http" | ||
) | ||
|
||
type xmlBinding struct { | ||
} | ||
|
||
func (xmlBinding) Name() string { | ||
return "xml" | ||
} | ||
|
||
func (b xmlBinding) Bind(r *http.Request, obj interface{}) error { | ||
if r.Body == nil { | ||
return nil | ||
} | ||
decoder := xml.NewDecoder(r.Body) | ||
if err := decoder.Decode(obj); err != nil { | ||
return err | ||
} | ||
return validate(obj) | ||
} |
Oops, something went wrong.