第28章:实战项目一 —— RESTful API 用户管理系统
本章目标
学完本章后,你将能够独立搭建一个完整的用户管理 API 系统
技术栈:Gin + GORM + JWT + bcrypt
项目结构
user-api/
├── main.go
├── config/config.go
├── models/user.go
├── handlers/user.go
├── middlewares/auth.go
├── response/response.go
└── routes/router.go核心代码
go
// models/user.go
package models
import (
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Username string `gorm:"uniqueIndex;not null" json:"username"`
Password string `gorm:"not null;->:false" json:"-"`
Email string `gorm:"uniqueIndex" json:"email"`
Role string `gorm:"default:user" json:"role"`
}
func (u *User) BeforeCreate(tx *gorm.DB) error {
hashed, _ := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
u.Password = string(hashed)
return nil
}
func (u *User) CheckPassword(pwd string) bool {
return bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(pwd)) == nil
}go
// handlers/user.go
func Register(c *gin.Context) {
var req struct {
Username string `json:"username" binding:"required,min=3,max=50"`
Password string `json:"password" binding:"required,min=6"`
Email string `json:"email" binding:"required,email"`
}
if err := c.ShouldBindJSON(&req); err != nil {
response.ValidationError(c, err.Error())
return
}
user := models.User{Username: req.Username, Password: req.Password, Email: req.Email}
if err := db.Create(&user).Error; err != nil {
response.Error(c, 409, 1003, "用户名或邮箱已存在")
return
}
response.Created(c, gin.H{"id": user.ID, "username": user.Username})
}
func Login(c *gin.Context) {
var req struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
response.ValidationError(c, err.Error())
return
}
var user models.User
if db.Where("username = ?", req.Username).First(&user).Error != nil {
response.Error(c, 401, 1001, "用户名或密码错误")
return
}
if !user.CheckPassword(req.Password) {
response.Error(c, 401, 1002, "用户名或密码错误")
return
}
token, _ := GenerateToken(user.ID, user.Username)
response.Success(c, gin.H{"token": token})
}
func ListUsers(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
var users []models.User
var total int64
db.Model(&models.User{}).Count(&total)
db.Scopes(Paginate(page, pageSize)).Find(&users)
response.Success(c, gin.H{"users": users, "total": total})
}路由注册
go
// routes/router.go
func SetupRouter() *gin.Engine {
r := gin.Default()
api := r.Group("/api/v1")
{
api.POST("/register", handlers.Register)
api.POST("/login", handlers.Login)
auth := api.Group("")
auth.Use(middlewares.JWTAuth())
{
auth.GET("/users", handlers.ListUsers)
auth.GET("/users/:id", handlers.GetUser)
auth.PUT("/users/:id", handlers.UpdateUser)
auth.DELETE("/users/:id", handlers.DeleteUser)
}
}
return r
}API 接口列表
| 方法 | 路径 | 认证 | 说明 |
|---|---|---|---|
| POST | /api/v1/register | 否 | 注册 |
| POST | /api/v1/login | 否 | 登录 |
| GET | /api/v1/users | 是 | 用户列表 |
| GET | /api/v1/users/:id | 是 | 用户详情 |
| PUT | /api/v1/users/:id | 是 | 更新用户 |
| DELETE | /api/v1/users/:id | 是 | 删除用户 |
练习题
- 克隆项目结构,实现所有 6 个接口。
- 添加"修改密码"接口(需要旧密码验证)。
- 添加"用户搜索"功能(按用户名/邮箱模糊搜索)。
- 添加角色权限控制(admin 可以看所有用户,user 只能看自己)。