Files
asset_assistant/backend/country/src/logic/register.go
2025-11-11 16:39:59 +08:00

252 lines
6.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}