diff --git a/docs/guide-zh-CN/addon-flow.md b/docs/guide-zh-CN/addon-flow.md
index 35650e4..209cc56 100644
--- a/docs/guide-zh-CN/addon-flow.md
+++ b/docs/guide-zh-CN/addon-flow.md
@@ -14,7 +14,7 @@
1、HotGo 后台进入 开发工具->插件管理->找到创建新插件,根据引导进行创建即可。
-```
+```shell
创建成功后默认情况下会在以下目录中生成插件文件,假设新生成的插件名为:hgexample
1. /server/addons/hgexample/ # 插件模块目录
@@ -29,7 +29,7 @@
2、创建插件完毕重启服务端后,插件管理中会出现你新创建的插件信息。操作栏有几个按钮,在此进行说明
- 安装:会自动执行 server/hgexample/main.go 文件中的Install方法,方法中的具体逻辑默认为空,可以根据实际情况自行配置。如生成后台菜单、生成插件配置表初始化数据、迁移home页面、web项目文件等。
-```
+```go
// Install 安装模块
func (m *module) Install(ctx context.Context) (err error) {
// ...
@@ -38,7 +38,7 @@ func (m *module) Install(ctx context.Context) (err error) {
```
- 更新:会自动执行 server/hgexample/main.go 文件中的Upgrade方法,方法中的具体逻辑默认为空,可以根据实际情况自行配置。
-```
+```go
// Upgrade 更新模块
func (m *module) Upgrade(ctx context.Context) (err error) {
// ...
@@ -47,7 +47,7 @@ func (m *module) Upgrade(ctx context.Context) (err error) {
```
- 卸载:会自动执行 server/hgexample/main.go 文件中的UnInstall方法,方法中的具体逻辑默认为空,可以根据实际情况自行配置。如会清除所有的数据表和已安装的信息等。
-```
+```go
// UnInstall 卸载模块
func (m *module) UnInstall(ctx context.Context) (err error) {
// ...
diff --git a/docs/guide-zh-CN/addon-helper.md b/docs/guide-zh-CN/addon-helper.md
index 2ae1465..57d4d56 100644
--- a/docs/guide-zh-CN/addon-helper.md
+++ b/docs/guide-zh-CN/addon-helper.md
@@ -9,6 +9,7 @@
#### 模块结构
- 文件路径:server/internal/library/addons/module.go
+
```go
// Skeleton 模块骨架
type Skeleton struct {
@@ -43,6 +44,7 @@ type Module interface {
#### 获取模块信息
- 在插件模块内
+
```go
package main
@@ -57,6 +59,7 @@ func test() {
```
- 在插件模块外
+
```go
package main
diff --git a/docs/guide-zh-CN/start-installation.md b/docs/guide-zh-CN/start-installation.md
index ab69804..11f5936 100644
--- a/docs/guide-zh-CN/start-installation.md
+++ b/docs/guide-zh-CN/start-installation.md
@@ -69,7 +69,7 @@ gfcli:
三、 启动服务
1、服务端:
-```shell script
+```shell
cd server
# 设置国内代理,如果已经设置好了代理可以跳过
@@ -86,7 +86,7 @@ gfcli:
```
2、web前端:
-```shell script
+```shell
cd web
# 首先确定你以安装node16.0以上版本并安装了包[npm、pnpm],否则可能会出现一些未知报错
diff --git a/docs/guide-zh-CN/sys-db.md b/docs/guide-zh-CN/sys-db.md
index 369a132..64a70ef 100644
--- a/docs/guide-zh-CN/sys-db.md
+++ b/docs/guide-zh-CN/sys-db.md
@@ -1,149 +1,150 @@
-## 数据库
-
-目录
-
-- 字段类型
-- 特殊字段默认表单组件
-- 特殊字段默认表单验证器
-- SQL默认查询方式
-- 其他
-
-### 字段类型
-
-- 创建数据库表当按如下的规则进行字段命名、类型、属性设置和备注后,再生成CRUD代码时会自动生成对应的Api、控制器、业务逻辑、Web页面、[表单组件](web-form.md)等的一些默认属性
-- 当你了解这些默认技巧后,会有效提高你在实际开发中的生产效率
-
-| 数据库类型 | 额外属性 | 转换Go类型 | 转换Ts类型 | 表单组件 |
-|---------------------------------------------------------------|--------------|--------------|---------|-----------------------|
-| int, tinyint,small_int,smallint,medium_int,mediumint,serial | / | int | number | InputNumber(数字输入框) |
-| int, tinyint,small_int,smallint,medium_int,mediumint,serial | unsigned | uint | number | InputNumber(数字输入框) |
-| big_int,bigint,bigserial | / | int64 | number | InputNumber(数字输入框) |
-| big_int,bigint,bigserial | unsigned | uint64 | number | InputNumber(数字输入框) |
-| real | / | float32 | number | InputNumber(数字输入框) |
-| float,double,decimal,money,numeric,smallmoney | / | float64 | number | InputNumber(数字输入框) |
-| bit(1) 、bit(true)、bit(false) | / | bool | boolean | Input(文本输入框,默认) |
-| bit | / | int64-bytes | array | InputDynamic(动态KV表单) |
-| bit | unsigned | uint64-bytes | array | InputDynamic (动态KV表单) |
-| bool | / | bool | boolean | Input(文本输入框,默认) |
-| date | / | *gtime.Time | string | Date(日期选择器) |
-| datetime,timestamp,timestamptz | / | *gtime.Time | string | Time(时间选择器) |
-| json | / | *gjson.Json | string | Input(文本输入框) |
-| jsonb | / | *gjson.Json | string | Input(文本输入框) |
-| 以下为物理类型中包含字段部分时的转换方式,默认情况 | / | / | / | / |
-| text,char,character | / | string | string | Input(文本输入框) |
-| float,double,numeric | / | string | string | Input(文本输入框) |
-| bool | / | bool | boolean | Input(文本输入框,默认) |
-| binary,blob | / | []byte | string | Input(文本输入框,默认) |
-| int | / | int | number | InputNumber(数字输入框) |
-| int | unsigned | int | number | InputNumber(数字输入框) |
-| time | / | *gtime.Time | string | Time(时间选择器) |
-| date | / | *gtime.Time | string | Date(日期选择器) |
-| 没有满足以上任何条件的 | / | string | string | Input(文本输入框) |
-
-
-### 特殊字段默认表单组件
-- 以下字段在不设置表单组件时会默认使用的表单组件
-
-| 数据库字段 | 字段名称 | 表单组件 |
-|--------------|----------------------|----------------------|
-| status | 状态字段(任意int类型) | Select (单选下拉框) |
-| created_at | 创建时间字段 | TimeRange (时间范围选择) |
-| province_id | 省份ID字段(任意int类型) | CitySelector (省市区选择) |
-| city_id | 城市ID字段(任意int类型) | CitySelector (省市区选择) |
-| 任意字串符字段 | 长度>= 200 and <= 500 | InputTextarea (文本域) |
-| 任意字串符字段 | 长度> 500 | InputEditor (富文本) |
-
-
-### 特殊字段默认表单验证器
-- 以下字段在不设置表单组件时会默认使用的表单验证器
-
-| 数据库字段/Go类型 | 字段名称 | 表单验证规则 |
-|-------------------|--------|-----------------------|
-| mobile | 手机号 | 不为空时必须是手机号码(国内) |
-| qq | QQ | 不为空时必须是QQ号码 |
-| email | 邮箱地址 | 不为空时必须是邮箱格式 |
-| id_card | 身份证号码 | 不为空时必须是15或18位身份证号码 |
-| bank_card | 银行卡号码 | 银行卡号码 |
-| password | 密码 | 密码验证,必须包含6-18为字母和数字 |
-| price | 价格 | 金额验证,最多允许输入10位整数及2位小数 |
-| Go类型为uint、uint64 | 正整数 | 非零正整数验证 |
-
-### SQL默认查询方式
-- Go类型取决于数据库物理类型,请参考 [字段类型] 部分
-
-| Go类型 | 查询方式 |
-|-------------------------|--------------------------------------|
-| string | LIKE |
-| date,datetime | = |
-| int,uint,int64,uint64 | = |
-| []int,[]int64,[]uint64 | IN (...) |
-| float32,float64 | = |
-| []byte4 | =(默认) |
-| time.Time,*gtime.Time | = |
-| *gjson.Json | JSON_CONTAINS(json_doc, val[, path]) |
-
-
-
-### 其他
-
-#### 默认字典选项
-
-- 数据库字段为 `status`且类型为任意数字类型的会使用系统默认的状态字典
-
-#### 默认属性
-
-- 默认必填,当数据库字段存在非空`IS_NULLABLE`属性时,默认勾选必填验证
-- 默认唯一,当数据库字段索引存在`UNI`时,默认勾选唯一值验证
-- 默认主键,当数据库字段索引存在`PRI`时,默认为主键,不允许编辑
-- 默认排序,当数据库字段存在`sort`时,默认开启排序,添加表单自动获取最大排序增量值并填充表单
-- 默认列名,默认使用字段注释作为表格的列名。当数据库字段未设置注释时,默认使用字段名称作为列名
-
-#### 自动更新/插入
-
-- 自动更新,当数据库字段为`updated_at`(更新时间),`updated_by`(更新者)
-- 自动插入,当数据库字段为`created_at`(创建时间),`created_by`(创建者)
-- 软删除,表存在字段`deleted_at`时,使用表的Orm模型查询条件将会自动加入[ `deleted_at` IS NULL ],删除时只更新删除时间而不会真的删除数据
-- 树表:不论更新插入,都会根据表中字段`pid`(上级ID)自动维护`level`(树等级)和`tree`(关系树)
-
-
-#### 操作人字段维护
-
-- 生成列表中存在并且勾选展示字段`created_by`(创建者)、`updated_by`(修改者)、`deleted_by`(删除者)时,会自动到表`hg_admin_member`中获取操作人的基本信息摘要,并渲染到列表中,效果如下:
-
-
-
-- 生成列表中存在并且勾选查询字段`created_by`(创建者)、`updated_by`(修改者)、`deleted_by`(删除者)时,会强制将查询表单改为关键词查询,从`hg_admin_member`查询操作人。效果如下:
-
-
-
-- 查询代码片段,参考路径:[server/internal/logic/admin/member.go](../../server/internal/logic/admin/member.go)
-```go
-
-// 查询创建者
-if in.CreatedBy != "" {
- ids, err := service.AdminMember().GetIdsByKeyword(ctx, in.CreatedBy)
- if err != nil {
- return nil, 0, err
- }
- mod = mod.WhereIn(dao.SysGenCurdDemo.Columns().CreatedBy, ids)
-}
-
-// GetIdsByKeyword 根据关键词查找符合条件的用户ID
-func (s *sAdminMember) GetIdsByKeyword(ctx context.Context, ks string) (res []int64, err error) {
- ks = gstr.Trim(ks)
- if len(ks) == 0 {
- return
- }
- array, err := dao.AdminMember.Ctx(ctx).Fields("id").
- Where("`id` = ? or `real_name` = ? or `username` = ? or `mobile` = ?", ks, ks, ks, ks).
- Array()
- if err != nil {
- err = gerror.Wrap(err, "根据关键词获取用户ID失败,请稍后重试!")
- }
- res = gvar.New(array).Int64s()
- return
-}
-```
-
-
-> 这里只列举了较为常用的默认规则,其他更多默认规则请参考:[server/internal/library/hggen/views/column_default.go](../../server/internal/library/hggen/views/column_default.go)
+## 数据库
+
+目录
+
+- 字段类型
+- 特殊字段默认表单组件
+- 特殊字段默认表单验证器
+- SQL默认查询方式
+- 其他
+
+### 字段类型
+
+- 创建数据库表当按如下的规则进行字段命名、类型、属性设置和备注后,再生成CRUD代码时会自动生成对应的Api、控制器、业务逻辑、Web页面、[表单组件](web-form.md)等的一些默认属性
+- 当你了解这些默认技巧后,会有效提高你在实际开发中的生产效率
+
+| 数据库类型 | 额外属性 | 转换Go类型 | 转换Ts类型 | 表单组件 |
+|---------------------------------------------------------------|--------------|--------------|---------|-----------------------|
+| int, tinyint,small_int,smallint,medium_int,mediumint,serial | / | int | number | InputNumber(数字输入框) |
+| int, tinyint,small_int,smallint,medium_int,mediumint,serial | unsigned | uint | number | InputNumber(数字输入框) |
+| big_int,bigint,bigserial | / | int64 | number | InputNumber(数字输入框) |
+| big_int,bigint,bigserial | unsigned | uint64 | number | InputNumber(数字输入框) |
+| real | / | float32 | number | InputNumber(数字输入框) |
+| float,double,decimal,money,numeric,smallmoney | / | float64 | number | InputNumber(数字输入框) |
+| bit(1) 、bit(true)、bit(false) | / | bool | boolean | Input(文本输入框,默认) |
+| bit | / | int64-bytes | array | InputDynamic(动态KV表单) |
+| bit | unsigned | uint64-bytes | array | InputDynamic (动态KV表单) |
+| bool | / | bool | boolean | Input(文本输入框,默认) |
+| date | / | *gtime.Time | string | Date(日期选择器) |
+| datetime,timestamp,timestamptz | / | *gtime.Time | string | Time(时间选择器) |
+| json | / | *gjson.Json | string | Input(文本输入框) |
+| jsonb | / | *gjson.Json | string | Input(文本输入框) |
+| 以下为物理类型中包含字段部分时的转换方式,默认情况 | / | / | / | / |
+| text,char,character | / | string | string | Input(文本输入框) |
+| float,double,numeric | / | string | string | Input(文本输入框) |
+| bool | / | bool | boolean | Input(文本输入框,默认) |
+| binary,blob | / | []byte | string | Input(文本输入框,默认) |
+| int | / | int | number | InputNumber(数字输入框) |
+| int | unsigned | int | number | InputNumber(数字输入框) |
+| time | / | *gtime.Time | string | Time(时间选择器) |
+| date | / | *gtime.Time | string | Date(日期选择器) |
+| 没有满足以上任何条件的 | / | string | string | Input(文本输入框) |
+
+
+### 特殊字段默认表单组件
+- 以下字段在不设置表单组件时会默认使用的表单组件
+
+| 数据库字段 | 字段名称 | 表单组件 |
+|--------------|----------------------|----------------------|
+| status | 状态字段(任意int类型) | Select (单选下拉框) |
+| created_at | 创建时间字段 | TimeRange (时间范围选择) |
+| province_id | 省份ID字段(任意int类型) | CitySelector (省市区选择) |
+| city_id | 城市ID字段(任意int类型) | CitySelector (省市区选择) |
+| 任意字串符字段 | 长度>= 200 and <= 500 | InputTextarea (文本域) |
+| 任意字串符字段 | 长度> 500 | InputEditor (富文本) |
+
+
+### 特殊字段默认表单验证器
+- 以下字段在不设置表单组件时会默认使用的表单验证器
+
+| 数据库字段/Go类型 | 字段名称 | 表单验证规则 |
+|-------------------|--------|-----------------------|
+| mobile | 手机号 | 不为空时必须是手机号码(国内) |
+| qq | QQ | 不为空时必须是QQ号码 |
+| email | 邮箱地址 | 不为空时必须是邮箱格式 |
+| id_card | 身份证号码 | 不为空时必须是15或18位身份证号码 |
+| bank_card | 银行卡号码 | 银行卡号码 |
+| password | 密码 | 密码验证,必须包含6-18为字母和数字 |
+| price | 价格 | 金额验证,最多允许输入10位整数及2位小数 |
+| Go类型为uint、uint64 | 正整数 | 非零正整数验证 |
+
+### SQL默认查询方式
+- Go类型取决于数据库物理类型,请参考 [字段类型] 部分
+
+| Go类型 | 查询方式 |
+|-------------------------|--------------------------------------|
+| string | LIKE |
+| date,datetime | = |
+| int,uint,int64,uint64 | = |
+| []int,[]int64,[]uint64 | IN (...) |
+| float32,float64 | = |
+| []byte4 | =(默认) |
+| time.Time,*gtime.Time | = |
+| *gjson.Json | JSON_CONTAINS(json_doc, val[, path]) |
+
+
+
+### 其他
+
+#### 默认字典选项
+
+- 数据库字段为 `status`且类型为任意数字类型的会使用系统默认的状态字典
+
+#### 默认属性
+
+- 默认必填,当数据库字段存在非空`IS_NULLABLE`属性时,默认勾选必填验证
+- 默认唯一,当数据库字段索引存在`UNI`时,默认勾选唯一值验证
+- 默认主键,当数据库字段索引存在`PRI`时,默认为主键,不允许编辑
+- 默认排序,当数据库字段存在`sort`时,默认开启排序,添加表单自动获取最大排序增量值并填充表单
+- 默认列名,默认使用字段注释作为表格的列名。当数据库字段未设置注释时,默认使用字段名称作为列名
+
+#### 自动更新/插入
+
+- 自动更新,当数据库字段为`updated_at`(更新时间),`updated_by`(更新者)
+- 自动插入,当数据库字段为`created_at`(创建时间),`created_by`(创建者)
+- 软删除,表存在字段`deleted_at`时,使用表的Orm模型查询条件将会自动加入[ `deleted_at` IS NULL ],删除时只更新删除时间而不会真的删除数据
+- 树表:不论更新插入,都会根据表中字段`pid`(上级ID)自动维护`level`(树等级)和`tree`(关系树)
+
+
+#### 操作人字段维护
+
+- 生成列表中存在并且勾选展示字段`created_by`(创建者)、`updated_by`(修改者)、`deleted_by`(删除者)时,会自动到表`hg_admin_member`中获取操作人的基本信息摘要,并渲染到列表中,效果如下:
+
+
+
+- 生成列表中存在并且勾选查询字段`created_by`(创建者)、`updated_by`(修改者)、`deleted_by`(删除者)时,会强制将查询表单改为关键词查询,从`hg_admin_member`查询操作人。效果如下:
+
+
+
+- 查询代码片段,参考路径:[server/internal/logic/admin/member.go](../../server/internal/logic/admin/member.go)
+
+```go
+
+// 查询创建者
+if in.CreatedBy != "" {
+ ids, err := service.AdminMember().GetIdsByKeyword(ctx, in.CreatedBy)
+ if err != nil {
+ return nil, 0, err
+ }
+ mod = mod.WhereIn(dao.SysGenCurdDemo.Columns().CreatedBy, ids)
+}
+
+// GetIdsByKeyword 根据关键词查找符合条件的用户ID
+func (s *sAdminMember) GetIdsByKeyword(ctx context.Context, ks string) (res []int64, err error) {
+ ks = gstr.Trim(ks)
+ if len(ks) == 0 {
+ return
+ }
+ array, err := dao.AdminMember.Ctx(ctx).Fields("id").
+ Where("`id` = ? or `real_name` = ? or `username` = ? or `mobile` = ?", ks, ks, ks, ks).
+ Array()
+ if err != nil {
+ err = gerror.Wrap(err, "根据关键词获取用户ID失败,请稍后重试!")
+ }
+ res = gvar.New(array).Int64s()
+ return
+}
+```
+
+
+> 这里只列举了较为常用的默认规则,其他更多默认规则请参考:[server/internal/library/hggen/views/column_default.go](../../server/internal/library/hggen/views/column_default.go)
diff --git a/docs/guide-zh-CN/sys-exploit.md b/docs/guide-zh-CN/sys-exploit.md
index 76b1fbe..70fb37b 100644
--- a/docs/guide-zh-CN/sys-exploit.md
+++ b/docs/guide-zh-CN/sys-exploit.md
@@ -63,16 +63,17 @@
#### import
* 单行import不建议用圆括号包裹
* 按照`官方包`,NEW LINE,`当前工程包`,NEW LINE,`第三方依赖包`顺序引入
- ```go
- import (
- "context"
- "string"
-
- "greet/user/internal/config"
-
- "google.golang.org/grpc"
- )
- ```
+
+```go
+import (
+ "context"
+ "string"
+
+ "greet/user/internal/config"
+
+ "google.golang.org/grpc"
+)
+```
#### 函数返回
* 对象避免非指针返回
@@ -84,7 +85,8 @@
#### 函数体编码
* 建议一个block结束空一行,如if、for等
- ```go
+
+```go
func main (){
if x==1{
// do something
@@ -92,15 +94,16 @@
fmt.println("xxx")
}
- ```
+```
* return前尽可能空一行
- ```go
- func getUser(id string)(string,error){
- ....
-
- return "xx",nil
- }
- ```
+
+```go
+func getUser(id string)(string,error){
+ ....
+
+ return "xx",nil
+}
+```
### 框架规范
diff --git a/docs/guide-zh-CN/sys-library.md b/docs/guide-zh-CN/sys-library.md
index 99471c1..25255d9 100644
--- a/docs/guide-zh-CN/sys-library.md
+++ b/docs/guide-zh-CN/sys-library.md
@@ -1,316 +1,318 @@
-## 功能扩展库
-
-目录
-
-- 缓存驱动
-- 请求上下文
-- 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
-}
-```
-
-#### 代码生成支持
-- 内置的枚举字典和自定义方法字典在生成代码时可以直接进行选择,生成代码格式和系统字典管理写法一致
-
-
-
-
-#### 内置字典和系统字典的区分
-
-##### 主要区别
-- 系统字典由表:`hg_sys_dict_type`和`hg_sys_dict_data`共同进行维护,使用时需通过后台到字典管理中进行添加
-- 内置字典是系统开发期间在代码层面事先定义和注册好的数据选项
-
-
-##### 数据格式区别
-- 系统字典所有ID都是大于0的int64类型
-- 内置字典ID都是小于0的int64类型。枚举字典以20000开头,如:-200001381053496;方法字典以30000开头,如:-30000892528327;开头以外数字是根据数据选项的`key`值进行哈希算法得出
-
-### 地理定位
-```go
-// 待写
-```
-
-### 通知
-```go
-// 待写
+## 功能扩展库
+
+目录
+
+- 缓存驱动
+- 请求上下文
+- 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
+}
+```
+
+#### 代码生成支持
+- 内置的枚举字典和自定义方法字典在生成代码时可以直接进行选择,生成代码格式和系统字典管理写法一致
+
+
+
+
+#### 内置字典和系统字典的区分
+
+##### 主要区别
+- 系统字典由表:`hg_sys_dict_type`和`hg_sys_dict_data`共同进行维护,使用时需通过后台到字典管理中进行添加
+- 内置字典是系统开发期间在代码层面事先定义和注册好的数据选项
+
+
+##### 数据格式区别
+- 系统字典所有ID都是大于0的int64类型
+- 内置字典ID都是小于0的int64类型。枚举字典以20000开头,如:-200001381053496;方法字典以30000开头,如:-30000892528327;开头以外数字是根据数据选项的`key`值进行哈希算法得出
+
+### 地理定位
+```go
+// 待写
+```
+
+### 通知
+```go
+// 待写
```
\ No newline at end of file
diff --git a/docs/guide-zh-CN/sys-middleware.md b/docs/guide-zh-CN/sys-middleware.md
index 4546cb7..70f334a 100644
--- a/docs/guide-zh-CN/sys-middleware.md
+++ b/docs/guide-zh-CN/sys-middleware.md
@@ -1,249 +1,250 @@
-## 中间件/拦截器
-
-目录
-
-- 介绍
-- 全局中间件
-- 鉴权中间件
-- 响应中间件
-- 更多
-
-### 介绍
-- 在hotgo中,中间件/拦截器主要作用于web请求的上下文预设、跨域请求处理、鉴权处理、请求拦截和请求结束后统一响应处理等。
-
-
-### 全局中间件
-```go
-package main
-
-import (
- "hotgo/internal/service"
-)
-
-func main() {
-
- // 初始化请求上下文,一般需要第一个进行加载,后续中间件存在依赖关系
- service.Middleware().Ctx()
-
- // 跨域中间件,自动处理跨域问题
- service.Middleware().CORS()
-
- // IP黑名单中间件,如果请求IP被后台拉黑,所有请求将被拒绝
- service.Middleware().Blacklist()
-
- // 演示系統操作限制,当开启演示模式时,所有POST请求将被拒绝
- service.Middleware().DemoLimit()
-
- // 请求输入预处理,api使用gf规范路由并且XxxReq结构体实现了validate.Filter接口即可隐式预处理
- service.Middleware().PreFilter()
-
- // HTTP响应预处理,在业务处理完成后,对响应结果进行格式化和错误过滤,将处理后的数据发送给请求方
- service.Middleware().ResponseHandler()
-
-}
-
-```
-### 鉴权中间件
-```go
-package main
-
-import (
- "github.com/gogf/gf/v2/frame/g"
-)
-
-func main() {
-
- // 在鉴权中间件下的路由如果没有通过权限验证,后续请求将被拒绝
- // 在hotgo中,鉴权中间件一般是配合一个业务模块下的路由组进行使用
- // 目前admin、api、home、websocket模块都已接入
- // 如果你需要创建一个新的模块也需要用到鉴权中间件,可以参考:server/internal/logic/middleware/admin_auth.go
-
-
- // 一个简单例子
- s := g.Server()
- s.Group("/api", func(group *ghttp.RouterGroup) {
- group.Middleware(service.Middleware().ApiAuth)
- group.Bind(
- member.Member, // 管理员
- )
- })
-
-}
-
-```
-
-### 响应中间件
-- 文件路径:server/internal/logic/middleware/response.go
-
-
-#### 常用响应类型
-
-- hotgo为一些常用的响应类型做了统一格式封装,例如:`application/json`、`text/xml`、`text/html`、`text/event-stream`等,默认使用`application/json`。
-- 下面我们以`text/xml`为例简单演示几种使用方法:
-
-1. 当你使用规范化路由时,可直接在XxxRes结构体的`g.Meta`中声明响应类型:
-```go
-type HelloReq struct {
- g.Meta `path:"/hello" tags:"Hello" method:"get" summary:"You first hello api"`
- Name string `json:"name" d:"hotgo" dc:"名字"`
-}
-
-type HelloRes struct {
- g.Meta `mime:"text/xml" type:"string"`
- Tips string `json:"tips"`
-}
-```
-
-2. 在响应前设置响应头:
-```go
-var (
- Hello = cHello{}
-)
-
-type cHello struct{}
-
-func (c *cHello) Hello(ctx context.Context, req *user.HelloReq) (res *user.HelloRes, err error) {
- r := ghttp.RequestFromCtx(ctx)
- r.Response.Header().Set("Content-Type", "text/xml")
-
- res = &user.HelloRes{
- Tips: fmt.Sprintf("hello %v, this is the api for %v applications.", req.Name, simple.AppName(ctx)),
- }
- return
-}
-```
-
-- 浏览器中访问响应内容如下:
-
-
-
-
-#### 自定义响应
-- 在实际开发中,可能需要使用自定义的响应类型,由于响应中间件是全局的,因此您需要对其进行单独处理。
-- 推荐以下几种处理方案,可做参考:
-1. 使用`ghttp.ExitAll()`,需要注意的是此方法会终止后续所有的http处理
-
-```go
-package main
-
-import (
- "github.com/gogf/gf/v2/net/ghttp"
-)
-
-func main() {
- r := new(ghttp.Request) // 当前请求对象
-
- // 清空响应
- r.Response.ClearBuffer()
-
- // 写入响应
- r.Response.Write("自定义响应内容")
-
- // 终止后续http处理
- r.ExitAll()
-}
-```
-
-2. 在`server/internal/logic/middleware/response.go`中根据请求的独有特征进行单独的处理,兼容后续http处理。
-
-
-#### 重写响应错误提示
-
-- 在实际开发中,我们可能想要隐藏一些敏感错误,返回给客户端友好的错误提示,但开发者同时又想需要看到真实的敏感错误。对此hotgo已经进行了过滤处理,下面是一个简单的例子:
-
-```go
-package main
-
-import (
- "github.com/gogf/gf/v2/errors/gerror"
-)
-
-func test() error {
- err = gerror.New("这是一个sql执行错误")
- err = gerror.Wrap(err, "用户创建失败,请稍后重试!~")
- return err
-}
-```
-
-- 开启debug时的客户端响应:
-```json
-{
- "code": -1,
- "message": "用户创建失败,请稍后重试!~",
- "error": [
- "1. 用户创建失败,请稍后重试!~",
- " 1). hotgo/internal/logic/admin.(*sAdminMember).List",
- " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526",
- "2. 这是一个sql执行错误", " 1). hotgo/internal/logic/admin.(*sAdminMember).List",
- " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:525",
- " 2). hotgo/internal/controller/admin/admin.(*cMember).List",
- " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/controller/admin/admin/member.go:157", ""
- ],
- "timestamp": 1684145107,
- "traceID": "084022730d495f17f19e550140f3e1a8"
-}
-```
-
-- 关闭debug时的客户端响应:
-```json
-{
- "code": -1,
- "message": "用户创建失败,请稍后重试!~",
- "timestamp": 1684145107,
- "traceID": "084022730d495f17f19e550140f3e1a8"
-}
-```
-
-- 控制台的输出日志:
-```shell
-2023-05-15 18:05:07.776 {084022730d495f17f19e550140f3e1a8} 200 "GET http localhost:8000 /admin/member/list?page=1&pageSize=10&roleId=-1 HTTP/1.1" 0.002, 127.0.0.1, "http://192.168.0.207:8001/login", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Co
-re/1.94.197.400 QQBrowser/11.7.5287.400", -1, "", ""
-Stack:
-1. 用户创建失败,请稍后重试!~
- 1). hotgo/internal/logic/admin.(*sAdminMember).List
- E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526
-2. 这是一个sql执行错误
- 1). hotgo/internal/logic/admin.(*sAdminMember).List
- E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/response.go:24
- 13). hotgo/internal/logic/middleware.(*sMiddleware).DemoLimit
- E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:90
-
-```
-
-- 如果你开启了访问日志,那么日志记录中会详细记录本次请求的相关信息,内容如下:
-
-
-
-#### 重写错误码
-- hotgo默认使用了gf内置的错误码进行业务处理,通常情况下成功状态码为`0`,失败状态码为`-1`
-- 查看gf内置错误码:https://goframe.org/pages/viewpage.action?pageId=30739587
-- 以下是自定义错误码的简单例子:
-
-```go
-package main
-
-import (
- "github.com/gogf/gf/v2/errors/gerror"
-)
-
-func test() error {
- // 使用自定义状态码30001响应客户端
- err = gerror.NewCode(gcode.New(30001, "用户创建失败,请稍后重试!~", nil))
- return err
-}
-```
-
-
-- 客户端响应如下:
-```json
-{
- "code": 30001,
- "message": "用户创建失败,请稍后重试!~",
- "timestamp": 1684146313,
- "traceID": "b4f90e16264a5f17cd3fc27141aba448"
-}
-```
-
-### 更多
-- 更多关于中间件/拦截器的介绍请参考:https://goframe.org/pages/viewpage.action?pageId=55289881
-
+## 中间件/拦截器
+
+目录
+
+- 介绍
+- 全局中间件
+- 鉴权中间件
+- 响应中间件
+- 更多
+
+### 介绍
+- 在hotgo中,中间件/拦截器主要作用于web请求的上下文预设、跨域请求处理、鉴权处理、请求拦截和请求结束后统一响应处理等。
+
+
+### 全局中间件
+```go
+package main
+
+import (
+ "hotgo/internal/service"
+)
+
+func main() {
+
+ // 初始化请求上下文,一般需要第一个进行加载,后续中间件存在依赖关系
+ service.Middleware().Ctx()
+
+ // 跨域中间件,自动处理跨域问题
+ service.Middleware().CORS()
+
+ // IP黑名单中间件,如果请求IP被后台拉黑,所有请求将被拒绝
+ service.Middleware().Blacklist()
+
+ // 演示系統操作限制,当开启演示模式时,所有POST请求将被拒绝
+ service.Middleware().DemoLimit()
+
+ // 请求输入预处理,api使用gf规范路由并且XxxReq结构体实现了validate.Filter接口即可隐式预处理
+ service.Middleware().PreFilter()
+
+ // HTTP响应预处理,在业务处理完成后,对响应结果进行格式化和错误过滤,将处理后的数据发送给请求方
+ service.Middleware().ResponseHandler()
+
+}
+
+```
+### 鉴权中间件
+```go
+package main
+
+import (
+ "github.com/gogf/gf/v2/frame/g"
+)
+
+func main() {
+
+ // 在鉴权中间件下的路由如果没有通过权限验证,后续请求将被拒绝
+ // 在hotgo中,鉴权中间件一般是配合一个业务模块下的路由组进行使用
+ // 目前admin、api、home、websocket模块都已接入
+ // 如果你需要创建一个新的模块也需要用到鉴权中间件,可以参考:server/internal/logic/middleware/admin_auth.go
+
+
+ // 一个简单例子
+ s := g.Server()
+ s.Group("/api", func(group *ghttp.RouterGroup) {
+ group.Middleware(service.Middleware().ApiAuth)
+ group.Bind(
+ member.Member, // 管理员
+ )
+ })
+
+}
+
+```
+
+### 响应中间件
+- 文件路径:server/internal/logic/middleware/response.go
+
+
+#### 常用响应类型
+
+- hotgo为一些常用的响应类型做了统一格式封装,例如:`application/json`、`text/xml`、`text/html`、`text/event-stream`等,默认使用`application/json`。
+- 下面我们以`text/xml`为例简单演示几种使用方法:
+
+1. 当你使用规范化路由时,可直接在XxxRes结构体的`g.Meta`中声明响应类型:
+
+```go
+type HelloReq struct {
+ g.Meta `path:"/hello" tags:"Hello" method:"get" summary:"You first hello api"`
+ Name string `json:"name" d:"hotgo" dc:"名字"`
+}
+
+type HelloRes struct {
+ g.Meta `mime:"text/xml" type:"string"`
+ Tips string `json:"tips"`
+}
+```
+
+2. 在响应前设置响应头:
+
+```go
+var (
+ Hello = cHello{}
+)
+
+type cHello struct{}
+
+func (c *cHello) Hello(ctx context.Context, req *user.HelloReq) (res *user.HelloRes, err error) {
+ r := ghttp.RequestFromCtx(ctx)
+ r.Response.Header().Set("Content-Type", "text/xml")
+
+ res = &user.HelloRes{
+ Tips: fmt.Sprintf("hello %v, this is the api for %v applications.", req.Name, simple.AppName(ctx)),
+ }
+ return
+}
+```
+
+- 浏览器中访问响应内容如下:
+
+
+
+
+#### 自定义响应
+- 在实际开发中,可能需要使用自定义的响应类型,由于响应中间件是全局的,因此您需要对其进行单独处理。
+- 推荐以下几种处理方案,可做参考:
+1. 使用`ghttp.ExitAll()`,需要注意的是此方法会终止后续所有的http处理
+
+```go
+package main
+
+import (
+ "github.com/gogf/gf/v2/net/ghttp"
+)
+
+func main() {
+ r := new(ghttp.Request) // 当前请求对象
+
+ // 清空响应
+ r.Response.ClearBuffer()
+
+ // 写入响应
+ r.Response.Write("自定义响应内容")
+
+ // 终止后续http处理
+ r.ExitAll()
+}
+```
+
+2. 在`server/internal/logic/middleware/response.go`中根据请求的独有特征进行单独的处理,兼容后续http处理。
+
+#### 重写响应错误提示
+- 在实际开发中,我们可能想要隐藏一些敏感错误,返回给客户端友好的错误提示,但开发者同时又想需要看到真实的敏感错误。对此hotgo已经进行了过滤处理,下面是一个简单的例子:
+
+```go
+package main
+
+import (
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+func test() error {
+ err = gerror.New("这是一个sql执行错误")
+ err = gerror.Wrap(err, "用户创建失败,请稍后重试!~")
+ return err
+}
+```
+
+- 开启debug时的客户端响应:
+```json
+{
+ "code": -1,
+ "message": "用户创建失败,请稍后重试!~",
+ "error": [
+ "1. 用户创建失败,请稍后重试!~",
+ " 1). hotgo/internal/logic/admin.(*sAdminMember).List",
+ " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526",
+ "2. 这是一个sql执行错误", " 1). hotgo/internal/logic/admin.(*sAdminMember).List",
+ " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:525",
+ " 2). hotgo/internal/controller/admin/admin.(*cMember).List",
+ " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/controller/admin/admin/member.go:157", ""
+ ],
+ "timestamp": 1684145107,
+ "traceID": "084022730d495f17f19e550140f3e1a8"
+}
+```
+
+- 关闭debug时的客户端响应:
+```json
+{
+ "code": -1,
+ "message": "用户创建失败,请稍后重试!~",
+ "timestamp": 1684145107,
+ "traceID": "084022730d495f17f19e550140f3e1a8"
+}
+```
+
+- 控制台的输出日志:
+
+```shell
+2023-05-15 18:05:07.776 {084022730d495f17f19e550140f3e1a8} 200 "GET http localhost:8000 /admin/member/list?page=1&pageSize=10&roleId=-1 HTTP/1.1" 0.002, 127.0.0.1, "http://192.168.0.207:8001/login", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Co
+re/1.94.197.400 QQBrowser/11.7.5287.400", -1, "", ""
+Stack:
+1. 用户创建失败,请稍后重试!~
+ 1). hotgo/internal/logic/admin.(*sAdminMember).List
+ E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526
+2. 这是一个sql执行错误
+ 1). hotgo/internal/logic/admin.(*sAdminMember).List
+ E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/response.go:24
+ 13). hotgo/internal/logic/middleware.(*sMiddleware).DemoLimit
+ E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:90
+
+```
+
+- 如果你开启了访问日志,那么日志记录中会详细记录本次请求的相关信息,内容如下:
+
+
+
+#### 重写错误码
+- hotgo默认使用了gf内置的错误码进行业务处理,通常情况下成功状态码为`0`,失败状态码为`-1`
+- 查看gf内置错误码:https://goframe.org/pages/viewpage.action?pageId=30739587
+- 以下是自定义错误码的简单例子:
+
+```go
+package main
+
+import (
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+func test() error {
+ // 使用自定义状态码30001响应客户端
+ err = gerror.NewCode(gcode.New(30001, "用户创建失败,请稍后重试!~", nil))
+ return err
+}
+```
+
+
+- 客户端响应如下:
+```json
+{
+ "code": 30001,
+ "message": "用户创建失败,请稍后重试!~",
+ "timestamp": 1684146313,
+ "traceID": "b4f90e16264a5f17cd3fc27141aba448"
+}
+```
+
+### 更多
+- 更多关于中间件/拦截器的介绍请参考:https://goframe.org/pages/viewpage.action?pageId=55289881
+
diff --git a/docs/guide-zh-CN/sys-tenant.md b/docs/guide-zh-CN/sys-tenant.md
index 931224e..6c97d79 100644
--- a/docs/guide-zh-CN/sys-tenant.md
+++ b/docs/guide-zh-CN/sys-tenant.md
@@ -44,6 +44,7 @@ SaaS系统多租户多应用设计,已成为互联网企业的重要发展建
- 在用户登录成功后,server端可通过上下文来获取用户部门类型来确定用户身份
- 文件路径:server/internal/library/contexts/context.go
+
```go
package contexts
@@ -87,6 +88,7 @@ func IsUserDept(ctx context.Context) bool {
- 在用户登录成功后,web端可通`useUserStore`来获取用户部门类型来确定用户身份
- 文件路径:web/src/store/modules/user.ts
+
```vue
+ // Progress Plugin Configuration
+ progress: {
+ position: "top",
+ // color: "var(--theme-color,#42b983)",
+ height: "3px",
+ },
+ };
+
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-