Initial commit: Basic project structure and dependencies
This commit is contained in:
455
internal/domains/user/handlers/user_handler.go
Normal file
455
internal/domains/user/handlers/user_handler.go
Normal file
@@ -0,0 +1,455 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"tyapi-server/internal/domains/user/dto"
|
||||
"tyapi-server/internal/domains/user/services"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
"tyapi-server/internal/shared/middleware"
|
||||
)
|
||||
|
||||
// UserHandler 用户HTTP处理器
|
||||
type UserHandler struct {
|
||||
userService *services.UserService
|
||||
response interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
logger *zap.Logger
|
||||
jwtAuth *middleware.JWTAuthMiddleware
|
||||
}
|
||||
|
||||
// NewUserHandler 创建用户处理器
|
||||
func NewUserHandler(
|
||||
userService *services.UserService,
|
||||
response interfaces.ResponseBuilder,
|
||||
validator interfaces.RequestValidator,
|
||||
logger *zap.Logger,
|
||||
jwtAuth *middleware.JWTAuthMiddleware,
|
||||
) *UserHandler {
|
||||
return &UserHandler{
|
||||
userService: userService,
|
||||
response: response,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
jwtAuth: jwtAuth,
|
||||
}
|
||||
}
|
||||
|
||||
// GetPath 返回处理器路径
|
||||
func (h *UserHandler) GetPath() string {
|
||||
return "/users"
|
||||
}
|
||||
|
||||
// GetMethod 返回HTTP方法
|
||||
func (h *UserHandler) GetMethod() string {
|
||||
return "GET" // 主要用于列表,具体方法在路由注册时指定
|
||||
}
|
||||
|
||||
// GetMiddlewares 返回中间件
|
||||
func (h *UserHandler) GetMiddlewares() []gin.HandlerFunc {
|
||||
return []gin.HandlerFunc{
|
||||
// 这里可以添加特定的中间件
|
||||
}
|
||||
}
|
||||
|
||||
// Handle 主处理函数(用于列表)
|
||||
func (h *UserHandler) Handle(c *gin.Context) {
|
||||
h.List(c)
|
||||
}
|
||||
|
||||
// RequiresAuth 是否需要认证
|
||||
func (h *UserHandler) RequiresAuth() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetPermissions 获取所需权限
|
||||
func (h *UserHandler) GetPermissions() []string {
|
||||
return []string{"user:read"}
|
||||
}
|
||||
|
||||
// REST操作实现
|
||||
|
||||
// Create 创建用户
|
||||
func (h *UserHandler) Create(c *gin.Context) {
|
||||
var req dto.CreateUserRequest
|
||||
|
||||
// 验证请求体
|
||||
if err := h.validator.BindAndValidate(c, &req); err != nil {
|
||||
return // 响应已在验证器中处理
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
user, err := h.userService.Create(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to create user", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 返回响应
|
||||
response := dto.FromEntity(user)
|
||||
h.response.Created(c, response, "User created successfully")
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取用户
|
||||
func (h *UserHandler) GetByID(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
h.response.BadRequest(c, "User ID is required")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户
|
||||
user, err := h.userService.GetByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get user", zap.Error(err))
|
||||
h.response.NotFound(c, "User not found")
|
||||
return
|
||||
}
|
||||
|
||||
// 返回响应
|
||||
response := dto.FromEntity(user)
|
||||
h.response.Success(c, response)
|
||||
}
|
||||
|
||||
// Update 更新用户
|
||||
func (h *UserHandler) Update(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
h.response.BadRequest(c, "User ID is required")
|
||||
return
|
||||
}
|
||||
|
||||
var req dto.UpdateUserRequest
|
||||
|
||||
// 验证请求体
|
||||
if err := h.validator.BindAndValidate(c, &req); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新用户
|
||||
user, err := h.userService.Update(c.Request.Context(), id, &req)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to update user", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 返回响应
|
||||
response := dto.FromEntity(user)
|
||||
h.response.Success(c, response, "User updated successfully")
|
||||
}
|
||||
|
||||
// Delete 删除用户
|
||||
func (h *UserHandler) Delete(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
h.response.BadRequest(c, "User ID is required")
|
||||
return
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
if err := h.userService.Delete(c.Request.Context(), id); err != nil {
|
||||
h.logger.Error("Failed to delete user", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 返回响应
|
||||
h.response.Success(c, nil, "User deleted successfully")
|
||||
}
|
||||
|
||||
// List 获取用户列表
|
||||
func (h *UserHandler) List(c *gin.Context) {
|
||||
var req dto.UserListRequest
|
||||
|
||||
// 验证查询参数
|
||||
if err := h.validator.ValidateQuery(c, &req); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
|
||||
// 构建查询选项
|
||||
options := interfaces.ListOptions{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
Sort: req.Sort,
|
||||
Order: req.Order,
|
||||
Search: req.Search,
|
||||
Filters: req.Filters,
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
users, err := h.userService.List(c.Request.Context(), options)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get user list", zap.Error(err))
|
||||
h.response.InternalError(c, "Failed to get user list")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
countOptions := interfaces.CountOptions{
|
||||
Search: req.Search,
|
||||
Filters: req.Filters,
|
||||
}
|
||||
total, err := h.userService.Count(c.Request.Context(), countOptions)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to count users", zap.Error(err))
|
||||
h.response.InternalError(c, "Failed to count users")
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
userResponses := dto.FromEntities(users)
|
||||
pagination := buildPagination(req.Page, req.PageSize, total)
|
||||
|
||||
h.response.Paginated(c, userResponses, pagination)
|
||||
}
|
||||
|
||||
// Login 用户登录
|
||||
func (h *UserHandler) Login(c *gin.Context) {
|
||||
var req dto.LoginRequest
|
||||
|
||||
// 验证请求体
|
||||
if err := h.validator.BindAndValidate(c, &req); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 用户登录
|
||||
user, err := h.userService.Login(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("Login failed", zap.Error(err))
|
||||
h.response.Unauthorized(c, "Invalid credentials")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成JWT token
|
||||
accessToken, err := h.jwtAuth.GenerateToken(user.ID, user.Username, user.Email)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to generate token", zap.Error(err))
|
||||
h.response.InternalError(c, "Failed to generate access token")
|
||||
return
|
||||
}
|
||||
|
||||
// 构建登录响应
|
||||
loginResponse := &dto.LoginResponse{
|
||||
User: dto.FromEntity(user),
|
||||
AccessToken: accessToken,
|
||||
TokenType: "Bearer",
|
||||
ExpiresIn: 86400, // 24小时,从配置获取
|
||||
}
|
||||
|
||||
h.response.Success(c, loginResponse, "Login successful")
|
||||
}
|
||||
|
||||
// Logout 用户登出
|
||||
func (h *UserHandler) Logout(c *gin.Context) {
|
||||
// 简单实现,客户端删除token即可
|
||||
// 如果需要服务端黑名单,可以在这里实现
|
||||
h.response.Success(c, nil, "Logout successful")
|
||||
}
|
||||
|
||||
// GetProfile 获取当前用户信息
|
||||
func (h *UserHandler) GetProfile(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
user, err := h.userService.GetByID(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get user profile", zap.Error(err))
|
||||
h.response.NotFound(c, "User not found")
|
||||
return
|
||||
}
|
||||
|
||||
// 返回响应
|
||||
response := dto.FromEntity(user)
|
||||
h.response.Success(c, response)
|
||||
}
|
||||
|
||||
// UpdateProfile 更新当前用户信息
|
||||
func (h *UserHandler) UpdateProfile(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
var req dto.UpdateUserRequest
|
||||
|
||||
// 验证请求体
|
||||
if err := h.validator.BindAndValidate(c, &req); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新用户
|
||||
user, err := h.userService.Update(c.Request.Context(), userID, &req)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to update profile", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 返回响应
|
||||
response := dto.FromEntity(user)
|
||||
h.response.Success(c, response, "Profile updated successfully")
|
||||
}
|
||||
|
||||
// ChangePassword 修改密码
|
||||
func (h *UserHandler) ChangePassword(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
var req dto.ChangePasswordRequest
|
||||
|
||||
// 验证请求体
|
||||
if err := h.validator.BindAndValidate(c, &req); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
if err := h.userService.ChangePassword(c.Request.Context(), userID, &req); err != nil {
|
||||
h.logger.Error("Failed to change password", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, nil, "Password changed successfully")
|
||||
}
|
||||
|
||||
// Search 搜索用户
|
||||
func (h *UserHandler) Search(c *gin.Context) {
|
||||
var req dto.UserSearchRequest
|
||||
|
||||
// 验证查询参数
|
||||
if err := h.validator.ValidateQuery(c, &req); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = 10
|
||||
}
|
||||
|
||||
// 构建查询选项
|
||||
options := interfaces.ListOptions{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
Search: req.Query,
|
||||
}
|
||||
|
||||
// 搜索用户
|
||||
users, err := h.userService.Search(c.Request.Context(), req.Query, options)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to search users", zap.Error(err))
|
||||
h.response.InternalError(c, "Failed to search users")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取搜索结果总数
|
||||
countOptions := interfaces.CountOptions{
|
||||
Search: req.Query,
|
||||
}
|
||||
total, err := h.userService.Count(c.Request.Context(), countOptions)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to count search results", zap.Error(err))
|
||||
h.response.InternalError(c, "Failed to count search results")
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
userResponses := dto.FromEntities(users)
|
||||
pagination := buildPagination(req.Page, req.PageSize, total)
|
||||
|
||||
h.response.Paginated(c, userResponses, pagination)
|
||||
}
|
||||
|
||||
// GetStats 获取用户统计
|
||||
func (h *UserHandler) GetStats(c *gin.Context) {
|
||||
stats, err := h.userService.GetStats(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get user stats", zap.Error(err))
|
||||
h.response.InternalError(c, "Failed to get user statistics")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, stats)
|
||||
}
|
||||
|
||||
// 私有方法
|
||||
|
||||
// getCurrentUserID 获取当前用户ID
|
||||
func (h *UserHandler) getCurrentUserID(c *gin.Context) string {
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
if id, ok := userID.(string); ok {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// parsePageSize 解析页面大小
|
||||
func (h *UserHandler) parsePageSize(str string, defaultValue int) int {
|
||||
if str == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
if size, err := strconv.Atoi(str); err == nil && size > 0 && size <= 100 {
|
||||
return size
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// parsePage 解析页码
|
||||
func (h *UserHandler) parsePage(str string, defaultValue int) int {
|
||||
if str == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
if page, err := strconv.Atoi(str); err == nil && page > 0 {
|
||||
return page
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// buildPagination 构建分页元数据
|
||||
func buildPagination(page, pageSize int, total int64) interfaces.PaginationMeta {
|
||||
totalPages := int(float64(total) / float64(pageSize))
|
||||
if float64(total)/float64(pageSize) > float64(totalPages) {
|
||||
totalPages++
|
||||
}
|
||||
|
||||
if totalPages < 1 {
|
||||
totalPages = 1
|
||||
}
|
||||
|
||||
return interfaces.PaginationMeta{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Total: total,
|
||||
TotalPages: totalPages,
|
||||
HasNext: page < totalPages,
|
||||
HasPrev: page > 1,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user