go语言实现用户管理系统

goweb实现用户管理系统

用户后台管理系统功能描述

登录功能

  1. 支持用户通过邮箱密码和密码进行登录。
  2. 对输入的邮箱和密码进行验证,确保用户信息的正确性。
  3. 登录成功后,更新用户的今日登录统计信息,并将用户信息存入会话(cookie)中,便于后续操作。
  4. 提供友好的错误提示,如"用户不存在""密码错误""用户已被禁用"等,帮助用户了解登录失败的原因。
go 复制代码
package service

import (
	"UserManager/src/mapper"
	"UserManager/src/utils"
	"fmt"
	"golang.org/x/crypto/bcrypt"
)

type LoginService struct {
	Mapper *mapper.LoginMapper
}

func NewLoginService(lm *mapper.LoginMapper) *LoginService {
	return &LoginService{
		Mapper: lm,
	}
}

// 用户登录
func (ls *LoginService) LoginUser(email string, password string) (string, error) {
	user, err := ls.Mapper.GetUserByEmail(email)
	if err != nil || user == nil {
		return "", fmt.Errorf("用户不存在")
	}

	//验证密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)); err != nil {
		return "", fmt.Errorf("密码错误")
	}
	fmt.Println("hhh", user)
	if user.Status == 0 {
		return "", fmt.Errorf("用户已被禁用")
	}
	//生成JWT
	token, err := utils.GenerateToken(user)

	if err != nil {
		return "", fmt.Errorf("生成令牌失败")
	}

	return token, nil
}

注册功能

  1. 允许用户输入邮箱、验证码,密码及确认密码进行注册。
  2. 对邮箱进行唯一性校验,避免重复注册,并发送验证码。
  3. 检查两次输入的密码是否一致,确保用户密码的准确性。
  4. 使用 bcrypt 算法对用户密码进行加密存储,保障用户密码的安全性。
  5. 注册成功后,自动增加今日新增人数统计。
go 复制代码
package service

import (
	"UserManager/src/mapper"
	"UserManager/src/models"
	"UserManager/src/utils"
	"fmt"
	"github.com/google/uuid"
	"golang.org/x/crypto/bcrypt"
	"regexp"
)

// VerificationInfo 保存验证码及其过期时间

type RegisterService struct {
	Mapper              *mapper.RegisterMapper
	EmailService        *utils.EmailService
	VerificationService *utils.VerificationService
}

func NewRegisterService(rm *mapper.RegisterMapper, emailService *utils.EmailService, vService *utils.VerificationService) *RegisterService {
	return &RegisterService{
		Mapper:              rm,
		EmailService:        emailService,
		VerificationService: vService,
	}
}

// SendVerificationCode 生成验证码,并使用 Redis 存储(有效期5分钟)后发送邮件
func (rs *RegisterService) SendVerificationCode(email string) error {
	code, err := rs.VerificationService.GenerateAndStoreCode(email)
	if err != nil {
		return err
	}
	subject := "您的验证码"
	body := fmt.Sprintf("您的验证码为:%s,请勿泄露于他人!该验证码5分钟内有效!如非本人操作,请忽略此邮件!。", code)

	return rs.EmailService.SendEmail(email, subject, body)
}

// 用户注册
func (rs *RegisterService) RegisterUser(email, inputCode, password, passwordConfirm string) error {
	if !isValidPassword(password) {
		return fmt.Errorf("密码必须是8-12位字母和数字组合")
	}
	if password != passwordConfirm {
		return fmt.Errorf("两次密码输入不一致")
	}
	// 验证验证码
	if err := rs.VerificationService.VerifyCode(email, inputCode); err != nil {
		return err
	}
	// 检查邮箱是否已注册
	if user, _ := rs.Mapper.GetUserByEmail(email); user != nil {
		return fmt.Errorf("邮箱已注册")
	}
	// 加密密码
	hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return fmt.Errorf("密码加密失败:%v", err)
	}
	// 插入新用户
	newUser := &models.User{
		Email:        email,
		PasswordHash: string(hashed),
		Nickname:     "user_" + uuid.New().String()[:8],
	}
	if err := rs.Mapper.InsertUser(newUser); err != nil {
		return fmt.Errorf("用户注册失败:%v", err)
	}

	return nil
}

