Go 的表单绑定器
Go 做 Web 开发,也算成熟了,平时后台开发,需要一款得心应手的表单绑定器,表单绑定器能快捷把表单数据填充业务实体类,免去 request 里一个个获取数据,赋值给实体类,省去了大量的时间和代码。
目前发现两个比较好用的表单绑定器:
binding: https://github.com/mholt/binding
bind: https://github.com/robfig/bind
自己常用的是 binding,功能比较完善,人气也多一些;而 bind 人气少很多,几乎没有被人发现。要我说哪个好用,个人觉得 bind 直接些,因为 bind 使用起来很简单,纯粹奔着绑定表单用途,实体类 struct 不需要写额外代码,但代价是表单字段名和实体类属性名一致,在业务代码块,直接使用 bind 即可,节省了代码;返回object 错误;至于 binding 需要再实体类中添加一些 FieldMap 代码,返回错误是 json 格式的,功能更强大,可以自定义错误信息,可以验证字段,表单别名映射更灵活等等优势。
两者支持的数据类型都很丰富,基本全面涵盖了可能出现的类型。
bind 支持的数据类型如下:
- bool
- float32, float64
- int, int8, int16, int32, int64
- uint, uint8, uint16, uint32, uint64
- string
- struct
- a pointer to any supported type
- a slice of any supported type
- time.Time
- uploaded files (as io.Reader, io.ReadSeeker, *os.File, []byte, *multipart.FileHeader)
binding 支持的数据类型如下:
- uint, *uint, []uint, uint8, *uint8, []uint8, uint16, *uint16, []uint16, uint32, *uint32, - []uint32, uint64, *uint64, []uint64
- int, *int, []int, int8, *int8, []int8, int16, *int16, []int16, int32, *int32, []int32, int64, - *int64, []int64
- float32, *float32, []float32, float64, *float64, []float64
- bool, *bool, []bool
- string, *string, []string
- time.Time, *time.Time, []time.Time
- multipart.FileHeader, []multipart.FileHeader
作者描述详尽不一样,其实 bind 也支持 Slices 类型
bind 的使用方法:
POST /accounts/:accountId/users/?op=UPDATE
相当简洁明了!!!!
binding 使用方法:
两个功能都比较齐全,上传文件也会支持。绑定时间的时候,bingding 需要注意时区的问题,必要时候需要指定 TimeFormat,如上Created的定义。而 bind 默认支持时间格式:"2006-01-02 15:04",""2006-01-02",如果需要时间秒,则需要指定:
-EOF-
目前发现两个比较好用的表单绑定器:
binding: https://github.com/mholt/binding
bind: https://github.com/robfig/bind
自己常用的是 binding,功能比较完善,人气也多一些;而 bind 人气少很多,几乎没有被人发现。要我说哪个好用,个人觉得 bind 直接些,因为 bind 使用起来很简单,纯粹奔着绑定表单用途,实体类 struct 不需要写额外代码,但代价是表单字段名和实体类属性名一致,在业务代码块,直接使用 bind 即可,节省了代码;返回object 错误;至于 binding 需要再实体类中添加一些 FieldMap 代码,返回错误是 json 格式的,功能更强大,可以自定义错误信息,可以验证字段,表单别名映射更灵活等等优势。
两者支持的数据类型都很丰富,基本全面涵盖了可能出现的类型。
bind 支持的数据类型如下:
- bool
- float32, float64
- int, int8, int16, int32, int64
- uint, uint8, uint16, uint32, uint64
- string
- struct
- a pointer to any supported type
- a slice of any supported type
- time.Time
- uploaded files (as io.Reader, io.ReadSeeker, *os.File, []byte, *multipart.FileHeader)
binding 支持的数据类型如下:
- uint, *uint, []uint, uint8, *uint8, []uint8, uint16, *uint16, []uint16, uint32, *uint32, - []uint32, uint64, *uint64, []uint64
- int, *int, []int, int8, *int8, []int8, int16, *int16, []int16, int32, *int32, []int32, int64, - *int64, []int64
- float32, *float32, []float32, float64, *float64, []float64
- bool, *bool, []bool
- string, *string, []string
- time.Time, *time.Time, []time.Time
- multipart.FileHeader, []multipart.FileHeader
作者描述详尽不一样,其实 bind 也支持 Slices 类型
bind 的使用方法:
POST /accounts/:accountId/users/?op=UPDATE
<form> <input name="user.Id"> <input name="user.Name"> <input name="user.Phones[0].Label"> <input name="user.Phones[0].Number"> <input name="user.Phones[1].Label"> <input name="user.Phones[1].Number"> <input name="user.Labels[]"> <input name="user.Labels[]"> </form> type Phone struct { Label, Number string } type User struct { Id uint32 Phones []Phone Labels []string } var ( params = mux.Vars(req) // embedded URL args id uint32 op string user User ) handleErrors( bind.Map(params).Field(&id, "accountId"), bind.Request(req).Field(&op, "op") bind.Request(req).Field(&user, "user"), )
相当简洁明了!!!!
binding 使用方法:
// First define a type to hold the data // (If the data comes from JSON, see: http://mholt.github.io/json-to-go) type ContactForm struct { User struct { ID int } Email string Message string Created time.Time } // Then provide a field mapping (pointer receiver is vital) func (cf *ContactForm) FieldMap(req *http.Request) binding.FieldMap { return binding.FieldMap{ &cf.User.ID: "user_id", &cf.Email: "email", &cf.Message: binding.Field{ Form: "message", Required: true, }, &cf.Created: binding.Field{ Form: "advert.Created", TimeFormat: "2006-01-02 15:04:05", }, } } // Now your handlers can stay clean and simple func handler(resp http.ResponseWriter, req *http.Request) { contactForm := new(ContactForm) errs := binding.Bind(req, contactForm) if errs.Handle(resp) { return } fmt.Fprintf(resp, "From: %d\n", contactForm.User.ID) fmt.Fprintf(resp, "Message: %s\n", contactForm.Message) }很明显 实体类需要定义 FieldMap 方法,做一个表单和实体类的桥接定义。
两个功能都比较齐全,上传文件也会支持。绑定时间的时候,bingding 需要注意时区的问题,必要时候需要指定 TimeFormat,如上Created的定义。而 bind 默认支持时间格式:"2006-01-02 15:04",""2006-01-02",如果需要时间秒,则需要指定:
func init() { bind.TimeFormats = append(bind.TimeFormats, "2006-01-02 15:04:05") }
-EOF-
哇~~~ 竟然还没有评论!