package main import ( "database/sql" "fmt" "net/http" "os" "time" "github.com/gin-gonic/gin" _ "github.com/lib/pq" "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,omitempty"` } var db *sql.DB func main() { // 初始化Gin引擎 fmt.Println("[主程序] 初始化Gin引擎") r := gin.Default() // 从环境变量获取数据库配置 fmt.Println("[主程序] 读取数据库配置环境变量") dbHost := os.Getenv("DB_HOST") dbPort := os.Getenv("DB_PORT") dbUser := os.Getenv("DB_USER") dbPassword := os.Getenv("DB_PASSWORD") dbName := os.Getenv("DB_NAME") // 构建数据库连接字符串 connStr := fmt.Sprintf( "host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", dbHost, dbPort, dbUser, dbPassword, dbName, ) fmt.Printf("[主程序] 数据库连接字符串构建完成: %s\n", maskPassword(connStr)) // 连接数据库 var err error db, err = sql.Open("postgres", connStr) if err != nil { panic(fmt.Sprintf("[主程序] 无法连接数据库: %v", err)) } defer db.Close() fmt.Println("[主程序] 数据库连接对象创建成功") // 验证数据库连接 if err := db.Ping(); err != nil { panic(fmt.Sprintf("[主程序] 数据库连接失败: %v", err)) } fmt.Println("[主程序] 数据库连接验证成功") // 注册账号接口 r.POST("/user/register", registerHandler) fmt.Println("[主程序] 注册接口路由已配置") // 启动服务,监听80端口 fmt.Println("[主程序] 服务启动在80端口") r.Run(":80") } // 屏蔽连接字符串中的密码,避免日志泄露敏感信息 func maskPassword(connStr string) string { // 简单处理:替换password=后的内容直到下一个空格 start := false result := "" for _, c := range connStr { if start && c == ' ' { start = false } if start { continue } result += string(c) // 先检查长度是否足够,避免索引越界 if len(result) >= 10 && result[len(result)-10:] == "password=" { start = true result += "***" } } return result } // registerHandler 处理用户注册逻辑 func registerHandler(c *gin.Context) { startTime := time.Now() reqID := fmt.Sprintf("req-%d", time.Now().UnixNano()) // 生成请求唯一标识 fmt.Printf("[%s] 收到注册请求,开始处理\n", reqID) var req RegisterRequest // 绑定并验证请求参数 if err := c.ShouldBindJSON(&req); err != nil { fmt.Printf("[%s] 请求参数绑定失败: %v\n", reqID, err) c.JSON(http.StatusBadRequest, RegisterResponse{ Success: false, Message: "请求参数错误: " + err.Error(), }) return } fmt.Printf("[%s] 请求参数绑定成功,账号: %s\n", reqID, req.Account) // 1. 判断接口的账号和密码是否为空 if req.Account == "" || req.Password == "" { fmt.Printf("[%s] 账号或密码为空,拒绝注册\n", 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 ) ` fmt.Printf("[%s] 执行账号存在性查询: %s\n", reqID, query) err := db.QueryRow(query, req.Account).Scan(&exists) if err != nil { fmt.Printf("[%s] 账号查询失败: %v\n", reqID, err) c.JSON(http.StatusInternalServerError, RegisterResponse{ Success: false, Message: "查询账号信息失败: " + err.Error(), }) return } fmt.Printf("[%s] 账号存在性查询完成,存在: %v\n", reqID, exists) // 3. 判断查询结果,若存在则提示账号已存在 if exists { fmt.Printf("[%s] 账号已存在: %s\n", reqID, req.Account) c.JSON(http.StatusOK, RegisterResponse{ Success: false, Message: "账号已存在", }) return } // 4. 开启数据库事务,确保数据一致性 tx, err := db.Begin() if err != nil { fmt.Printf("[%s] 开启事务失败: %v\n", reqID, err) c.JSON(http.StatusInternalServerError, RegisterResponse{ Success: false, Message: "开启事务失败: " + err.Error(), }) return } defer func() { if r := recover(); r != nil { fmt.Printf("[%s] 发生恐慌,回滚事务: %v\n", reqID, r) tx.Rollback() } }() fmt.Printf("[%s] 数据库事务开启成功\n", reqID) // 5. 在user表生成新用户ID var userID string insertUserQuery := ` INSERT INTO "user" DEFAULT VALUES RETURNING id ` fmt.Printf("[%s] 执行用户创建: %s\n", reqID, insertUserQuery) err = tx.QueryRow(insertUserQuery).Scan(&userID) if err != nil { fmt.Printf("[%s] 创建用户失败: %v\n", reqID, err) tx.Rollback() c.JSON(http.StatusInternalServerError, RegisterResponse{ Success: false, Message: "创建用户失败: " + err.Error(), }) return } fmt.Printf("[%s] 用户创建成功,用户ID: %s\n", reqID, userID) // 6. 对密码进行加密处理 fmt.Printf("[%s] 开始密码加密\n", reqID) hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) if err != nil { fmt.Printf("[%s] 密码加密失败: %v\n", reqID, err) tx.Rollback() c.JSON(http.StatusInternalServerError, RegisterResponse{ Success: false, Message: "密码加密失败: " + err.Error(), }) return } fmt.Printf("[%s] 密码加密成功\n", reqID) // 7. 插入user_account表 insertAccountQuery := ` INSERT INTO user_account (user_id, account) VALUES ($1, $2) ` fmt.Printf("[%s] 执行账号插入: %s, 参数: user_id=%s, account=%s\n", reqID, insertAccountQuery, userID, req.Account) _, err = tx.Exec(insertAccountQuery, userID, req.Account) if err != nil { fmt.Printf("[%s] 保存账号信息失败: %v\n", reqID, err) tx.Rollback() c.JSON(http.StatusInternalServerError, RegisterResponse{ Success: false, Message: "保存账号信息失败: " + err.Error(), }) return } fmt.Printf("[%s] 账号信息保存成功\n", reqID) // 8. 插入user_password表 insertPasswordQuery := ` INSERT INTO user_password (user_id, password) VALUES ($1, $2) ` fmt.Printf("[%s] 执行密码插入: %s, 参数: user_id=%s\n", reqID, insertPasswordQuery, userID) _, err = tx.Exec(insertPasswordQuery, userID, string(hashedPassword)) if err != nil { fmt.Printf("[%s] 保存密码信息失败: %v\n", reqID, err) tx.Rollback() c.JSON(http.StatusInternalServerError, RegisterResponse{ Success: false, Message: "保存密码信息失败: " + err.Error(), }) return } fmt.Printf("[%s] 密码信息保存成功\n", reqID) // 9. 提交事务 if err := tx.Commit(); err != nil { fmt.Printf("[%s] 提交事务失败: %v\n", reqID, err) tx.Rollback() c.JSON(http.StatusInternalServerError, RegisterResponse{ Success: false, Message: "提交事务失败: " + err.Error(), }) return } fmt.Printf("[%s] 事务提交成功\n", reqID) // 10. 注册成功 response := RegisterResponse{ Success: true, Message: "注册成功", } response.Data.UserID = userID response.Data.Account = req.Account duration := time.Since(startTime) fmt.Printf("[%s] 注册成功,耗时: %v, 用户ID: %s, 账号: %s\n", reqID, duration, userID, req.Account) c.JSON(http.StatusOK, response) }