## 功能扩展库 目录 - 缓存驱动 - 请求上下文 - JWT - 数据字典 - 地理定位(待写) - 通知(待写) ### 缓存驱动 > 系统默认的缓存驱动为file,目前已支持:memory|redis|file等多种驱动。请自行选择适合你的驱动使用。 - 配置文件:server/manifest/config/config.yaml ```yaml #缓存 cache: adapter: "file" # 缓存驱动方式,支持:memory|redis|file,不填默认memory fileDir: "./storage/cache" # 文件缓存路径,adapter=file时必填 ``` #### 使用方式 ```go package main import ( "hotgo/internal/library/cache" "github.com/gogf/gf/v2/os/gctx" ) func test() { ctx := gctx.New() // 添加/修改 cache.Instance().Set(ctx, "qwe", 123, 0) // 查询 cache.Instance().Get(ctx, "qwe") // 删除 cache.Instance().Remove(ctx, "qwe") // 更多方法请参考:https://goframe.org/pages/viewpage.action?pageId=27755640 } ``` ### 请求上下文 - 主要用于在处理HTTP和websocket请求时通过中间件将用户、应用、插件等信息绑定到上下文中,方便在做业务处理时用到这些信息 ```go package admin import ( "fmt" "context" "hotgo/internal/library/contexts" "hotgo/internal/library/addons" ) func test(ctx context.Context) { // 获取当前请求的所有上下文变量 var ctxModel = contexts.Get(ctx) fmt.Printf("当前请求的所有上下文变量:%+v\n", ctxModel) // 获取当前请求的应用模块 var module = contexts.GetModule(ctx) fmt.Printf("当前请求的应用:%+v\n", module) // 获取当前请求的用户信息 var member = contexts.GetUser(ctx) fmt.Printf("当前访问用户信息:%+v\n", member) // 获取当前请求的插件模块 fmt.Printf("当前是否为插件请求:%v", contexts.IsAddonRequest(ctx)) if contexts.IsAddonRequest(ctx) { fmt.Printf("当前插件名称:%v", contexts.GetAddonName(ctx)) fmt.Printf("当前插件信息:%v", addons.GetModule(contexts.GetAddonName(ctx))) } } ``` ### JWT - 基于jwt+缓存驱动实现的用户登录令牌功能,支持自动续约,解决了jwt服务端无法退出问题和jwt令牌无法主动失效问题 #### 配置示例 ```yaml # 登录令牌 token: secretKey: "hotgo123" # 令牌加密秘钥,考虑安全问题生产环境中请修改默认值 expires: 604800 # 令牌有效期,单位:秒。默认7天 autoRefresh: true # 是否开启自动刷新过期时间, false|true 默认为true refreshInterval: 86400 # 刷新间隔,单位:秒。必须小于expires,否则无法触发。默认1天内只允许刷新一次 maxRefreshTimes: 30 # 最大允许刷新次数,-1不限制。默认30次 multiLogin: true # 是否允许多端登录, false|true 默认为true ``` ```go package admin import ( "fmt" "context" "hotgo/internal/library/token" "hotgo/internal/model" ) func test(ctx context.Context) { // 登录 user := &model.Identity{ Id: mb.Id, Pid: mb.Pid, DeptId: mb.DeptId, RoleId: ro.Id, RoleKey: ro.Key, Username: mb.Username, RealName: mb.RealName, Avatar: mb.Avatar, Email: mb.Email, Mobile: mb.Mobile, App: consts.AppAdmin, LoginAt: gtime.Now(), } loginToken, expires, err := token.Login(ctx, user) if err != nil { return nil, err } // gf请求对象 r := *ghttp.Request // 获取登录用户信息 user, err := token.ParseLoginUser(r) if err != nil { return } // 注销登录 err = token.Logout(r) } ``` ### 数据字典 - hotgo增加了对枚举字典和自定义方法字典的内置支持,从而在系统中经常使用的一些特定数据上做出了增强。 #### 字典数据选项 - 文件路径:server/internal/model/dict.go ```go package model // Option 字典数据选项 type Option struct { Key interface{} `json:"key"` Label string `json:"label" description:"字典标签"` Value interface{} `json:"value" description:"字典键值"` ValueType string `json:"valueType" description:"键值数据类型"` Type string `json:"type" description:"字典类型"` ListClass string `json:"listClass" description:"表格回显样式"` } ``` #### 枚举字典 - 适用于系统开发期间内置的枚举数据,这样即维护了枚举值,又关联了数据字典 ##### 一个例子 - 定义枚举值和字典数据选项,并注册字典类型 - 文件路径:server/internal/consts/credit_log.go ```go package consts import ( "hotgo/internal/library/dict" "hotgo/internal/model" ) func init() { dict.RegisterEnums("creditType", "资金变动类型", CreditTypeOptions) dict.RegisterEnums("creditGroup", "资金变动分组", CreditGroupOptions) } const ( CreditTypeBalance = "balance" // 余额 CreditTypeIntegral = "integral" // 积分 ) const ( CreditGroupDecr = "decr" // 扣款 CreditGroupIncr = "incr" // 加款 CreditGroupOpDecr = "op_decr" // 操作扣款 CreditGroupOpIncr = "op_incr" // 操作加款 CreditGroupBalanceRecharge = "balance_recharge" // 余额充值 CreditGroupBalanceRefund = "balance_refund" // 余额退款 CreditGroupApplyCash = "apply_cash" // 申请提现 ) // CreditTypeOptions 变动类型 var CreditTypeOptions = []*model.Option{ dict.GenSuccessOption(CreditTypeBalance, "余额"), dict.GenInfoOption(CreditTypeIntegral, "积分"), } // CreditGroupOptions 变动分组 var CreditGroupOptions = []*model.Option{ dict.GenWarningOption(CreditGroupDecr, "扣款"), dict.GenSuccessOption(CreditGroupIncr, "加款"), dict.GenWarningOption(CreditGroupOpDecr, "操作扣款"), dict.GenSuccessOption(CreditGroupOpIncr, "操作加款"), dict.GenWarningOption(CreditGroupBalanceRefund, "余额退款"), dict.GenSuccessOption(CreditGroupBalanceRecharge, "余额充值"), dict.GenInfoOption(CreditGroupApplyCash, "申请提现"), } ``` #### 自定义方法字典 - 适用于非固定选项,如数据是从某个表/文件读取或从第三方读取,数据需要进行转换时使用 ##### 方法字典接口 - 文件路径:server/internal/consts/credit_log.go ```go package dict // FuncDict 方法字典,实现本接口即可使用内置方法字典 type FuncDict func(ctx context.Context) (res []*model.Option, err error) ``` ##### 一个例子 - 定义获取字典数据方法,并注册字典类型 - 文件路径:server/internal/logic/admin/post.go ```go package admin import ( "context" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "hotgo/internal/consts" "hotgo/internal/dao" "hotgo/internal/library/dict" "hotgo/internal/model" "hotgo/internal/model/entity" "hotgo/internal/service" ) type sAdminPost struct{} func NewAdminPost() *sAdminPost { return &sAdminPost{} } func init() { service.RegisterAdminPost(NewAdminPost()) dict.RegisterFunc("adminPostOption", "岗位选项", service.AdminPost().Option) } // Option 岗位选项 func (s *sAdminPost) Option(ctx context.Context) (opts []*model.Option, err error) { var list []*entity.AdminPost if err = dao.AdminPost.Ctx(ctx).OrderAsc(dao.AdminPost.Columns().Sort).Scan(&list); err != nil { return nil, err } if len(list) == 0 { opts = make([]*model.Option, 0) return } for _, v := range list { opts = append(opts, dict.GenHashOption(v.Id, v.Name)) } return } ``` #### 代码生成支持 - 内置的枚举字典和自定义方法字典在生成代码时可以直接进行选择,生成代码格式和系统字典管理写法一致 ![最终编辑表单效果](images/sys-library-dict.png) #### 内置字典和系统字典的区分 ##### 主要区别 - 系统字典由表:`hg_sys_dict_type`和`hg_sys_dict_data`共同进行维护,使用时需通过后台到字典管理中进行添加 - 内置字典是系统开发期间在代码层面事先定义和注册好的数据选项 ##### 数据格式区别 - 系统字典所有ID都是大于0的int64类型 - 内置字典ID都是小于0的int64类型。枚举字典以20000开头,如:-200001381053496;方法字典以30000开头,如:-30000892528327;开头以外数字是根据数据选项的`key`值进行哈希算法得出 ### 地理定位 ```go // 待写 ``` ### 通知 ```go // 待写 ```