用户资料管理是多数业务系统的基础功能,核心需求包括用户资料的创建、查询、更新、删除,以及对应的数据合法性校验和存储逻辑。下面我们将基于Golang生态的常用组件,完整实现一套可用的用户资料管理功能。

环境准备与依赖安装
实现功能前需要先准备基础环境,首先确保本地已经安装Golang 1.18及以上版本,同时安装MySQL数据库用于数据存储。接下来初始化项目并安装所需依赖:
# 初始化Go模块 go mod init user_profile_demo # 安装gin框架 go get -u github.com/gin-gonic/gin # 安装MySQL驱动 go get -u gorm.io/driver/mysql # 安装GORM ORM库 go get -u gorm.io/gorm # 安装参数校验库 go get -u github.com/go-playground/validator/v10
数据库表设计
用户资料表需要存储用户的基础信息,设计如下字段,使用GORM的模型定义方式:
package model
import (
"gorm.io/gorm"
"time"
)
// UserProfile 用户资料模型
type UserProfile struct {
ID uint `gorm:"primarykey" json:"id"`
Username string `gorm:"type:varchar(50);not null;uniqueIndex" json:"username"` // 用户名 唯一
Nickname string `gorm:"type:varchar(50)" json:"nickname"` // 昵称
Email string `gorm:"type:varchar(100);uniqueIndex" json:"email"` // 邮箱 唯一
Phone string `gorm:"type:varchar(20)" json:"phone"` // 手机号
Avatar string `gorm:"type:varchar(255)" json:"avatar"` // 头像地址
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}
数据库连接初始化
封装数据库连接的初始化逻辑,方便后续在业务中使用:
package global
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
var DB *gorm.DB
// InitDB 初始化MySQL连接
func InitDB() {
dsn := "root:password@tcp(127.0.0.1:3306)/user_db?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatalf("数据库连接失败: %v", err)
}
// 自动迁移表结构
err = db.AutoMigrate(&model.UserProfile{})
if err != nil {
log.Fatalf("表结构迁移失败: %v", err)
}
DB = db
log.Println("数据库连接成功")
}
请求参数校验定义
使用validator库定义创建和更新用户资料的请求参数结构体,实现自动校验:
package request
import "github.com/go-playground/validator/v10"
// CreateProfileReq 创建用户资料请求参数
type CreateProfileReq struct {
Username string `json:"username" validate:"required,min=3,max=50"` // 用户名必填 长度3-50
Nickname string `json:"nickname" validate:"max=50"` // 昵称最长50
Email string `json:"email" validate:"required,email"` // 邮箱必填 格式校验
Phone string `json:"phone" validate:"omitempty,e164"` // 手机号可选 符合E164格式
Avatar string `json:"avatar" validate:"omitempty,url"` // 头像可选 符合URL格式
}
// UpdateProfileReq 更新用户资料请求参数
type UpdateProfileReq struct {
Nickname string `json:"nickname" validate:"max=50"`
Email string `json:"email" validate:"omitempty,email"`
Phone string `json:"phone" validate:"omitempty,e164"`
Avatar string `json:"avatar" validate:"omitempty,url"`
}
// Validate 参数校验方法
func (r *CreateProfileReq) Validate() error {
validate := validator.New()
return validate.Struct(r)
}
func (r *UpdateProfileReq) Validate() error {
validate := validator.New()
return validate.Struct(r)
}
业务接口实现
创建用户资料接口
实现用户资料的创建逻辑,包含参数校验、重复校验和数据库写入:
package handler
import (
"net/http"
"user_profile_demo/global"
"user_profile_demo/model"
"user_profile_demo/request"
"github.com/gin-gonic/gin"
"log"
)
// CreateProfile 创建用户资料
func CreateProfile(c *gin.Context) {
var req request.CreateProfileReq
// 绑定请求参数
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数格式错误"})
return
}
// 参数校验
if err := req.Validate(); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": err.Error()})
return
}
// 检查用户名是否已存在
var existUser model.UserProfile
global.DB.Where("username = ?", req.Username).First(&existUser)
if existUser.ID != 0 {
c.JSON(http.StatusConflict, gin.H{"code": 409, "msg": "用户名已存在"})
return
}
// 检查邮箱是否已存在
global.DB.Where("email = ?", req.Email).First(&existUser)
if existUser.ID != 0 {
c.JSON(http.StatusConflict, gin.H{"code": 409, "msg": "邮箱已存在"})
return
}
// 构建用户资料对象
user := model.UserProfile{
Username: req.Username,
Nickname: req.Nickname,
Email: req.Email,
Phone: req.Phone,
Avatar: req.Avatar,
}
// 写入数据库
if err := global.DB.Create(&user).Error; err != nil {
log.Printf("创建用户失败: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "创建用户失败"})
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "创建成功", "data": user})
}
查询用户资料接口
支持根据用户名查询单个用户资料,以及分页查询所有用户资料:
// GetProfileByUsername 根据用户名查询用户资料
func GetProfileByUsername(c *gin.Context) {
username := c.Query("username")
if username == "" {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "用户名不能为空"})
return
}
var user model.UserProfile
global.DB.Where("username = ?", username).First(&user)
if user.ID == 0 {
c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "用户不存在"})
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "查询成功", "data": user})
}
// GetProfileList 分页查询用户资料列表
func GetProfileList(c *gin.Context) {
page := c.DefaultQuery("page", "1")
pageSize := c.DefaultQuery("page_size", "10")
var users []model.UserProfile
var total int64
// 查询总数
global.DB.Model(&model.UserProfile{}).Count(&total)
// 分页查询
global.DB.Offset((pageInt - 1) * pageSizeInt).Limit(pageSizeInt).Find(&users)
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": "查询成功",
"data": users,
"total": total,
})
}
更新用户资料接口
实现用户资料的更新逻辑,仅允许更新昵称、邮箱、手机号、头像字段:
// UpdateProfile 更新用户资料
func UpdateProfile(c *gin.Context) {
id := c.Param("id")
var req request.UpdateProfileReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数格式错误"})
return
}
if err := req.Validate(); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": err.Error()})
return
}
var user model.UserProfile
global.DB.First(&user, id)
if user.ID == 0 {
c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "用户不存在"})
return
}
// 如果更新邮箱 检查是否已被其他用户使用
if req.Email != "" && req.Email != user.Email {
var existUser model.UserProfile
global.DB.Where("email = ?", req.Email).First(&existUser)
if existUser.ID != 0 {
c.JSON(http.StatusConflict, gin.H{"code": 409, "msg": "邮箱已被使用"})
return
}
}
// 更新字段
updateData := map[string]interface{}{}
if req.Nickname != "" {
updateData["nickname"] = req.Nickname
}
if req.Email != "" {
updateData["email"] = req.Email
}
if req.Phone != "" {
updateData["phone"] = req.Phone
}
if req.Avatar != "" {
updateData["avatar"] = req.Avatar
}
global.DB.Model(&user).Updates(updateData)
c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "更新成功", "data": user})
}
删除用户资料接口
使用GORM的软删除功能,删除用户资料时不会真正删除数据库记录:
// DeleteProfile 删除用户资料
func DeleteProfile(c *gin.Context) {
id := c.Param("id")
var user model.UserProfile
global.DB.First(&user, id)
if user.ID == 0 {
c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "用户不存在"})
return
}
// 软删除 数据库deleted_at字段会被赋值
global.DB.Delete(&user)
c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "删除成功"})
}
路由注册与服务启动
最后将接口注册到gin路由,启动HTTP服务:
package main
import (
"user_profile_demo/global"
"user_profile_demo/handler"
"github.com/gin-gonic/gin"
"log"
)
func main() {
// 初始化数据库
global.InitDB()
r := gin.Default()
// 用户资料管理路由组
profileGroup := r.Group("/api/profile")
{
profileGroup.POST("/create", handler.CreateProfile) // 创建用户
profileGroup.GET("/get", handler.GetProfileByUsername) // 查询单个用户
profileGroup.GET("/list", handler.GetProfileList) // 查询用户列表
profileGroup.PUT("/update/:id", handler.UpdateProfile) // 更新用户
profileGroup.DELETE("/delete/:id", handler.DeleteProfile) // 删除用户
}
log.Println("服务启动在 127.0.0.1:8080")
r.Run("127.0.0.1:8080")
}
测试验证
启动服务后,可以使用curl或者postman测试接口:
- 创建用户:发送POST请求到
127.0.0.1:8080/api/profile/create,携带正确的JSON参数即可创建用户 - 查询用户:发送GET请求到
127.0.0.1:8080/api/profile/get?username=test可查询指定用户 - 更新用户:发送PUT请求到
127.0.0.1:8080/api/profile/update/1,携带更新参数即可修改用户资料 - 删除用户:发送DELETE请求到
127.0.0.1:8080/api/profile/delete/1可删除对应用户
以上实现覆盖了用户资料管理的核心场景,开发者可以根据实际业务需求扩展更多字段或者功能,比如增加用户资料的权限控制、添加操作日志等。