// isValidPassword 校验密码是否满足8-12位字母和数字组合
func isValidPassword(password string) bool {
	// 1. 检查长度是否为8-12位
	if len(password) < 8 || len(password) > 12 {
		return false
	}
	// 2. 检查是否只包含字母和数字
	validChars, err := regexp.MatchString(`^[0-9A-Za-z]+$`, password)
	if err != nil || !validChars {
		return false
	}
	// 3. 检查是否至少包含一个字母
	hasLetter, err := regexp.MatchString(`[A-Za-z]`, password)
	if err != nil || !hasLetter {
		return false
	}
	// 4. 检查是否至少包含一个数字
	hasDigit, err := regexp.MatchString(`\d`, password)
	if err != nil || !hasDigit {
		return false
	}

	return true
}

用户管理

用户列表展示
  1. 以分页的形式展示系统中的用户列表,每页显示固定数量的用户记录。
  2. 提供用户的基本信息,包括用户名、角色、状态、邮箱、头像、注册时间等,方便管理员快速了解用户情况。
  3. 根据当前页码和总记录数,动态计算并显示分页导航栏,方便管理员切换页面查看不同用户数据。
用户搜索
  1. 支持管理员通过用户名关键字进行用户搜索,快速定位目标用户。
  2. 搜索结果同样以分页形式展示,方便查看大量用户数据。
  3. 提供搜索结果的总记录数、总页数等信息,帮助管理员了解搜索结果的范围。
用户创建

**

  1. 管理员可以输入用户名、密码、邮箱、角色、状态等信息创建新用户。
  2. 对输入的用户信息进行校验,如用户名是否已存在、必填项是否填写等。
  3. 支持上传用户头像,并对上传的文件进行类型、大小校验,确保头像的合法性。 创建成功后,自动更新今日新增人数统计。
用户更新
  1. 管理员可以对现有用户的信息进行修改,包括用户名、密码、邮箱、角色、状态、头像等。
  2. 在修改密码时,只有当用户输入了新密码时才会进行密码更新,并且会对新密码进行加密处理。
  3. 对修改后的用户信息进行校验,如用户名是否被其他用户占用等。
  4. 更新成功后,返回更新后的用户头像路径等信息。
用户删除
  1. 管理员可以删除指定的用户,但不允许删除当前登录用户自己。
  2. 删除用户时,同时删除该用户的头像文件(如果头像不是默认头像)。
  3. 删除成功后,自动更新今日被删除人数统计。
go 复制代码
package service

import (
	"UserManager/src/mapper"
	"UserManager/src/models"
	"UserManager/src/utils"
	"errors"
	"fmt"
	"golang.org/x/crypto/bcrypt"
	"io"
)

type UserService struct {
	Mapper *mapper.UserMapper
}

func NewUserService(hm *mapper.UserMapper) *UserService {
	return &UserService{
		Mapper: hm,
	}
}

// GetUsers 支持分页 + 搜索 + 状态筛选
func (us *UserService) GetUsers(keyword, statusStr string, page, pageSize int) ([]*models.User, int, error) {
	// 计算 offset
	offset := (page - 1) * pageSize
	// 委托 Mapper 执行查询并返回总数
	return us.Mapper.QueryUsersWithPage(keyword, statusStr, offset, pageSize)
}

// 新增用户
func (us *UserService) CreateUser(email, passwordHash, nickname string, avatarFile io.Reader, avatarFileName string, role, status int) (*models.User, error) {
	// 上传头像到 OSS
	avatarURL, err := utils.UploadFileToOSS(avatarFile, avatarFileName)
	if err != nil {
		return nil, err
	}
	// 检查邮箱是否已注册
	if user, _ := us.Mapper.GetUserByEmail(email); user != nil {
		return nil, errors.New("邮箱已注册,请使用其他邮箱")
	}
	// 加密密码
	hashed, err := bcrypt.GenerateFromPassword([]byte(passwordHash), bcrypt.DefaultCost)
	if err != nil {
		return nil, errors.New("密码加密失败")
	}
	user := &models.User{
		Email:        email,
		PasswordHash: string(hashed),
		Nickname:     nickname,
		AvatarUrl:    avatarURL,
		Role:         role,
		Status:       status,
	}
	if err := us.Mapper.CreateUser(user); err != nil {
		return nil, err
	}
	return user, nil
}

