网站/小程序/APP个性化定制开发,二开,改版等服务,加扣:8582-36016

model层不允许使用 json, dto层又重复造轮子,一个表的字段可能20个左右,那么赋值语句难受死了。其次就是json直接解析,model层的time.Time,完蛋格式不对,返回的数据不对。


1、背景

model层不允许使用 json, dto层又重复造轮子,一个表的字段可能20个左右,那么赋值语句难受死了。

其次就是json直接解析,model层的time.Time,完蛋格式不对,返回的数据不对。

比如

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

    这种情况,无法解决,就需要必须重写一个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 
    }

      解决这个问题,开干

      2、下划线命名法

      下划线如何解决,结构体的字段属于驼峰命名法,怎么解决呢?

      写了一个简单的工具类

      问题:

      • 如果是ID,连续大写,输出i_d

      • 因为数组到切片需要拷贝一次,所以可以利用unsafe解决,因为字符串底层就是切片,但是不安全

      func CamelCase(s stringstring { 
          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' 
      }

        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 
        }

          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) 
          }

            输出结果:

            完美,美中不足是需要使用likedMap,由于Golang源码包没有,所以,注定乱序

            {"create_time":"2020-06-05 14:05:31","user_name":"xiaoli"}


              评论 0

              暂无评论
              0
              0
              0
              立即
              投稿
              发表
              评论
              返回
              顶部