252 lines
6.7 KiB
Go
252 lines
6.7 KiB
Go
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)
|
||
}
|