场景:第三方传过来的数据是json,用json.Unmarshal()转结构体的时候int类型自动转成科学计算法,或者转成floate64类型很是头大。为此想了很多办法最后找到json.number+反射解决。
1、将拿到的字符串使用json.number处理代码如下:
decoder1 := json.NewDecoder(bytes.NewBuffer([]byte("")))
decoder1.UseNumber()
err := decoder1.Decode(结构体指针)
2、通过json.number解析处理的map[string]interface{}转换为结构体代码如下:
func MapTOStruct(data map[string]interface{}, inter interface{}) (err error) {
var targetField *string
defer func() {
if p := recover(); p != nil {
errMsg := fmt.Sprintf("MapTOStruct error:%v, field:%s", p, *targetField)
err = errors.New(errMsg)
}
}()
// 把key转成小写
dataLower := make(map[string]interface{})
for k, v := range data {
dataLower[strings.ToLower(k)] = v
}
poValues := reflect.ValueOf(inter).Elem()
poTypes := poValues.Type()
for i := 0; i < poValues.NumField(); i++ {
// po字段类型
poField := poTypes.Field(i)
// po字段值
poValue := poValues.Field(i)
// 字段名(优先用json注释,如果json注释不存在,则使用db注释)
colName := poField.Tag.Get("json")
if len(colName) == 0 {
colName = poField.Tag.Get("db")
}
targetField = &colName
// map值
value, isExists := dataLower[strings.ToLower(colName)]
var strValue = ""
if value != nil {
strValue = fmt.Sprintf("%v", value.(interface{}))
}
//根据po字段类型赋值
switch poField.Type.String() {
case "sql.NullString":
if !isExists || value == nil || value == "" {
poValue.Set(reflect.ValueOf(NullString("", true)))
} else {
poValue.Set(reflect.ValueOf(NullString(strValue, true)))
}
case "sql.NullInt32":
if !isExists || value == nil {
poValue.Set(reflect.ValueOf(NullInt32(0, true)))
} else {
intvalue, err := strconv.Atoi(strValue)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(NullInt32(int32(intvalue), true)))
}
case "sql.NullInt64":
if !isExists || value == nil {
poValue.Set(reflect.ValueOf(NullInt64(0, true)))
} else {
intvalue, err := strconv.ParseInt(strValue, 10, 64)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(NullInt64(intvalue, true)))
}
case "sql.NullFloat64":
if !isExists || value == nil {
poValue.Set(reflect.ValueOf(NullFloat64(0, true)))
} else {
float64value, err := strconv.ParseFloat(strValue, 64)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(NullFloat64(float64value, true)))
}
case "sql.NullTime":
if !isExists || value == nil || len(strValue) == 0 {
poValue.Set(reflect.ValueOf(sql.NullTime{Valid: false}))
} else {
poValue.Set(reflect.ValueOf(NullTime(parseTimeStr(strValue), true)))
}
case "time.Time":
if !isExists || value == nil || len(strValue) == 0 {
continue
}
poValue.Set(reflect.ValueOf(parseTimeStr(strValue)))
default:
if !isExists || value == nil {
continue
}
if poField.Type.String() == "int32" {
valueInt32, err := strconv.ParseInt(strValue, 10, 32)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(int32(valueInt32)))
} else if poField.Type.String() == "uint32" {
valueUint32, err := strconv.ParseInt(strValue, 10, 32)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(uint32(valueUint32)))
} else if poField.Type.String() == "int64" {
valueInt64, err := strconv.ParseInt(strValue, 10, 64)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(valueInt64))
} else if poField.Type.String() == "uint64" {
valueUint64, err := strconv.ParseUint(strValue, 10, 64)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(valueUint64))
} else if poField.Type.String() == "float64" {
valueFloat64, err := strconv.ParseFloat(strValue, 64)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(valueFloat64))
} else if poField.Type.String() == "string" {
poValue.Set(reflect.ValueOf(strValue))
} else if poField.Type.String() == "bool" {
valueBool, err := strconv.ParseBool(strValue)
if err != nil {
continue
}
poValue.Set(reflect.ValueOf(valueBool))
} else {
poValue.Set(reflect.ValueOf(value))
}
}
}
return nil
}
var TimeLayout = []string{
"2006-01-02 15:04:05.000",
}
func parseTimeStr(timeStr string) time.Time {
for i := 0; i < len(TimeLayout); i++ {
layout := TimeLayout[i]
var err error
var result time.Time
if strings.Contains(layout, "Z") || strings.Contains(layout, "z") {
result, err = time.Parse(layout, timeStr)
} else {
result, err = time.ParseInLocation(layout, timeStr, time.Local)
}
if err == nil {
return result
}
}
return time.Time{}
}
func NullString(str string, valid bool) sql.NullString {
return sql.NullString{String: str, Valid: valid}
}
func NullInt32(i int32, valid bool) sql.NullInt32 {
return sql.NullInt32{Int32: i, Valid: valid}
}
func NullInt64(i int64, valid bool) sql.NullInt64 {
return sql.NullInt64{Int64: i, Valid: valid}
}
func NullFloat64(f float64, valid bool) sql.NullFloat64 {
return sql.NullFloat64{Float64: f, Valid: valid}
}
func NullTime(t time.Time, valid bool) sql.NullTime {
return sql.NullTime{Time: t, Valid: valid}
}