Go開發中結構體 model、dto 、time格式問題

一、背景

model層不容許申明json tag, dto層又重複造輪子,一個表的字段可能20個左右,那麼賦值語句難受死了。git

其次就是json直接解析,model層的time.Time,完蛋格式不對,返回的數據不對。json

好比數組

{
    "user_name": "xiaoli",
    "create_time": "2020-06-05T13:53:06.293614+08:00"
}
複製代碼

這種狀況,沒法解決,就須要必須重寫一個dto。安全

那麼如何解決這個問題呢,本人思考了一段時間,最終使用Map來解決。app

二、解決問題

一、反射

那麼反射會遇到,各類奇葩的書寫方式,有些人什麼都出傳入指針,有些人各類interface{} 隱藏轉換,反正就是太過於差別化。工具

因此就是須要解決,如何準確的拿到Value對象,下面是我寫的一個工具類測試

func GetRealValue(value reflect.Value) reflect.Value {
	kind := value.Kind()
	if kind == reflect.Ptr {
		return GetRealValue(value.Elem())
	}
	if kind == reflect.Interface {
		// eg:var s2 interface{}
		// s2 = User{}
		// fmt.Println(reflect.ValueOf(&s2).Elem().Kind())// interface
		// 因此這裏須要將它轉換
		if value.CanInterface() {
			return GetRealValue(reflect.ValueOf(value.Interface()))
		}
		return GetRealValue(value.Elem())
	}
	return value
}
複製代碼

解決這個問題,開幹ui

二、下劃線命名法

下劃線如何解決,結構體的字段屬於駝峯命名法,怎麼解決呢,爲此。spa

寫了一個簡單的工具類指針

問題:一、若是是ID,連續大寫,輸出i_d

二、由於數組到切片須要拷貝一次,因此能夠利用unsafe解決,由於字符串底層就是切片,可是不安全

func CamelCase(s string) string {
	if s == "" {
		return ""
	}
	t := make([]byte, 0, 32)
	i := 0
	for ; i < len(s); i++ {
		c := s[i]
		if isASCIIDigit(c) {
			t = append(t, c)
			continue
		}
		if isASCIIUpper(c) {
			c ^= ' '
		}
		t = append(t, c)
		for i+1 < len(s) && isASCIIUpper(s[i+1]) {
			i++
			t = append(t, '_', s[i]+32)
		}
	}
	//return *(*string)(unsafe.Pointer(&t))
	return string(t)
}
func isASCIIUpper(c byte) bool {
	return 'A' <= c && c <= 'Z'
}

func isASCIIDigit(c byte) bool {
	return '0' <= c && c <= '9'
}
複製代碼

三、開幹

一、解決time的問題

二、反射、下劃線命名法

func ToStdMap(bean interface{}) map[string]interface{} {
	_value := GetRealValue(reflect.ValueOf(bean))
	if _value.Kind() != reflect.Struct {
		panic("the bean mush struct")
	}
	_type := _value.Type()
	fieldNum := _value.NumField()
	_map := make(map[string]interface{}, fieldNum)
	for x := 0; x < fieldNum; x++ {
		field := _type.Field(x)
		value := GetRealValue(_value.Field(x))
		if value.CanInterface() {
			realValue := value.Interface()
			switch realValue.(type) {
			case time.Time:
				_map[CamelCase(field.Name)] = times.FormatStdTime(realValue.(time.Time))
			default:
				_map[CamelCase(field.Name)] = realValue
			}
		}
	}
	return _map
}
複製代碼

四、測試

func TestObjToMap(t *testing.T) {
	users := Users{
		UserName: "xiaoli",
	}
	now := time.Now()
	users.CreateTime = &now
	stdMap := ToStdMap(users)
	bytes, err := json.Marshal(stdMap)
	if err != nil {
		t.Fatal(err)
	}
	fmt.Printf("%s\n", bytes)
}
複製代碼

輸出結果:

完美,美中不足是須要使用likedMap,因爲Golang源碼包沒有,因此😓,註定亂序

{"create_time":"2020-06-05 14:05:31","user_name":"xiaoli"}
複製代碼
相關文章
相關標籤/搜索