内容简介:1、首先看官方绑定,time.Time将绑定失败2、自定义绑定加入Struct类型判断:
1、首先看官方绑定,time.Time将绑定失败
func(c echo.Context) (err error) { u := new(User) if err = c.Bind(u); err != nil { return } return c.JSON(http.StatusOK, u) }
2、自定义绑定
加入Struct类型判断:
image.png
直接添加选项
case reflect.Struct: //时间类型 var t time.Time var err error val = strings.Replace(val, " 00:00:00", "", -1) if IsValidDate(val) { //判断日期格式 t, err = ParseDate(val) if err == nil { structField.Set(reflect.ValueOf(t)) } } else if IsValidTime(val) { //判断日期时间格式 t, err = ParseTime(val) if err == nil { structField.Set(reflect.ValueOf(t)) } } break
完整版bind.go
package handle import ( "reflect" "strconv" "strings" "github.com/labstack/echo" "net/http" "encoding/json" "fmt" "errors" "encoding/xml" "time" ) type CustomBinder struct{} // Bind implements the `Binder#Bind` function. func (b *CustomBinder) Bind(i interface{}, c echo.Context) (err error) { req := c.Request() if req.ContentLength == 0 { if req.Method == echo.GET || req.Method == echo.DELETE { if err = b.bindData(i, c.QueryParams(), "query"); err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } return } return echo.NewHTTPError(http.StatusBadRequest, "Request body can't be empty") } ctype := req.Header.Get(echo.HeaderContentType) switch { case strings.HasPrefix(ctype, echo.MIMEApplicationJSON): if err = json.NewDecoder(req.Body).Decode(i); err != nil { if ute, ok := err.(*json.UnmarshalTypeError); ok { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset)) } else if se, ok := err.(*json.SyntaxError); ok { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())) } else { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } } case strings.HasPrefix(ctype, echo.MIMEApplicationXML), strings.HasPrefix(ctype, echo.MIMETextXML): if err = xml.NewDecoder(req.Body).Decode(i); err != nil { if ute, ok := err.(*xml.UnsupportedTypeError); ok { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error())) } else if se, ok := err.(*xml.SyntaxError); ok { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error())) } else { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } } case strings.HasPrefix(ctype, echo.MIMEApplicationForm), strings.HasPrefix(ctype, echo.MIMEMultipartForm): params, err := c.FormParams() if err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } if err = b.bindData(i, params, "form"); err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } default: return echo.ErrUnsupportedMediaType } return } func (b *CustomBinder) bindData(ptr interface{}, data map[string][]string, tag string) error { typ := reflect.TypeOf(ptr).Elem() val := reflect.ValueOf(ptr).Elem() if typ.Kind() != reflect.Struct { return errors.New("binding element must be a struct") } for i := 0; i < typ.NumField(); i++ { typeField := typ.Field(i) structField := val.Field(i) if !structField.CanSet() { continue } structFieldKind := structField.Kind() inputFieldName := typeField.Tag.Get(tag) if inputFieldName == "" { inputFieldName = typeField.Name // If tag is nil, we inspect if the field is a struct. if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct { err := b.bindData(structField.Addr().Interface(), data, tag) if err != nil { return err } continue } } inputValue, exists := data[inputFieldName] if !exists { // Go json.Unmarshal supports case insensitive binding. However the // url params are bound case sensitive which is inconsistent. To // fix this we must check all of the map values in a // case-insensitive search. inputFieldName = strings.ToLower(inputFieldName) for k, v := range data { if strings.ToLower(k) == inputFieldName { inputValue = v exists = true break } } } if !exists { continue } // Call this first, in case we're dealing with an alias to an array type if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok { if err != nil { return err } continue } numElems := len(inputValue) if structFieldKind == reflect.Slice && numElems > 0 { sliceOf := structField.Type().Elem().Kind() slice := reflect.MakeSlice(structField.Type(), numElems, numElems) for j := 0; j < numElems; j++ { if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil { return err } } val.Field(i).Set(slice) } else { if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil { return err } } } return nil } func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error { // But also call it here, in case we're dealing with an array of BindUnmarshalers if ok, err := unmarshalField(valueKind, val, structField); ok { return err } switch valueKind { case reflect.Ptr: return setWithProperType(structField.Elem().Kind(), val, structField.Elem()) case reflect.Int: return setIntField(val, 0, structField) case reflect.Int8: return setIntField(val, 8, structField) case reflect.Int16: return setIntField(val, 16, structField) case reflect.Int32: return setIntField(val, 32, structField) case reflect.Int64: return setIntField(val, 64, structField) case reflect.Uint: return setUintField(val, 0, structField) case reflect.Uint8: return setUintField(val, 8, structField) case reflect.Uint16: return setUintField(val, 16, structField) case reflect.Uint32: return setUintField(val, 32, structField) case reflect.Uint64: return setUintField(val, 64, structField) case reflect.Bool: return setBoolField(val, structField) case reflect.Float32: return setFloatField(val, 32, structField) case reflect.Float64: return setFloatField(val, 64, structField) case reflect.String: structField.SetString(val) case reflect.Struct: //时间类型 var t time.Time var err error val = strings.Replace(val, " 00:00:00", "", -1) if IsValidDate(val) { t, err = ParseDate(val) if err == nil { structField.Set(reflect.ValueOf(t)) } } else if IsValidTime(val) { t, err = ParseTime(val) if err == nil { structField.Set(reflect.ValueOf(t)) } } break default: return errors.New("unknown type") } return nil } func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) { switch valueKind { case reflect.Ptr: return unmarshalFieldPtr(val, field) default: return unmarshalFieldNonPtr(val, field) } } // bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler func bindUnmarshaler(field reflect.Value) (echo.BindUnmarshaler, bool) { ptr := reflect.New(field.Type()) if ptr.CanInterface() { iface := ptr.Interface() if unmarshaler, ok := iface.(echo.BindUnmarshaler); ok { return unmarshaler, ok } } return nil, false } func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) { if unmarshaler, ok := bindUnmarshaler(field); ok { err := unmarshaler.UnmarshalParam(value) field.Set(reflect.ValueOf(unmarshaler).Elem()) return true, err } return false, nil } func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) { if field.IsNil() { // Initialize the pointer to a nil value field.Set(reflect.New(field.Type().Elem())) } return unmarshalFieldNonPtr(value, field.Elem()) } func setIntField(value string, bitSize int, field reflect.Value) error { if value == "" { value = "0" } intVal, err := strconv.ParseInt(value, 10, bitSize) if err == nil { field.SetInt(intVal) } return err } func setUintField(value string, bitSize int, field reflect.Value) error { if value == "" { value = "0" } uintVal, err := strconv.ParseUint(value, 10, bitSize) if err == nil { field.SetUint(uintVal) } return err } func setBoolField(value string, field reflect.Value) error { if value == "" { value = "false" } boolVal, err := strconv.ParseBool(value) if err == nil { field.SetBool(boolVal) } return err } func setFloatField(value string, bitSize int, field reflect.Value) error { if value == "" { value = "0.0" } floatVal, err := strconv.ParseFloat(value, bitSize) if err == nil { field.SetFloat(floatVal) } return err } func ParseTime(date string) (time.Time, error) { date = strings.Replace(date, "/", "-", -1) date = strings.Replace(date, ".", "-", -1) return time.Parse("2006-01-02 15:04:05", date) } func ParseDate(date string) (time.Time, error) { date = strings.Replace(date, "/", "-", -1) date = strings.Replace(date, ".", "-", -1) return time.Parse("2006-01-02", date) } func IsValidTime(s string) bool { _, err := time.Parse("2006-01-02 15:04:05", s) if err != nil { return false } return true } func IsValidDate(s string) bool { _, err := time.Parse("2006-01-02", s) if err != nil { return false } return true }
使用示例:
if err := new(CustomBinder).Bind(user, c); err != nil { ... }
以上所述就是小编给大家介绍的《Golang Echo数据绑定中time.Time类型绑定失败》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- macos – dyld:惰性符号绑定失败:未找到符号:_PQsetErrorContextVisibility
- 快速失败机制 & 失败安全机制
- 通过不断地失败来避免失败,携程混沌工程实践
- 快速失败(fail-fast)和安全失败(fail-safe)
- 如何在Symfony的表单中添加一个未绑定字段,否则绑定到一个实体?
- greenplum 集群启动失败
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。