Модель структуры, dto, проблемы формата времени в разработке Go

Go

1. Предпосылки

Уровень модели не позволяет объявлять теги json, а слой dto повторяет колесо, в таблице может быть около 20 полей, поэтому оператор присваивания неудобен.

Второй — прямой разбор json, время. Время слоя модели имеет неправильный формат, и возвращаемые данные неверны.

Например

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

В этом случае ее решить нельзя, и нужно переписать dto.

Итак, как решить эту проблему, я некоторое время думал об этом и, наконец, использовал Map для ее решения.

2. Решить проблему

1. Отражение

Тогда рефлексия будет сталкиваться с разными странными способами написания, кто-то передает указатели на все подряд, а кто-то скрывает преобразования различных интерфейсов{}, все равно это слишком дифференцировано.

Итак, необходимо решить, как точно получить объект 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, подчеркните метод именования

Как решить подчеркивание, поля конструкции относятся к номенклатуре верблюжьего падежа, как решить, для этого.

Написал простой служебный класс

Вопрос: 1. Если даID, последовательный верхний регистр, выводi_d

2. Поскольку массив в срез нужно скопировать один раз, это можно решить небезопасно, потому что нижний слой строки — это срез, а это небезопасно.

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

3. Открыть и сушить

1. Решить проблему времени

2, отражение, номенклатура подчеркивания

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

Выходной результат:

Отлично, ложкой дегтя является необходимость использования LikeMap, так как в исходном пакете Golang его нет, так что 😓, суждено выйти из строя

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

3. Используйте небезопасно для работы напрямую

Ниже приведены два объекта с одинаковой структурой.Согласно принципу преобразования памяти в unsafe, преобразование из a в b может быть реализовано, только если объект a больше или равен структуре объекта b (требуется расположение быть последовательным)

type UserModel struct { // 数据库对象
	Name     string
	Age      int
	Birthday time.Time
}
type UserDto struct { // 数据传输对象,还要求数据传出的格式是 标准格式
	Name     string `json:"name"`
	Age      int    `json:"age"`
	Birthday Time   `json:"birthday"`
}

type Time time.Time
func (this Time) MarshalText() (text []byte, err error) {
	i := time.Time(this)
	return []byte(i.Format("2006-01-02 15:04:05")), nil
}

код

func BenchmarkName(b *testing.B) {
	for i := 0; i < b.N; i++ {
		model := UserModel{
			Name:     "tom",
			Age:      1,
			Birthday: time.Now(),
		}
		userDao := (*UserDto)(unsafe.Pointer(&model))
		_, _ = json.Marshal(userDao)
		//fmt.Println(string(bytes))
    //// {"name":"tom","age":1,"birthday":"2020-06-26 15:20:20"}
	}
}

Этот код слишком жесток, он преобразует a->b напрямую, и нет необходимости открывать новую память, поэтому этот метод можно использовать, когда a==b.