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

    浪漫家园,没事就来逛逛
  • 相关阅读:
    ajax回调中window.open弹出的窗口会被浏览器拦截的解决方法
    javascript中常见的函数封装 :判断是否是手机,判断是否是微信,获取url地址?后面的具体参数值,毫秒格式化时间,手机端px、rem尺寸转换等
    javascript正则表达式(regular expression)
    基于jquery类库的绘制二维码的插件jquery.qrcode.js
    javascript常见的数组方法
    javascript函数,构造函数。js对象和json的区别。js中this指向问题
    vue中的组件,Component元素,自定义路由,异步数据获取
    vue中自定义指令vue.direvtive,自定义过滤器vue.filter(),vue过渡transition
    vue的表单的简单介绍 input radio checkbox等表单特性
    Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on
  • 原文地址:https://www.cnblogs.com/lovezbs/p/14512340.html
Copyright © 2011-2022 走看看