這幾天收到一個戰術性需求,將一大坨欄位序列化為特定格式的字串。
大概是下表這樣:
序號 | 欄位名 | 描述 | 是否必填 |
---|---|---|---|
0 | logVersion | 紀錄檔版本 | 是 |
1 | productName | 產品 | 是 |
2 | serviceName | 服務 | 是 |
... | |||
... | |||
... | |||
25 | extend3 | 擴充套件欄位3 | 否 |
26 | extend4 | 擴充套件欄位3 | 否 |
27 | extend5 | 擴充套件欄位3 | 否 |
checklist-client com.CommonApiController uploadImage 2017-12-27 10:35:08 378 1.0 null null 192.168.35.12 EBJ4945 null null ylKLPAvAsoaWRnqGZhZ6xqZ6hkYxSrVKsQDOSOpwXgAAAA== 0 91 null null 0 202226d4-255f-891c-b627-9efc28ef366b 0 010 -1 null null null null null null
控制點1:必填欄位少,若可選欄位無值,該欄位序列化為「null」;
控制點2:序列化時只顯示欄位值(有序),欄位之間用空格區分。
這不就是自定義序列化 且設定序列化預設值?
真要我挨個欄位填充,我眼睛都要對花, 而且很容易漏掉欄位。
// 虛擬碼如下:
b := bytes.Buffer{}
b.WriteString("P1")
b.WriteString(" ")
b.WriteString("null")
b.WriteString(" ")
b.WriteString("null")
b.WriteString(" ")
b.WriteString("A")
...
b.WriteString(" ")
b.WriteString("null")
log.Info(b.String())
根據"必填欄位極少,可選欄位預設設為null字串"的背景,我開始自定義序列化器:
將結構體轉換為 map, 這個行為涉及元型別的變動,聯想到反射。
自古以來,反射也是兵家必爭之地, 於是首次操刀golang的反射特性。
思路和虛擬碼很明確,實操時還是有2點障礙:
關於第一個問題,利用網上的[提取key放在slice裡面,再根據key的排序取map值]的思路是想當然了。
我們的key是字串,sort.Strings()
之後依舊不是自己的預期(預期是按照struct欄位出現的先後順序)。
所以對map做for迴圈時,能拿到與struct欄位出現順序一致的鍵值對就是關鍵。
取巧:
我們利用反射struct時的欄位順序,定義了一個按照struct欄位出現順序為鍵的map[int]string
,
這樣sort.Ints(keys)
排序之後,for map時依舊是我們預期的鍵值對順序。
func constructFixedMap(body interface{}) map[int]string {
typ := reflect.TypeOf(body) //TypeOf返回目標資料型別
val := reflect.ValueOf(body) //ValueOf返回目標資料的的值
if typ.Kind() != reflect.Pointer {
fmt.Println("expect pointer")
return nil
}
typ = typ.Elem() // 返回指標所指向的原值
val = val.Elem()
mp := make(map[int]string, 20)
for i := 0; i < typ.NumField(); i++ {
if typ.Field(i).Type.Kind().String() == "string" {
if val.Field(i).String() == "" { // 可選欄位,在反射時被修改
mp[i] = "null"
} else {
mp[i] = val.Field(i).String() // 必填欄位,保持不變
}
} else {
if val.Field(i).CanInt() {
mp[i] = strconv.FormatInt(val.Field(i).Int(), 10)
} else {
mp[i] = "null"
}
}
}
return mp
}
本文來自部落格園,作者:{有態度的馬甲},轉載請註明原文連結:https://www.cnblogs.com/JulianHuang/p/17437421.html
歡迎關注我的原創技術、職場公眾號, 加好友談天說地,一起進化