利用gorm的callbacks实现审计字段,如创建、修改订单时自动保存创建人、修改人信息,但又不希望每个结构体中定义SetCreatedBy、SetUpdatedBy方法。开干
Callbacks简单介绍
GORM 自身也是基于 Callbacks
的,包括 Create
、Query
、Update
、Delete
、Row
、Raw
。此外,您也完全可以根据自己的意愿自定义 GORM
回调会注册到全局 *gorm.DB
,而不是会话级别。如果您想要 *gorm.DB
具有不同的回调,您需要初始化另一个 *gorm.DB
详情见gorm官方文档,
编写插件 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.
实现我们自己的callback函数,比如想实现自动审计日志
1、创建一个autoAuditlog方法
func autoAuditLog(db *gorm.DB) {
// 查找schema中是否包含CreatedBy字段
createby := db.Statement.Schema.LookUpField("CreatedBy")
// 如果没有则直接返回
if createby == nil {
return
}
// 登录鉴权后把个人信息存储到当前的Context中然后传递给相关数据库操作方法
// 把Context传递给*gorm.DB.WithContext, 然后就可以获取Context中的账号信息
account := httpctx.GetAccount(db.Statement.Context)
// 获取当前创建Model(表结构体)的反射数据
data := db.Statement.ReflectValue
// 这里需要判断一下是否为Slice, 如果切片则表示批量新增,所以进行for循环赋值
if data.Kind() == reflect.Slice {
for i := 0; i < data.Len(); i++ {
// 获取每个切片元素的所有element
elem := data.Index(i)
// 获取CreatedBy字段
field := elem.FieldByName("CreatedBy")
// 判断是否有效并且是否可以设置
if field.IsValid() && field.CanSet() {
field.SetString(account)
}
}
// 通过return 结束该回调方法
return
}
// 不是切片则直接修改CreatedBy的值
db.Statement.SetColumn("CreatedBy", account)
}
2、在全局*gorm.DB中注册callback,Before表示在数据创建前注册一个autoAuditLog回调
var DbClient *gorm.DB
func ConnectToDB() {
var err error
dsn := "host=localhost user=postgres password=postgre dbname=my_test0910 port=5432 sslmode=disable TimeZone=Asia/Shanghai"
DbClient, err = gorm.Open(postgres.Open(dsn), &gorm.Config{PrepareStmt: true, SkipDefaultTransaction: true})
// 创建前注册autoAuditLog, 每次新增都会进行该回调处理
DbClient.Callback().Create().Before("gorm:before_create").Register("update_create_by", autoAuditLog)
if err != nil {
slog.Error("postges sql connection failed", err)
panic(err)
}
}
至此完成了一个简单创建人的审计字段,大家可根据自己的业务需求实现自己想要的审计日志逻辑,这样即能省略了一大堆重复代码,也增强了代码的可维护性。如果各位大佬有更好的实现方式欢迎留言讨论。。。