diff --git a/go.mod b/go.mod index ebb6587..06725db 100644 --- a/go.mod +++ b/go.mod @@ -72,8 +72,11 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/labstack/echo/v4 v4.13.4 // indirect + github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -87,6 +90,8 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect diff --git a/go.sum b/go.sum index 7c99d20..cf12567 100644 --- a/go.sum +++ b/go.sum @@ -116,10 +116,16 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA= +github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= @@ -171,6 +177,10 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= diff --git a/internal/app/controller/auth_utils.go b/internal/app/controller/auth_utils.go index 08a9589..aa8f447 100644 --- a/internal/app/controller/auth_utils.go +++ b/internal/app/controller/auth_utils.go @@ -4,21 +4,21 @@ import ( "errors" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) var ( - // ErrUserNotFoundInContext 表示在 gin.Context 中未找到用户信息。 + // ErrUserNotFoundInContext 表示在 context 中未找到用户信息。 ErrUserNotFoundInContext = errors.New("context中未找到用户信息") - // ErrInvalidUserType 表示从 gin.Context 中获取的用户信息类型不正确。 + // ErrInvalidUserType 表示从 context 中获取的用户信息类型不正确。 ErrInvalidUserType = errors.New("context中用户信息类型不正确") ) -// GetOperatorIDFromContext 从 gin.Context 中提取操作者ID。 +// GetOperatorIDFromContext 从 echo.Context 中提取操作者ID。 // 假设操作者ID是由 AuthMiddleware 存储到 context 中的 *models.User 对象的 ID 字段。 -func GetOperatorIDFromContext(c *gin.Context) (uint, error) { - userVal, exists := c.Get(models.ContextUserKey.String()) - if !exists { +func GetOperatorIDFromContext(c echo.Context) (uint, error) { + userVal := c.Get(models.ContextUserKey.String()) + if userVal == nil { return 0, ErrUserNotFoundInContext } @@ -30,11 +30,11 @@ func GetOperatorIDFromContext(c *gin.Context) (uint, error) { return user.ID, nil } -// GetOperatorFromContext 从 gin.Context 中提取操作者。 -// 假设操作者是由 AuthMiddleware 存储到 context 中的 *models.User 对象的 字段。 -func GetOperatorFromContext(c *gin.Context) (*models.User, error) { - userVal, exists := c.Get(models.ContextUserKey.String()) - if !exists { +// GetOperatorFromContext 从 echo.Context 中提取操作者。 +// 假设操作者是由 AuthMiddleware 存储到 context 中的 *models.User 对象的字段。 +func GetOperatorFromContext(c echo.Context) (*models.User, error) { + userVal := c.Get(models.ContextUserKey.String()) + if userVal == nil { return nil, ErrUserNotFoundInContext } diff --git a/internal/app/controller/response.go b/internal/app/controller/response.go index cb06298..c16d5ce 100644 --- a/internal/app/controller/response.go +++ b/internal/app/controller/response.go @@ -4,7 +4,7 @@ import ( "net/http" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) // --- 业务状态码 --- @@ -37,8 +37,8 @@ type Response struct { } // SendResponse 发送统一格式的JSON响应 (基础函数,不带审计) -func SendResponse(ctx *gin.Context, code ResponseCode, message string, data interface{}) { - ctx.JSON(http.StatusOK, Response{ +func SendResponse(c echo.Context, code ResponseCode, message string, data interface{}) error { + return c.JSON(http.StatusOK, Response{ Code: code, Message: message, Data: data, @@ -46,14 +46,14 @@ func SendResponse(ctx *gin.Context, code ResponseCode, message string, data inte } // SendErrorResponse 发送统一格式的错误响应 (基础函数,不带审计) -func SendErrorResponse(ctx *gin.Context, code ResponseCode, message string) { - SendResponse(ctx, code, message, nil) +func SendErrorResponse(c echo.Context, code ResponseCode, message string) error { + return SendResponse(c, code, message, nil) } // --- 带审计功能的响应函数 --- -// setAuditDetails 是一个内部辅助函数,用于在 gin.Context 中设置业务相关的审计信息。 -func setAuditDetails(c *gin.Context, actionType, description string, targetResource interface{}) { +// setAuditDetails 是一个内部辅助函数,用于在 echo.Context 中设置业务相关的审计信息。 +func setAuditDetails(c echo.Context, actionType, description string, targetResource interface{}) { // 只有当 actionType 不为空时,才设置审计信息,这作为触发审计的标志 if actionType != "" { c.Set(models.ContextAuditActionType.String(), actionType) @@ -65,32 +65,32 @@ func setAuditDetails(c *gin.Context, actionType, description string, targetResou // SendSuccessWithAudit 发送成功的响应,并设置审计日志所需的信息。 // 这是控制器中用于记录成功操作并返回响应的首选函数。 func SendSuccessWithAudit( - ctx *gin.Context, // Gin上下文,用于处理HTTP请求和响应 + c echo.Context, // Echo上下文,用于处理HTTP请求和响应 code ResponseCode, // 业务状态码,表示操作结果 message string, // 提示信息,向用户展示操作结果的文本描述 data interface{}, // 业务数据,操作成功后返回的具体数据 actionType string, // 审计操作类型,例如"创建用户", "更新配置" description string, // 审计描述,对操作的详细说明 targetResource interface{}, // 审计目标资源,被操作的资源对象或其标识 -) { +) error { // 1. 设置审计信息 - setAuditDetails(ctx, actionType, description, targetResource) + setAuditDetails(c, actionType, description, targetResource) // 2. 发送响应 - SendResponse(ctx, code, message, data) + return SendResponse(c, code, message, data) } // SendErrorWithAudit 发送失败的响应,并设置审计日志所需的信息。 // 这是控制器中用于记录失败操作并返回响应的首选函数。 func SendErrorWithAudit( - ctx *gin.Context, // Gin上下文,用于处理HTTP请求和响应 + c echo.Context, // Echo上下文,用于处理HTTP请求和响应 code ResponseCode, // 业务状态码,表示操作结果 message string, // 提示信息,向用户展示操作结果的文本描述 actionType string, // 审计操作类型,例如"登录失败", "删除失败" description string, // 审计描述,对操作的详细说明 targetResource interface{}, // 审计目标资源,被操作的资源对象或其标识 -) { +) error { // 1. 设置审计信息 - setAuditDetails(ctx, actionType, description, targetResource) + setAuditDetails(c, actionType, description, targetResource) // 2. 发送响应 - SendErrorResponse(ctx, code, message) + return SendErrorResponse(c, code, message) } diff --git a/openspec/changes/refactor-migrate-gin-to-echo/tasks.md b/openspec/changes/refactor-migrate-gin-to-echo/tasks.md index 3924a5a..bd60f0e 100644 --- a/openspec/changes/refactor-migrate-gin-to-echo/tasks.md +++ b/openspec/changes/refactor-migrate-gin-to-echo/tasks.md @@ -4,13 +4,13 @@ - [x] 修改 `config.yml` 中 `mode` 配置项的注释,将 "Gin 运行模式" 改为 "服务运行模式"。 - [x] 修改 `config.example.yml` 中 `mode` 配置项的注释,保持与 `config.yml` 一致。 -- [ ] **2. 控制器辅助函数 (最基础的依赖)** - - [ ] **`internal/app/controller/response.go`** - - [ ] 将 `*gin.Context` 参数全部替换为 `echo.Context`。 - - [ ] 修改 `SendResponse` 和 `SendErrorResponse` 等函数,使其不再直接写入响应,而是返回 `error`,并在内部调用 `c.JSON(...)`。 - - [ ] **`internal/app/controller/auth_utils.go`** - - [ ] 将 `*gin.Context` 参数全部替换为 `echo.Context`。 - - [ ] 适配 `Get...FromContext` 系列函数,使用 `c.Get("key")` 提取数据。 +- [x] **2. 控制器辅助函数 (最基础的依赖)** + - [x] **`internal/app/controller/response.go`** + - [x] 将 `*gin.Context` 参数全部替换为 `echo.Context`。 + - [x] 修改 `SendResponse` 和 `SendErrorResponse` 等函数,使其不再直接写入响应,而是返回 `error`,并在内部调用 `c.JSON(...)`。 + - [x] **`internal/app/controller/auth_utils.go`** + - [x] 将 `*gin.Context` 参数全部替换为 `echo.Context`。 + - [x] 适配 `Get...FromContext` 系列函数,使用 `c.Get("key")` 提取数据。 - [ ] **3. 中间件 (`internal/app/middleware`)** - [ ] **`auth.go`**