1、背景
model层不允许使用 json, dto层又重复造轮子,一个表的字段可能20个左右,那么赋值语句难受死了。
其次就是json直接解析,model层的time.Time,完蛋格式不对,返回的数据不对。
比如
{
"user_name": "xiaoli",
"create_time": "2020-06-05T13:53:06.293614+08:00"
}
- 1.
- 2.
- 3.
- 4.
这种情况,无法解决,就需要必须重写一个dto。
那么如何解决这个问题呢,本人思考了一段时间,最终使用Map来解决。
2、解决问题
1、反射
那么反射会遇到,各种奇葩的书写方式,有些人什么都出传入指针,有些人各种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
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
解决这个问题,开干
2、下划线命名法
下划线如何解决,结构体的字段属于驼峰命名法,怎么解决呢?
写了一个简单的工具类
问题:
- 如果是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'
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
3、开干
- 解决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
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
4、测试
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)
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
输出结果:
完美,美中不足是需要使用likedMap,由于Golang源码包没有,所以,注定乱序
{"create_time":"2020-06-05 14:05:31","user_name":"xiaoli"}
- 1.