内容简介: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 集群启动失败
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Web Design
Ethan Watrall、Jeff Siarto / O’Reilly Media, Inc. / 2009-01-02 / USD 49.99
Want to know how to make your pages look beautiful, communicate your message effectively, guide visitors through your website with ease, and get everything approved by the accessibility and usability ......一起来看看 《Head First Web Design》 这本书的介绍吧!