goframe学习笔记

文章目录

    • 一些命令
    • 开发流程
    • ORM链式操作
      • 时间操作
        • unscoped忽略时间特性
      • Fields/FieldsEx字段过滤
      • OmitEmpty空值过滤
    • 加盐加密
    • 前后台设计目录结构
    • gtoken 优势
    • 文件上传流程
    • 自定义错误
    • 快速导入接口
    • 自动识别转换-Scan转换
    • 数据校验
      • min-length与min的区别
    • 合理复用entity
    • 登录鉴权 context
    • 静态关联的使用
    • ORM事务处理-闭包操作
    • 排错记录


一些命令

  • 热更新运行

    gf run main.go

  • 创建项目模板

    gf init demo -u // 项目名称demo -u使用最新版本

  • 自动生成dao文件

    gf gen dao

开发流程

  1. 设计表结构,初始化项目,修改配置文件

  2. 使用 gf gen dao生成对应的 dao/do/model

  3. 编写api层:定义数据侧数据结构,提供对内的数据处理的输入/输出结构

  4. 编写model层:定义数据侧数据结构,提供对内的数据处理的输入/输出数据结构

  5. 编写logic层,自动生成service层代码。(通过配置goland File Watcher自动生成,也可以通过gf gen service手动执行脚本生成,建议前者)

  6. service层代码生成RegisterXX()方法后,在对应的logic模块注册服务(每个模块只需要写一次)

  7. 编写controller层,接收/解析用户输入的参数,调用service层的服务。

  8. 注册路由,对外暴露接口,比如这个项目是编写cmd.go文件。

  9. main.go中 加入一行 _ "project-name/internal/logic" (只需写一次)

  10. main.go中加入一行 _ "github.com/gogf/gf/contrib/drivers/mysql/v2" (如果你使用的是mysql;只需写一次)

  11. main.go中加入一行_ "github.com/gogf/gf/contrib/nosql/redis/v2"(如果使用redis`;只需写一次)

    其中9、10只需要添加一次; 步骤6每个模块只需要写一次

ORM链式操作

时间操作

gdb模块支持对时间写入、更新、删除的自动填充,若要使用该特性,我们约定:

  • 字段应当设置允许值null
  • 字段的类型必须为时间类型,如date,datetime,timestamp
  • 字段的名称固定:
    • created_at用于记录创建时更新,仅会写入一次
    • updated_at用于记录修改时更新,每次记录变更时更新
    • deleted_at用于记录的软删除特性,只有当记录删除时会写入一次

字段名称其实不区分大小写,也会忽略特殊字符,例如CreatedAt,UpdatedAt,DeletedAt也是支持的。此外,时间字段名称可以通过配置文件进行自定义修改,并可使用TimeMaintainDisabled配置完整关闭该特性。

unscoped忽略时间特性

Unscoped用于在链式操作中忽略自动时间更新特性,例如上面的示例,加上Unscoped方法后:

//SELECT*FROM`user`WHEREuid>1
g.Model("user").Unscoped().Where("uid>?",1).All()

//SELECT*FROM`user`AS`u`LEFTJOIN`user_detail`AS`ud`ON(ud.uid=u.uid)WHEREu.uid=10LIMIT1
g.Model("user","u").LeftJoin("user_detail","ud","ud.uid=u.uid").Where("u.uid",10).Unscoped().One()

当数据表中存在deleted_at字段时,所有涉及到该表的查询操作都将自动加上deleted_at IS NULL的条件

可使用unscoped实现硬删除

dao.RotationInfo.Ctx(ctx).Where(g.Map{
			dao.RotationInfo.Columns().Id: id,
		}).Unscoped().Delete()

Fields/FieldsEx字段过滤

  1. Fields 用于指定需要操作的表字段,包括查询字段、写入字段、更新字段等过滤;
  2. FieldsEx 用于例外的字段指定,可用于查询字段、写入字段、更新字段等过滤;
// SELECT `uid`,`nickname` FROM `user` ORDER BY `uid` asc
g.Model("user").Fields("uid, nickname").Order("uid asc").All()

OmitEmpty空值过滤

map/struct 中存在空值如 nil,"",0 时,默认情况下,gdb将会将其当做正常的输入参数,因此这些参数也会被更新到数据表。OmitEmpty特性可以在将数据写入到数据库之前过滤空值数据的字段。

func (m *Model) OmitEmpty() *Model
func (m *Model) OmitEmptyWhere() *Model
func (m *Model) OmitEmptyData() *Model 

OmitEmpty方法会同时过滤WhereData中的空值数据,而通过OmitEmptyWhere/OmitEmptyData方法可以执行特定的字段过滤。

批量写入/更新操作中OmitEmpty方法将会失效,因为在批量操作中,必须保证每个写入记录的字段是统一的。

加盐加密

加盐加密是一种对系统登录口令的加密方式,它实现的方式是将每一个口令跟一个n位随机数相关联,这个n位随机数叫做”盐“(salt)。

无论何时只要口令改变,随机数就改变。随机数以未加密的方式存放在口令文件中,这样每个人都可以读。不再只保存加密过的口令,而是先将口令和随机数连接起来然后一同加密,加密后的结果放在口令文件中。

前后台设计目录结构

  1. api需要分层,面向需求,灵活多变,要解耦
  2. model不需要分层,面向数据,要内聚
  3. logic和service可以统称为业务逻辑,不需要分层,面向业务,尽量细粒度
  4. controller不需要分层,建议复用文件,通过方法名区分平台(前台项目还是后台项目)
  5. cmd可以复用也可以分层,根据自己需要决定。我们的项目暂时不分层,先带大家跑通整体流程。

gtoken 优势

  • gtoken支撑单点应用使用内存存储,也支持集群使用redis存储;完全适用于企业生产级使用;
  • 有效的避免了jwt服务端无法退出问题;
  • 解决jwt无法作废已颁布的令牌,只能等到令牌过期问题;
  • 通过用户扩展信息存储在服务端,有效规避了jwt携带大量用户扩展信息导致降低传输效率问题;
  • 有效避免jwt需要客户端实现续签功能,增加客户端复杂度;支持服务端自动续期,客户端不需要关心续签逻辑;

文件上传流程

  1. 定义表结构技巧

  2. 整体业务逻辑编写

  3. 上传文件的注意问题

  4. *ghttp.UploadFile的使用、MustGet的使用技巧

  • *ghttp.UploadFile:上传文件类型
  • MustGetMustGet方法与Get类似,也是配置对象中获取配置数据,组装成gvar结构,但是返回参数只有一个:*gvar.Var
  1. 链式操作WhereGTE的使用

    ORM中用于查询条件的gte、gt、lte、lt分别为大于等于、大于、小于等于、小于

  2. 抽取常量文件

  3. gerror.NewCode()自定义错误码和错误信息

自定义错误

  • 自定义错误码和错误信息
gerror.NewCode(gcode.CodeMissingParameter, consts.CodeMissingParameterMsg)
  • 自定义错误信息
gerror.New(consts.CodeMissingParameterMsg)

快速导入接口

goframe支持swagger:http://127.0.0.1:8000/swagger/和api的json格式文件: http://127.0.0.1:8000/api.json

在apipost或postman中可以直接使用url导入,也可下载文件后导入

自动识别转换-Scan转换

该方法可以实现对任意参数到struct/struct数组/map/map数组的转换,并且根据开发者输入的转换目标参数自动识别执行转换。

func main() {
	type User struct {
		Uid  int
		Name string
	}
	params := g.Map{
		"uid":  1,
		"name": "john",
	}
	var user *User
	if err := gconv.Scan(params, &user); err != nil {
		panic(err)
	}
	g.Dump(user)
}

输出:

{
    Uid:  1,
    Name: "john",
}

数据校验

min-length与min的区别

min-length

  • 格式: min-length:min
  • 说明:参数长度最小为min(长度参数为整形),注意底层使用Unicode计算长度,因此中文一个汉字占1个长度单位。

min

  • 格式: min:min
  • 说明:参数大小最小为min(支持整形和浮点类型参数)。

合理复用entity

可以使用entity.XXInfo来复用结构体内的元素

登录鉴权 context

登录成功后保存id:

r.SetCtxVar(consts.CtxAdminId, adminInfo.Id) //r *ghttp.Request

需要使用时取出:

data.UserId = gconv.Int(ctx.Value(consts.CtxAdminId)) //ctx context.Context

静态关联的使用

model层:

type CollectionListOutputItem struct {
	Id        int         `json:"id"        description:""`
	UserId    int         `json:"user_id"    description:"用户id"`
	ObjectId  int         `json:"object_id"  description:"对象id"`
	Type      int         `json:"type"      description:"收藏类型:1商品 2文章"`
	Goods     GoodsItem   `json:"goods" orm:"with:id=object_id"`
	Article   ArticleItem `json:"article" orm:"with:id=object_id"` // 将Article的主键id与ObjectId关联
}

type GoodsItem struct {
	g.Meta `orm:"table:goods_info"`
	Id     uint   `json:"id"`
}

type ArticleItem struct {
	g.Meta `orm:"table:article_info"`
	Id     uint   `json:"id"`
}

logic层:

listModel := dao.CollectionInfo.Ctx(ctx).Page(in.Page, in.Size).
Where(dao.CollectionInfo.Columns().Type, in.Type)

if in.Type == consts.CollectionTypeGoods {
    err = listModel.With(model.GoodsItem{}).Scan(&out.List)
} else if in.Type == consts.CollectionTypeArticle {
    err = listModel.With(model.ArticleItem{}).Scan(&out.List)
} else {
    err = listModel.WithAll().Scan(&out.List)
}

ORM事务处理-闭包操作

为方便安全执行事务操作,ORM组件同样提供了事务的闭包操作,通过Transaction方法实现,该方法定义如下:

func (db DB) Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error)

当给定的闭包方法返回的errornil时,那么闭包执行结束后当前事务自动执行Commit提交操作;否则自动执行Rollback回滚操作。闭包中的context.Context参数为goframe v1.16版本后新增的上下文变量,主要用于链路跟踪传递以及嵌套事务管理。由于上下文变量是嵌套事务管理的重要参数,因此上下文变量通过显示的参数传递定义。

如果闭包内部操作产生panic中断,该事务也将自动进行回滚,以保证操作安全。

排错记录

  1. 报错信息:
# github.com/elastic/go-sysinfo/providers/windows
C:\Users\ilotus\go\pkg\mod\github.com\elastic\[email protected]\providers\windows\process_windows.go:307:14: assignment mismatch: 2 variables but tokenUser.User.Sid.String returns 1 value
C:\Users\ilotus\go\pkg\mod\github.com\elastic\[email protected]\providers\windows\process_windows.go:316:15: assignment mismatch: 2 variables but tokenGroup.PrimaryGroup.String returns 1 value

经过检查发现是版本错误,访问Releases · elastic/go-sysinfo (github.com)在Releases最新版为1.14.2,在go.mod中修改版本

github.com/elastic/go-sysinfo v1.14.2

然后使用go mod tidy下载新版本

  1. 错误代码
userInfo.SecretAnswer == in.SecretAnswer

userInfo.SecretAnswer类型为interface{}

in.SecretAnswer类型为string

不同类型不能做比较

修改为:

gconv.String(userInfo.SecretAnswer) == in.SecretAnswer

你可能感兴趣的:(golang学习,学习,笔记,golang)