Gorm 預加載及輸出處理(三)- 自定義時間格式


前言

Gorm 中 time.Time 類型的字段在 JSON 序列化后呈現的格式為 "2020-03-11T18:26:13+08:00",在 Go 標准庫文檔 - time 的 MarshaJSON 方法 下面有這樣一段描述:

MarshalJSON 實現了json.Marshaler 接口。返回值是用雙引號括起來的采用 RFC 3339 格式進行格式化的時間表示,如果需要會提供小於秒的精度。

這個 RFC 3339 格式並不符合日常使用習慣,本文將介紹如何將其轉換成常用的 "yyyy-MM-dd HH:mm:ss" 格式。

思路

在上一篇《Gorm 預加載及輸出處理(二)- 查詢輸出處理》中,采用重寫類型的 MarshaJSON 方法實現了自定義序列化輸出,時間的自定義格式輸出也采用這種方式,大致思路如下:

  1. 創建 time.Time 類型的副本 XTime;
  2. 為 Xtime 重寫 MarshaJSON 方法,在此方法中實現自定義格式的轉換;
  3. 為 Xtime 實現 Value 方法,寫入數據庫時會調用該方法將自定義時間類型轉換並寫入數據庫;
  4. 為 Xtime 實現 Scan 方法,讀取數據庫時會調用該方法將時間數據轉換成自定義時間類型;
  5. 自定義 BaseModel,結構和 gorm.Model 一致,將 time.Time 替換為 Xtime;
  6. 模型定義中使用 BaseModel 替代 gorm.Model;
  7. 模型定義中其他的 time.Time 類型字段也都使用 Xtime 替代。

實現

這里繼續使用前兩篇博文中的 User 模型:

// 用戶模型
type User struct {
    gorm.Model
    Username string    `gorm:"type:varchar(20);not null;unique"`
    Email    string    `gorm:"type:varchar(64);not null;unique"`
    Role     string    `gorm:"type:varchar(32);not null"`
    Active   *uint8    `gorm:"type:tinyint unsigned;default:1"`
    Profile  *Profile  `gorm:"foreignkey:UserID;association_autoupdate:false"`
}

根據上述思路,逐步實現時間的自定義格式輸出,為方便演示,以下代碼均寫在一個文件中,代碼如下:

import (
    "database/sql/driver"
    "fmt"
    "time"
)

// 1. 創建 time.Time 類型的副本 XTime;
type XTime struct {
    time.Time
}

// 2. 為 Xtime 重寫 MarshaJSON 方法,在此方法中實現自定義格式的轉換;
func (t XTime) MarshalJSON() ([]byte, error) {
    output := fmt.Sprintf("\"%s\"", t.Format("2006-01-02 15:04:05"))
    return []byte(output), nil
}

// 3. 為 Xtime 實現 Value 方法,寫入數據庫時會調用該方法將自定義時間類型轉換並寫入數據庫;
func (t XTime) Value() (driver.Value, error) {
    var zeroTime time.Time
    if t.Time.UnixNano() == zeroTime.UnixNano() {
        return nil, nil
    }
    return t.Time, nil
}

// 4. 為 Xtime 實現 Scan 方法,讀取數據庫時會調用該方法將時間數據轉換成自定義時間類型;
func (t *XTime) Scan(v interface{}) error {
    value, ok := v.(time.Time)
    if ok {
        *t = XTime{Time: value}
        return nil
    }
    return fmt.Errorf("can not convert %v to timestamp", v)
}

// 5. 自定義 BaseModel,結構和 gorm.Model 一致,將 time.Time 替換為 Xtime;
type BaseModel struct {
    ID        uint     `gorm:"primary_key"`
    CreatedAt XTime
    UpdatedAt XTime
    DeletedAt *XTime   `sql:"index"`
}

// 6. 模型定義中使用 BaseModel 替代 gorm.Model;
// 用戶模型
type User struct {
    BaseModel
    Username string    `gorm:"type:varchar(20);not null;unique"`
    Email    string    `gorm:"type:varchar(64);not null;unique"`
    Role     string    `gorm:"type:varchar(32);not null"`
    Active   *uint8    `gorm:"type:tinyint unsigned;default:1"`
    Profile  *Profile  `gorm:"foreignkey:UserID;association_autoupdate:false"`
}

// 7. 模型定義中其他的 time.Time 類型字段也都使用 Xtime 替代。
// pass

簡單測試下:

var users []*User

DB.Debug().Find(&users)

JSON 序列化輸出如下:

[
    {
        "ID": 1,
        "CreatedAt": "2020-03-11 18:26:13",
        "UpdatedAt": "2020-03-11 19:00:00",
        "DeletedAt": null,
        "Username": "test",
        "Email": "aaa@bbb.com",
        "Role": "admin",
        "Active": 1,
        "Profile": null
    },
    {
        "ID": 2,
        "CreatedAt": "2020-03-11 19:46:21",
        "UpdatedAt": "2020-03-11 19:46:21",
        "DeletedAt": null,
        "Username": "test2",
        "Email": "bbb@ccc.com",
        "Role": "admin",
        "Active": 1,
        "Profile": null
    }
]

小結

其實只要理解了 go 的 JSON 序列化過程,就可以較為輕松地實現數據的自定義序列化。為需要自定義序列化的類型創建副本,重寫 MarshalJSON 方法並在其中實現數據轉換邏輯,基本就完事了。但也要注意是否需要為副本實現其他特定方法以保證其正常工作,例如,本文自定義時間類型 XTime 就需要實現 Value 和 Scan 方法,否則無法正常工作。

Gorm 自定義時間格式就介紹到這里,如發現任何問題,歡迎指正,謝謝觀看!


本文出處:https://www.cnblogs.com/zhenfengxun/
本文鏈接:https://www.cnblogs.com/zhenfengxun/p/12548305.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM