业务场景:
在使用go-xorm框架,mysql数据库,json格式传参的时候,一种情况:数据库的字段非varchar类型,且该字段可空.
此时如果我们定义接收前端参数的结构体对应该字段为string时, 前端传入的值为空时,我们后台unmarshal之后,该字段对应的值为空;例如: 后台数据库有一个字段total_fee是float 类型, 此时如果要往插入该条数据,我们可以采用两种方法:
1.拼接sql, 此时我们需要判断total_fee是否为空,因为,如果往数据插入""的时候,因为数据对应的float类型,会报错,所以直接不拼接这个字段是可以解决的.
2.将前端传入的参数转化,和数据库对应起来.
因为拼接sql工程量大,且容易出错,所以我们这里介绍第二种方法,然后直接利用go-xorm的insert()方法插入数据.
解决代码:
package main import ( "reflect" "github.com/mitchellh/mapstructure" "fmt" "time" "strings" ) type A struct { Name string Id int TheTime string Price string } type B struct { Name string Id string TheTime interface{} Price interface{} } //定义一个方法,将结构体A转化为B func StructAtoB (a interface{},b interface{}) map[string]interface{}{ //第一步,先将结构体转化为map方便后续遍历 amap := Struct2Map(a) bmap := Struct2Map(b) //开始遍历A结构体的字段 for k1, v1 := range amap { for k2,v2:= range bmap { typea := reflect.TypeOf(v1) typeb := reflect.TypeOf(v2) if k1 == k2 && typea==typeb { bmap[k2] = v1 } if k1==k2 && typea!=typeb { if typeb == tInterface { //因为我们假设开放给前端的类型是字符串,所以我们直接用string转换为datetime //1.断言v1为string vs, ok := v1.(string) if ok { fmt.Println("开始转换number") if vs == "" { //v2 = nil //bmap[k2]=v2 continue } bmap[k2] = v1 } } } } } return bmap } func Struct2Map(obj interface{}) map[string]interface{} { t := reflect.TypeOf(obj) v := reflect.ValueOf(obj) var data = make(map[string]interface{}) for i := 0; i < t.NumField(); i++ { data[t.Field(i).Name] = v.Field(i).Interface() } return data } func main() { var a A var b B a.Name="namea" a.Id = 2 a.TheTime ="20180304" a.Price = "1.0" mapre := StructAtoB(a,b) if err := mapstructure.Decode(mapre, &b); err != nil { fmt.Println("the err when unmarshal mapstructure is:",err) } fmt.Println("the result is :",b) fmt.Printf("the b'prcie is :%v,and b's type is:%T",b.Price,b.Price) }我们将数据库可空的非varchar类型字段全部用interface代替即可.
局限性:目前只解决了前端传入为string的情况, 入参不能为指针类型,只能是普通的结构体.