前言

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

Gorm 预加载及输出处理(三)- 自定义时间格式的更多相关文章

  1. Gorm 预加载及输出处理(二)- 查询输出处理

    上一篇<Gorm 预加载及输出处理(一)- 预加载应用>中留下的三个问题: 如何自定义输出结构,只输出指定字段? 如何自定义字段名,并去掉空值字段? 如何自定义时间格式? 这一篇先解决前两 ...

  2. Gorm 预加载及输出处理(一)- 预加载应用

    单条关联查询 先创建两个关联模型: // 用户模型 type User struct { gorm.Model Username string `gorm:"type:varchar(20) ...

  3. 闭包,jQuery插件的写法:图片预加载

    最近做的一些网页,单个网页图片量都比较大,网络不好的情况下,特别卡,这个图片预加载的方法可以牺牲一些时间换来网页的浏览顺畅,还是值得的. //闭包的写法,它内部的变量都是局部的,不会和外部巳有的变量进 ...

  4. 图片利用 new Image()预加载原理 和懒加载的实现原理

    二:预加载和懒加载的区别 预加载与懒加载,我们经常经常用到,这些技术不仅仅限于图片加载,我们今天讨论的是图片加载: 图片预加载:顾名思义,图片预加载就是在网页全部加载之前,提前加载图片.当用户需要查看 ...

  5. entity framework 数据加载三种方式的异同(延迟加载,预加载,显示加载)

    三种加载方式的区别 显示加载: 显示加载

  6. gorm 结构体 预加载

    结构体构建 type PlansApproval struct {     ID uint     Plans_Id int //plans编号     UpdateUser int //更新者    ...

  7. viewpager处理(三):让viewpager不预加载下一页

    有时候viewpager加载页面的时候,我们发现页面的数据量很大,预加载的话会消耗性能,为了节省用户流量和手机性能,所以我们想让viewpager不自动预加载下一页,怎么实现呢? viewpager预 ...

  8. AngularJS进阶(三十六)AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记)

    AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记) 前言 在"AngularJS项目开发技巧之图片预加载" ...

  9. AngularJS进阶(三十)AngularJS项目开发技巧之图片预加载

    AngularJS项目开发技巧之图片预加载 绪 项目(移动端采用Ionic 框架)开发完毕,测试阶段发现移动APP首页的广告图片(图片由服务器端返回相应url地址)很难加载,主要原因还是网速.如下图左 ...

随机推荐

  1. ERROR 1176 (42000): Key 'XXX' doesn't exist in table 'XXX'报错处理

    MySQL5.7对sql语句强制使用索引查询时报错如下: 解决:这里的id字段是表的主键,查看别人的经验贴得知是语法错误,参考链接https://stackoverflow.com/questions ...

  2. Blue的博客

    整合其他ORM框架 使用Spring所提供的ORM整合方案, 可以获得许多好处: 方便基础设施的搭建 Spring中, 对不同的ORM框架, 首先, 始终可以采用相同的方式配置数据源; 其次, Spr ...

  3. Alberto Del Bimbo:为什么说研究员要有想象力?

    ​ Del Bimbo:为什么说研究员要有想象力?" title="Alberto Del Bimbo:为什么说研究员要有想象力?"> ​ 说到科研,与日本式的&q ...

  4. USB小白学习之路(12) Cy7c68013A固件之Slave FIFO(转)

    Cy7c68013固件之Slave FIFO 转自:http://blog.csdn.net/zengshaoqing/article/details/53053539 选择SlaveFIFO传输方式 ...

  5. CentOS 7 国内源配置

    CentOS 7 国内源配置 1. 备份自带源 # 首先要确认你有 wget 命令, 并且连着网 # cd /etc/yum.repos.d/ # mkdir repo # mv *.repo rep ...

  6. Enbale IE mode in Edge

    1. 打开Edge, 在地址栏输入 edge://flags/ 2. 搜索 Enable IE Integration , 配置为 IE mode 3. 找到Edge的启动程序路径.如 C:\Prog ...

  7. py基础之模块与包

    '''模块:当代码越来越多时,将所有代码放入一个文件中便会无法维护,所以放到多个文件中去,这样每一个py文件就是一个模块 包:模块越来越多时容易重名,便将模块放入不同的包中,每个包中必须有一个__in ...

  8. proxyTable的配置

    在dev环境下面: proxyTable: { '/api': { target: 'http://api.douban.com/v2', //主域名,以前我都写192.168.2.57:80,这里跨 ...

  9. 零基础HTML及CSS编码总结

    任务目的 针对设计稿样式进行合理的HTML架构,包括以下但不限于: * 掌握常用HTML标签的含义.用法 能够基于设计稿来合理规划HTML文档结构 理解语义化,合理地使用HTML标签来构建页面 掌握基 ...

  10. 讨论一下.NET里,对cookie身份验证的超时的处理

    引言 在.NET里提供了FormsAuthentication类用来对用户身份进行验证和授权.不过,对于cookie的超时处理,一直是一个头疼的问题.这里介绍一下微软对.NET 身份验证超时的处理机制 ...