golang json

案例记录

结构体转json,避免对[]byte进行base64

背景

protobuf 2如果定义bytes格式,会生成如下格式的结构体。

type KbVideoInput struct {
	KbArticleId         []byte `protobuf:"bytes,1,opt,name=kb_article_id" json:"kb_article_id,omitempty"`
	Title               []byte `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"`
	Time                *uint32  `protobuf:"varint,5,opt,name=time" json:"time,omitempty"`
	NewIndexScore       *float64        `protobuf:"fixed64,92,opt,name=new_index_score" json:"new_index_score,omitempty"`
	}

对于[]byte类型的字段,如果直接通过json.marshal转换成json字符串(pb提供的jsonpb也是直接调用json.marshal),会对值进行base64处理。

往往不符合期望结果。

代码记录

为解决上述问题,通过两个函数:

根据json tag转换struct到map中

// 只解析一层结构的struct
func StuctToJsonMap(structData interface{}) *map[string]interface{} {
    ret := make(map[string]interface{})
        TypeData := reflect.TypeOf(structData).Elem()
    ValueData := reflect.ValueOf(structData).Elem()
    for i := 0; i < TypeData.NumField(); i++ {
        fieldKey := TypeData.Field(i)
        fieldVal := ValueData.Field(i)
        tagKey, tagOp := parseTag(fieldKey.Tag.Get("json"))
        if tagKey == "-" {
            continue
        }
        //fmt.Printf("tagKey: %s, tag op: %s\n", tagKey, tagOp)
        //fmt.Printf("fieldVal: %s, fieldVal.IsValid: %v\n", fieldVal, fieldVal.IsNil())
        if !fieldVal.IsNil() {
            ret[tagKey] = fieldVal.Interface()
        } else {
            if tagOp != "omitempty" {
                ret[tagKey] = fieldVal.Interface()
            }
        }
    }
    return &ret
}

// tagOptions is the string following a comma in a struct field's "json"
// tag, or the empty string. It does not include the leading comma.
type tagOptions string

// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
    if idx := strings.Index(tag, ","); idx != -1 {
        return tag[:idx], tagOptions(tag[idx+1:])
    }
    return tag, tagOptions("")
}

map中的byte转string处理,防止json出现base64

func MapByteToString(dataMap *map[string]interface{}) {
    for k, v := range *dataMap {
        //fmt.Printf("key: %s, val: %+v, type: %s\n", k, v, reflect.TypeOf(v))
        if vByte, ok := v.([]byte); ok {
            (*dataMap)[k] = string(vByte)
        }
    }
}
Table of Contents