func (us *UserService) UpdateUser(id int, email, passwordHash, nickname string, avatarFile io.Reader, avatarFileName string, role, status int) (*models.User, error) {
	// 1. 先取出数据库中的原用户
	user, err := us.Mapper.GetUserByID(id)
	if err != nil {
		return nil, err
	}

	// 2. 如果邮箱被修改,检查是否重复
	if email != user.Email {
		if existing, _ := us.Mapper.GetUserByEmail(email); existing != nil {
			return nil, errors.New("邮箱已注册,请使用其他邮箱")
		}
	}

	// 3. 更新基本字段
	user.Email = email
	user.Nickname = nickname
	user.Role = role
	user.Status = status

	// 4. 如果前端传了非空密码,才加密并更新
	if passwordHash != "" {
		if !isValidPassword(passwordHash) {
			return nil, fmt.Errorf("密码必须是8-12位字母和数字组合")
		}
		hashed, err := bcrypt.GenerateFromPassword([]byte(passwordHash), bcrypt.DefaultCost)
		if err != nil {
			return nil, errors.New("密码加密失败")
		}
		user.PasswordHash = string(hashed)
	}

	// 5. 如果前端上传了新头像,才上传并更新 URL
	if avatarFile != nil {
		url, err := utils.UploadFileToOSS(avatarFile, avatarFileName)
		if err != nil {
			return nil, err
		}
		user.AvatarUrl = url
	}
	// 6. 写回数据库
	if err := us.Mapper.UpdateUser(user); err != nil {
		return nil, err
	}
	return user, nil
}

// 根据用户 ID 获取用户信息
func (us *UserService) GetUserByID(id int) (*models.User, error) {
	return us.Mapper.GetUserByID(id)
}

// 删除用户信息
func (us *UserService) DeleteUser(id int) error {
	return us.Mapper.DeleteUser(id)
}

用户统计与数据展示

首页统计信息展示
  1. 在系统首页展示一些关键的用户统计数据,如总用户数、本月登录人次、注销用户数量等。
    提供登录增长率、用户增长率、注销用户增长率等指标,帮助管理员了解系统的整体发展趋势
  2. 展示过去 30天的登录趋势图表,以日期为维度展示每日的登录次数,方便管理员观察登录量的变化趋势。
  3. 相关的统计信息(如今日登录人数、今日新增人数、今日被删除人数)会随着用户的登录、注册、删除等操作实时更新,确保数据的准确性和时效性。


go 复制代码
package service

import (
	"UserManager/src/mapper"
	"time"
)

type HomeService struct {
	Mapper *mapper.HomeMapper
}

// TrendData 用于返回给前端的访问趋势数据
type TrendData struct {
	Date  string `json:"date"`
	Count int    `json:"count"`
}

// 仪表数据
type DashboardData struct {
	RegisteredUsers        int     `json:"registered_users"`
	Visits                 int     `json:"visits"`
	DeactivatedUsers       int     `json:"deactivated_users"`
	RegisteredUsersGrowth  float64 `json:"registered_users_growth"`
	VisitsGrowth           float64 `json:"visits_growth"`
	DeactivatedUsersGrowth float64 `json:"deactivated_users_growth"`
}

func NewHomeService(hm *mapper.HomeMapper) *HomeService {
	return &HomeService{
		Mapper: hm,
	}
}

// 获取仪表盘统计数据
func (hs *HomeService) GetDashboardStats() (DashboardData, error) {
	// 获取当前时间
	now := time.Now()
	currentUsers, err := hs.Mapper.CountRegisteredUsers(now)

	if err != nil {
		return DashboardData{}, err
	}
	currentVisits, err := hs.Mapper.CountVisits(time.Now())

	if err != nil {
		return DashboardData{}, err
	}
	currentDeactivated, err := hs.Mapper.CountDeactivatedUsers(time.Now())

	if err != nil {
		return DashboardData{}, err
	}

	//获取上个月的数据

	// 获取当前年份和月份
	year, month, _ := now.Date()

	// 计算上个月的年份和月份
	if month == time.January {
		year--
		month = time.December
	} else {
		month--
	}

	// 获取上个月的第一天
	firstOfMonth := time.Date(year, month, 1, 0, 0, 0, 0, now.Location())

	// 上个月的最后一天是本月第一天的前一天
	lastMonth := firstOfMonth.AddDate(0, 1, -1)
	previousUsers, err := hs.Mapper.CountRegisteredUsers(lastMonth)
	if err != nil {
		return DashboardData{}, err
	}
	previousVisits, err := hs.Mapper.CountVisits(lastMonth)
	if err != nil {
		return DashboardData{}, err
	}
	previousDeactivated, err := hs.Mapper.CountDeactivatedUsers(lastMonth)
	if err != nil {
		return DashboardData{}, err
	}

	// 计算增长率
	usersGrowth := calculateGrowth(previousUsers, currentUsers)
	visitsGrowth := calculateGrowth(previousVisits, currentVisits)
	deactivatedGrowth := calculateGrowth(previousDeactivated, currentDeactivated)

	return DashboardData{
		RegisteredUsers:        currentUsers,
		Visits:                 currentVisits,
		DeactivatedUsers:       currentDeactivated,
		RegisteredUsersGrowth:  usersGrowth,
		VisitsGrowth:           visitsGrowth,
		DeactivatedUsersGrowth: deactivatedGrowth,
	}, nil
}

