From 77908424e38119ed5c3402285500799e41b4dd20 Mon Sep 17 00:00:00 2001 From: vipg Date: Tue, 11 Nov 2025 17:25:28 +0800 Subject: [PATCH] add --- backend/country/src/logic/create.go | 0 backend/country/src/logic/delete.go | 0 backend/country/src/logic/login.go | 166 ----------------- backend/country/src/logic/read.go | 0 backend/country/src/logic/register.go | 251 -------------------------- backend/country/src/logic/update.go | 0 6 files changed, 417 deletions(-) create mode 100644 backend/country/src/logic/create.go create mode 100644 backend/country/src/logic/delete.go delete mode 100644 backend/country/src/logic/login.go create mode 100644 backend/country/src/logic/read.go delete mode 100644 backend/country/src/logic/register.go create mode 100644 backend/country/src/logic/update.go diff --git a/backend/country/src/logic/create.go b/backend/country/src/logic/create.go new file mode 100644 index 0000000..e69de29 diff --git a/backend/country/src/logic/delete.go b/backend/country/src/logic/delete.go new file mode 100644 index 0000000..e69de29 diff --git a/backend/country/src/logic/login.go b/backend/country/src/logic/login.go deleted file mode 100644 index 0919e49..0000000 --- a/backend/country/src/logic/login.go +++ /dev/null @@ -1,166 +0,0 @@ -package logic - -import ( - "database/sql" - "net/http" - "user/db" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" - "go.uber.org/zap" - "golang.org/x/crypto/bcrypt" -) - -// LoginRequest 登录请求参数结构 -// 用于接收前端传递的登录账号和密码 -// json标签指定JSON序列化/反序列化的字段名 -// binding:"required"表示该字段为必填项,用于参数校验 -type LoginRequest struct { - Account string `json:"account" binding:"required"` // 登录账号 - Password string `json:"password" binding:"required"` // 登录密码 -} - -// LoginResponse 登录响应结构 -// 用于向前端返回登录结果 -type LoginResponse struct { - Success bool `json:"success"` // 登录是否成功 - Message string `json:"message"` // 登录结果描述信息 - Data struct { // 登录成功时返回的附加数据 - UserID string `json:"user_id,omitempty"` // 用户ID,omitempty表示为空时不序列化 - } `json:"data"` -} - -// LoginHandler 处理用户登录请求的处理器函数 -// 参数c是gin.Context,用于获取请求信息和返回响应 -func LoginHandler(c *gin.Context) { - // 获取请求ID,用于追踪请求链路,若请求头中没有则生成一个新的UUID - reqID := c.Request.Header.Get("X-LoginRequest-ID") - if reqID == "" { - reqID = uuid.New().String() - } - // 记录收到登录请求的日志,包含请求ID和客户端IP - zap.L().Info("💡 收到登录请求", - zap.String("reqID", reqID), - zap.String("clientIP", c.ClientIP()), - ) - - // 声明一个LoginRequest类型变量用于接收请求参数 - var req LoginRequest - // 绑定并验证请求参数(JSON格式) - if err := c.ShouldBindJSON(&req); err != nil { - // 绑定失败时记录警告日志,并返回错误响应 - zap.L().Warn("❗️ 请求参数绑定失败", - zap.String("reqID", reqID), - zap.Error(err), - zap.Any("请求体", c.Request.Body), - ) - c.JSON(http.StatusBadRequest, LoginResponse{ - Success: false, - Message: "账号或密码不能为空", - }) - return - } - // 记录参数绑定成功的日志 - zap.L().Info("✅ 请求参数绑定成功", - zap.String("reqID", reqID), - zap.String("账号", req.Account), - ) - - // 1. 二次校验账号和密码是否为空(双重保险,防止校验规则被绕过) - if req.Account == "" || req.Password == "" { - zap.L().Warn("❗️ 账号或密码为空", - zap.String("reqID", reqID), - zap.String("账号", req.Account), - ) - c.JSON(http.StatusBadRequest, LoginResponse{ - Success: false, - Message: "账号或密码不能为空", - }) - return - } - - // 2. 从数据库查询账号对应的密码和用户ID - var storedPassword string // 数据库中存储的加密密码 - var userID string // 用户ID - // 查询语句:从用户账号密码视图中查询指定账号(未删除)的密码和用户ID - query := ` - SELECT password, user_id - FROM user_account_password_view - WHERE account = $1 AND deleted = false - ` - zap.L().Info("💡 执行查询", - zap.String("reqID", reqID), - zap.String("query", query), - zap.String("参数", req.Account), - ) - // 执行查询并将结果扫描到变量中 - err := db.DB.QueryRow(query, req.Account).Scan(&storedPassword, &userID) - switch { - case err == sql.ErrNoRows: - // 账号不存在或已被删除的情况 - zap.L().Warn("❗️ 账号不存在或已删除", - zap.String("reqID", reqID), - zap.String("账号", req.Account), - ) - c.JSON(http.StatusOK, LoginResponse{ - Success: false, - Message: "账号不存在", - }) - return - case err != nil: - // 查询过程发生错误的情况 - zap.L().Error("❌ 查询账号信息失败", - zap.String("reqID", reqID), - zap.Error(err), - zap.String("账号", req.Account), - ) - c.JSON(http.StatusInternalServerError, LoginResponse{ - Success: false, - Message: "查询账号信息失败", - }) - return - } - // 记录查询账号信息成功的日志 - zap.L().Info("✅ 查询账号信息成功", - zap.String("reqID", reqID), - zap.String("账号", req.Account), - zap.String("userID", userID), - ) - - // 3. 验证密码(使用bcrypt比较原始密码和存储的加密密码) - err = bcrypt.CompareHashAndPassword([]byte(storedPassword), []byte(req.Password)) - if err != nil { - // 密码不匹配的情况 - zap.L().Warn("❗️ 密码验证失败", - zap.String("reqID", reqID), - zap.String("账号", req.Account), - zap.Error(err), - ) - c.JSON(http.StatusOK, LoginResponse{ - Success: false, - Message: "密码错误", - }) - return - } - // 记录密码验证成功的日志 - zap.L().Info("✅ 密码验证成功", - zap.String("reqID", reqID), - zap.String("账号", req.Account), - ) - - // 4. 登录成功,返回成功响应并包含用户ID - zap.L().Info("✅ 登录成功", - zap.String("reqID", reqID), - zap.String("账号", req.Account), - zap.String("userID", userID), - ) - c.JSON(http.StatusOK, LoginResponse{ - Success: true, - Message: "登录成功", - Data: struct { - UserID string `json:"user_id,omitempty"` - }{ - UserID: userID, - }, - }) -} diff --git a/backend/country/src/logic/read.go b/backend/country/src/logic/read.go new file mode 100644 index 0000000..e69de29 diff --git a/backend/country/src/logic/register.go b/backend/country/src/logic/register.go deleted file mode 100644 index c8c30f2..0000000 --- a/backend/country/src/logic/register.go +++ /dev/null @@ -1,251 +0,0 @@ -package logic - -import ( - "net/http" - "time" - "user/db" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" - _ "github.com/lib/pq" - "go.uber.org/zap" - "golang.org/x/crypto/bcrypt" -) - -// RegisterRequest 注册请求参数结构 -type RegisterRequest struct { - Account string `json:"account" binding:"required"` - Password string `json:"password" binding:"required"` -} - -// RegisterResponse 注册响应结构 -type RegisterResponse struct { - Success bool `json:"success"` - Message string `json:"message"` - Data struct { - UserID string `json:"user_id,omitempty"` - Account string `json:"account,omitempty"` - } `json:"data"` -} - -// registerHandler 处理用户注册逻辑 -func RegisterHandler(c *gin.Context) { - startTime := time.Now() - reqID := c.Request.Header.Get("X-RegisterRequest-ID") - if reqID == "" { - reqID = uuid.New().String() - } - // 使用zap.Info记录开始处理日志,添加请求ID字段 - zap.L().Info("⌛️ 收到注册请求,开始处理", zap.String("req_id", reqID)) - - var req RegisterRequest - // 绑定并验证请求参数 - if err := c.ShouldBindJSON(&req); err != nil { - zap.L().Error("❌ 请求参数绑定失败", - zap.String("req_id", reqID), - zap.Error(err)) - c.JSON(http.StatusBadRequest, RegisterResponse{ - Success: false, - Message: "请求参数错误: " + err.Error(), - }) - return - } - zap.L().Info("✅ 请求参数绑定成功", - zap.String("req_id", reqID), - zap.String("account", req.Account)) - - // 1. 判断接口的账号和密码是否为空 - if req.Account == "" || req.Password == "" { - zap.L().Warn("⚠️ 账号或密码为空,拒绝注册", - zap.String("req_id", reqID)) - c.JSON(http.StatusBadRequest, RegisterResponse{ - Success: false, - Message: "账号和密码不能为空", - }) - return - } - - // 2. 使用接口账号查询视图,检查账号是否已存在 - var exists bool - query := ` - SELECT EXISTS( - SELECT 1 - FROM user_account_password_view - WHERE account = $1 AND deleted = false - ) - ` - zap.L().Info("💡 执行账号存在性查询", - zap.String("req_id", reqID), - zap.String("query", query)) - - err := db.DB.QueryRow(query, req.Account).Scan(&exists) - if err != nil { - zap.L().Error("❌ 账号查询失败", - zap.String("req_id", reqID), - zap.Error(err)) - c.JSON(http.StatusInternalServerError, RegisterResponse{ - Success: false, - Message: "查询账号信息失败: " + err.Error(), - }) - return - } - zap.L().Info("💡 账号存在性查询完成", - zap.String("req_id", reqID), - zap.Bool("exists", exists)) - - // 3. 判断查询结果,若存在则提示账号已存在 - if exists { - zap.L().Warn("❗️ 账号已存在", - zap.String("req_id", reqID), - zap.String("account", req.Account)) - c.JSON(http.StatusOK, RegisterResponse{ - Success: false, - Message: "账号已存在", - }) - return - } - - // 4. 开启数据库事务,确保数据一致性 - tx, err := db.DB.Begin() - if err != nil { - zap.L().Error("❌ 开启事务失败", - zap.String("req_id", reqID), - zap.Error(err)) - c.JSON(http.StatusInternalServerError, RegisterResponse{ - Success: false, - Message: "开启事务失败: " + err.Error(), - }) - return - } - defer func() { - if r := recover(); r != nil { - zap.L().Error("❌ 发生恐慌,回滚事务", - zap.String("req_id", reqID), - zap.Any("recover", r)) - tx.Rollback() - } - }() - zap.L().Info("✅ 数据库事务开启成功", zap.String("req_id", reqID)) - - // 5. 在user表生成新用户ID - var userID string - insertUserQuery := ` - INSERT INTO "user" DEFAULT VALUES - RETURNING id - ` - zap.L().Info("💡 执行用户创建", - zap.String("req_id", reqID), - zap.String("query", insertUserQuery)) - - err = tx.QueryRow(insertUserQuery).Scan(&userID) - if err != nil { - zap.L().Error("❌ 创建用户失败", - zap.String("req_id", reqID), - zap.Error(err)) - tx.Rollback() - c.JSON(http.StatusInternalServerError, RegisterResponse{ - Success: false, - Message: "创建用户失败: " + err.Error(), - }) - return - } - zap.L().Info("✅ 用户创建成功", - zap.String("req_id", reqID), - zap.String("user_id", userID)) - - // 6. 对密码进行加密处理 - zap.L().Info("💡 开始密码加密", zap.String("req_id", reqID)) - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) - if err != nil { - zap.L().Error("❌ 密码加密失败", - zap.String("req_id", reqID), - zap.Error(err)) - tx.Rollback() - c.JSON(http.StatusInternalServerError, RegisterResponse{ - Success: false, - Message: "密码加密失败: " + err.Error(), - }) - return - } - zap.L().Info("✅ 密码加密成功", zap.String("req_id", reqID)) - - // 7. 插入user_account表 - insertAccountQuery := ` - INSERT INTO user_account (user_id, account) - VALUES ($1, $2) - ` - zap.L().Info("💡 执行账号插入", - zap.String("req_id", reqID), - zap.String("query", insertAccountQuery), - zap.String("user_id", userID), - zap.String("account", req.Account)) - - _, err = tx.Exec(insertAccountQuery, userID, req.Account) - if err != nil { - zap.L().Error("❌ 保存账号信息失败", - zap.String("req_id", reqID), - zap.Error(err)) - tx.Rollback() - c.JSON(http.StatusInternalServerError, RegisterResponse{ - Success: false, - Message: "保存账号信息失败: " + err.Error(), - }) - return - } - zap.L().Info("✅ 账号信息保存成功", zap.String("req_id", reqID)) - - // 8. 插入user_password表 - insertPasswordQuery := ` - INSERT INTO user_password (user_id, password) - VALUES ($1, $2) - ` - zap.L().Info("💡 执行密码插入", - zap.String("req_id", reqID), - zap.String("query", insertPasswordQuery), - zap.String("user_id", userID)) - - _, err = tx.Exec(insertPasswordQuery, userID, string(hashedPassword)) - if err != nil { - zap.L().Error("❌ 保存密码信息失败", - zap.String("req_id", reqID), - zap.Error(err)) - tx.Rollback() - c.JSON(http.StatusInternalServerError, RegisterResponse{ - Success: false, - Message: "保存密码信息失败: " + err.Error(), - }) - return - } - zap.L().Info("✅ 密码信息保存成功", zap.String("req_id", reqID)) - - // 9. 提交事务 - if err := tx.Commit(); err != nil { - zap.L().Error("❌ 提交事务失败", - zap.String("req_id", reqID), - zap.Error(err)) - tx.Rollback() - c.JSON(http.StatusInternalServerError, RegisterResponse{ - Success: false, - Message: "提交事务失败: " + err.Error(), - }) - return - } - zap.L().Info("✅ 事务提交成功", zap.String("req_id", reqID)) - - // 10. 注册成功 - response := RegisterResponse{ - Success: true, - Message: "注册成功", - } - response.Data.UserID = userID - response.Data.Account = req.Account - - duration := time.Since(startTime) - zap.L().Info("✅ 注册成功", - zap.String("req_id", reqID), - zap.Duration("duration", duration), - zap.String("user_id", userID), - zap.String("account", req.Account)) - - c.JSON(http.StatusOK, response) -} diff --git a/backend/country/src/logic/update.go b/backend/country/src/logic/update.go new file mode 100644 index 0000000..e69de29