golang根据json更新struct内容

想到一个场景,由于数据库操作感觉新建修改各种字段不太方便,想搞一个字段能够装下所有,但是还要限制一下字段的内容及类型。
譬如说如下场景,接口传来了如下json数据,但是只想保存学生结构体中的字段。
json数据如下:

{
    
    
  "name": "张三",
  "age": 18,
  "email": "[email protected]",
  "status": "game"
}

学生结构体如下:

type Student struct {
    
    
	Name  string  `json:"name"`
	Age   float64 `json:"age"`
	Phone string  `json:"phone"`
}

结构体原始的数值为

{
    
    "name": "李四", "age": 12, "phone": "18688886666"}

那么想搞一个函数直接把json中在结构体中存在的字段给更新了,其他的保持不变,以下就记录一下这个方法怎么实现。

首先想到的就是通过反射获取结构体中的json tag,然后在json中查找tag是否存在,如果存在看类型一致就给更新一下。

func UpdateStructByJson(v reflect.Value, js string) {
    
    
	var data map[string]interface{
    
    }
	err := json.Unmarshal([]byte(js), &data)
	if err != nil {
    
    
		return
	}

	for i := 0; i < v.NumField(); i++ {
    
    
		field := v.Type().Field(i)
		tag := field.Tag.Get("json")
		if tag == "" {
    
    
			continue
		}
		value, ok := data[tag]
		if !ok {
    
    
			continue
		}
		f := v.Field(i)
		if !f.CanSet() {
    
    
			continue
		}
		fv := reflect.ValueOf(value)
		if fv.Type().AssignableTo(f.Type()) {
    
    
			f.Set(fv)
		}
	}
}

其中接收了一个 reflect.Value 的参数,因为传入的类型如果是any在函数内部不类型转换无法拆包,因此入参数是一个反射类型,函数内部就屏蔽了结构类型的影响。
在外部获取一下反射类型的

v := reflect.ValueOf(&d).Elem()

这样基本上就能够完美的实现根据json更新struct的内容了。后端服务就能够不改变数据库的表结构,根据实际需求增删字段,版本迭代效率也会大大提高。
以下是完整测试代码。

package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

type Student struct {
    
    
	Name  string  `json:"name"`
	Age   float64 `json:"age"`
	Phone string  `json:"phone"`
}

func UpdateStructByJson(v reflect.Value, js string) {
    
    
	var data map[string]interface{
    
    }
	err := json.Unmarshal([]byte(js), &data)
	if err != nil {
    
    
		return
	}

	for i := 0; i < v.NumField(); i++ {
    
    
		field := v.Type().Field(i)
		tag := field.Tag.Get("json")
		if tag == "" {
    
    
			continue
		}
		value, ok := data[tag]
		if !ok {
    
    
			continue
		}
		f := v.Field(i)
		if !f.CanSet() {
    
    
			continue
		}
		fv := reflect.ValueOf(value)
		if fv.Type().AssignableTo(f.Type()) {
    
    
			f.Set(fv)
		}
	}
}

func main() {
    
    
	newJsonString := `{"name": "张三", "age": 18, "email": "[email protected]", "status": "game"}`
	oldJsonString := `{"name": "李四", "age": 12, "phone": "18688886666"}`

	var d Student
	json.Unmarshal([]byte(oldJsonString), &d)

	v := reflect.ValueOf(&d).Elem()
	UpdateStructByJson(v, newJsonString)

	// 转换为JSON字符串
	jsonBytes, err := json.Marshal(d)
	if err != nil {
    
    
		panic(err)
	}

	fmt.Println(string(jsonBytes))
}

猜你喜欢

转载自blog.csdn.net/xo19882011/article/details/131439499