// calculateGrowth 计算增长率
func calculateGrowth(previous, current int) float64 {
	if previous == 0 {
		if current > 0 {
			return 100.0 // 从0增长到正数,视为100%增长
		}
		return 0.0 // 无变化
	}
	return (float64(current-previous) / float64(previous)) * 100
}
func (hs *HomeService) AddVisitCounts(userID int) error {
	err := hs.Mapper.AddVisitCounts(userID)
	if err != nil {
		return err
	}
	return nil
}

// 根据传入天数获取访问趋势数据
func (hs *HomeService) GetAccessTrends(days int) ([]TrendData, error) {
	// 计算起始时间(包含当天)
	startTime := time.Now().AddDate(0, 0, -days+1)

	visits, err := hs.Mapper.GetVisitsFrom(startTime)
	if err != nil {
		return nil, err
	}

	// 初始化每天的访问计数(key 为日期字符串)
	trendMap := make(map[string]int)
	for i := 0; i < days; i++ {
		dateStr := time.Now().AddDate(0, 0, -i).Format("2006-01-02")
		trendMap[dateStr] = 0
	}

	// 遍历访问记录进行计数
	for _, visit := range visits {
		dateStr := visit.VisitTime.Format("2006-01-02")
		trendMap[dateStr]++
	}

	// 按时间顺序组织返回数据(例如从最早到最新)
	var trends []TrendData
	for i := days - 1; i >= 0; i-- {
		date := time.Now().AddDate(0, 0, -i).Format("2006-01-02")
		trends = append(trends, TrendData{
			Date:  date,
			Count: trendMap[date],
		})
	}

	return trends, nil
}

具体代码看我github,https://github.com/cxzgit/UserManager

另外utils下的oss.go这里你配一下就好了

go 复制代码
package utils

import (
	"fmt"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"io"
	"time"
)

// UploadFileToOSS 上传文件到 OSS,并返回公开访问的 URL
func UploadFileToOSS(file io.Reader, fileName string) (string, error) {

	endpoint := ""
	accessKeyID := ""
	accessKeySecret := ""
	bucketName := ""

	client, err := oss.New(endpoint, accessKeyID, accessKeySecret)
	if err != nil {
		return "", fmt.Errorf("failed to create OSS client: %w", err)
	}
	bucket, err := client.Bucket(bucketName)
	if err != nil {
		return "", fmt.Errorf("failed to get OSS bucket: %w", err)
	}

	// 生成唯一的对象 key(例如:avatars/时间戳_原文件名)
	objectKey := fmt.Sprintf("avatars/%d_%s", time.Now().UnixNano(), fileName)

	if err := bucket.PutObject(objectKey, file); err != nil {
		return "", fmt.Errorf("failed to upload file: %w", err)
	}

	// 假设 bucket 为公共读,构造公开访问的 URL
	ossURL := fmt.Sprintf("https://%s.%s/%s", bucketName, endpoint, objectKey)
	return ossURL, nil

}
相关推荐
Luna_Lovegood_001几秒前
Qt QGraphicsScene 的用法
开发语言·qt
月忆3642 分钟前
Go语言接口实现面对对象的三大特征
开发语言·后端·golang
o0向阳而生0o10 分钟前
35、C# 中的反射(Reflection)
开发语言·c#·.net
程序员曼布16 分钟前
RabbitMQ 深度解析:从核心组件到复杂应用场景
java·开发语言·后端·rabbitmq
大G哥1 小时前
用 Java 和 DL4J 实现验证码识别系统
java·linux·开发语言·前端·python
science怪兽1 小时前
【进阶】C# 委托(Delegate)知识点总结归纳
开发语言·笔记·c#
Ya-Jun1 小时前
性能优化实践:性能监控体系
android·开发语言·flutter·ios·性能优化
forth touch2 小时前
C与指针——输入输出
c语言·开发语言
钢铁男儿3 小时前
Python基本语法(lambda表达式)
开发语言·python
Wabi_sabi_x3 小时前
C++设计模式:面向对象的八大设计原则之三
开发语言·c++·设计模式