zoukankan      html  css  js  c++  java
  • 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

    浪漫家园,没事就来逛逛
  • 相关阅读:
    Reactive Extensions (Rx) 入门(5) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(4) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(3) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(2) —— 安装 Reactive Extensions
    Reactive Extensions (Rx) 入门(1) —— Reactive Extensions 概要
    Xamarin NuGet 缓存包导致 already added : Landroid/support/annotation/AnimRes 问题解决方案
    Android 系统Action大全
    Xamarin Forms 实现发送通知点击跳转
    如何理解灰度发布
    推荐一款分布式微服务框架 Surging
  • 原文地址:https://www.cnblogs.com/lovezbs/p/14512340.html
Copyright © 2011-2022 走看看