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) }