业务场景:
在使用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的情况, 入参不能为指针类型,只能是普通的结构体.