add
This commit is contained in:
272
deploy/api/api_register/main.go
Normal file
272
deploy/api/api_register/main.go
Normal file
@@ -0,0 +1,272 @@
|
||||
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)
|
||||
}
|
Reference in New Issue
Block a user