main
			
			
		
		
							parent
							
								
									d236217c22
								
							
						
					
					
						commit
						b796dab689
					
				@ -0,0 +1,28 @@
 | 
				
			||||
# 环境变量配置示例
 | 
				
			||||
# 复制此文件为 .env 并填入真实配置
 | 
				
			||||
 | 
				
			||||
# 阿里云OSS配置
 | 
				
			||||
ALIYUN_OSS_ENDPOINT=your-endpoint
 | 
				
			||||
ALIYUN_OSS_ACCESS_KEY_ID=your-access-key-id
 | 
				
			||||
ALIYUN_OSS_ACCESS_KEY_SECRET=your-access-key-secret
 | 
				
			||||
ALIYUN_OSS_BUCKET_NAME=your-bucket-name
 | 
				
			||||
ALIYUN_OSS_URL_PREFIX=https://your-bucket-name.oss-region.aliyuncs.com/
 | 
				
			||||
 | 
				
			||||
# 数据库配置
 | 
				
			||||
DB_URL=jdbc:mysql://localhost:3306/UniLife?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
 | 
				
			||||
DB_USERNAME=root
 | 
				
			||||
DB_PASSWORD=123456
 | 
				
			||||
 | 
				
			||||
# Redis配置
 | 
				
			||||
REDIS_HOST=127.0.0.1
 | 
				
			||||
REDIS_PORT=6379
 | 
				
			||||
 | 
				
			||||
# JWT配置
 | 
				
			||||
JWT_SECRET=qwertyuiopasdfghjklzxcvbnm
 | 
				
			||||
JWT_EXPIRATION=86400
 | 
				
			||||
 | 
				
			||||
# 邮箱配置
 | 
				
			||||
MAIL_HOST=smtp.163.com
 | 
				
			||||
MAIL_PORT=465
 | 
				
			||||
MAIL_USERNAME=your-email@163.com
 | 
				
			||||
MAIL_PASSWORD=your-auth-code 
 | 
				
			||||
@ -0,0 +1,39 @@
 | 
				
			||||
package com.unilife.config;
 | 
				
			||||
 | 
				
			||||
import com.aliyun.oss.OSS;
 | 
				
			||||
import com.aliyun.oss.OSSClientBuilder;
 | 
				
			||||
import org.springframework.beans.factory.annotation.Value;
 | 
				
			||||
import org.springframework.context.annotation.Bean;
 | 
				
			||||
import org.springframework.context.annotation.Configuration;
 | 
				
			||||
 | 
				
			||||
@Configuration
 | 
				
			||||
public class OssConfig {
 | 
				
			||||
    
 | 
				
			||||
    @Value("${aliyun.oss.endpoint}")
 | 
				
			||||
    private String endpoint;
 | 
				
			||||
    
 | 
				
			||||
    @Value("${aliyun.oss.accessKeyId}")
 | 
				
			||||
    private String accessKeyId;
 | 
				
			||||
    
 | 
				
			||||
    @Value("${aliyun.oss.accessKeySecret}")
 | 
				
			||||
    private String accessKeySecret;
 | 
				
			||||
    
 | 
				
			||||
    @Value("${aliyun.oss.bucketName}")
 | 
				
			||||
    private String bucketName;
 | 
				
			||||
    
 | 
				
			||||
    @Value("${aliyun.oss.urlPrefix}")
 | 
				
			||||
    private String urlPrefix;
 | 
				
			||||
    
 | 
				
			||||
    @Bean
 | 
				
			||||
    public OSS ossClient() {
 | 
				
			||||
        return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    public String getBucketName() {
 | 
				
			||||
        return bucketName;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    public String getUrlPrefix() {
 | 
				
			||||
        return urlPrefix;
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,146 @@
 | 
				
			||||
package com.unilife.controller;
 | 
				
			||||
 | 
				
			||||
import com.unilife.common.result.Result;
 | 
				
			||||
import com.unilife.service.AdminService;
 | 
				
			||||
import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||
import io.swagger.v3.oas.annotations.tags.Tag;
 | 
				
			||||
import lombok.extern.slf4j.Slf4j;
 | 
				
			||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||
import org.springframework.web.bind.annotation.*;
 | 
				
			||||
 | 
				
			||||
import java.util.Map;
 | 
				
			||||
 | 
				
			||||
@Slf4j
 | 
				
			||||
@RestController
 | 
				
			||||
@RequestMapping("/admin")
 | 
				
			||||
@Tag(name = "管理员接口", description = "后台管理相关接口")
 | 
				
			||||
public class AdminController {
 | 
				
			||||
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private AdminService adminService;
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "获取系统统计数据")
 | 
				
			||||
    @GetMapping("/stats")
 | 
				
			||||
    public Result getSystemStats() {
 | 
				
			||||
        return adminService.getSystemStats();
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "获取用户列表")
 | 
				
			||||
    @GetMapping("/users")
 | 
				
			||||
    public Result getUserList(
 | 
				
			||||
            @RequestParam(defaultValue = "1") Integer page,
 | 
				
			||||
            @RequestParam(defaultValue = "10") Integer size,
 | 
				
			||||
            @RequestParam(required = false) String keyword,
 | 
				
			||||
            @RequestParam(required = false) Integer role,
 | 
				
			||||
            @RequestParam(required = false) Integer status) {
 | 
				
			||||
        return adminService.getUserList(page, size, keyword, role, status);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "更新用户状态")
 | 
				
			||||
    @PutMapping("/users/{userId}/status")
 | 
				
			||||
    public Result updateUserStatus(@PathVariable Long userId, @RequestBody Map<String, Integer> request) {
 | 
				
			||||
        Integer status = request.get("status");
 | 
				
			||||
        return adminService.updateUserStatus(userId, status);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "更新用户角色")
 | 
				
			||||
    @PutMapping("/users/{userId}/role")
 | 
				
			||||
    public Result updateUserRole(@PathVariable Long userId, @RequestBody Map<String, Integer> request) {
 | 
				
			||||
        Integer role = request.get("role");
 | 
				
			||||
        return adminService.updateUserRole(userId, role);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "删除用户")
 | 
				
			||||
    @DeleteMapping("/users/{userId}")
 | 
				
			||||
    public Result deleteUser(@PathVariable Long userId) {
 | 
				
			||||
        return adminService.deleteUser(userId);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "获取帖子列表")
 | 
				
			||||
    @GetMapping("/posts")
 | 
				
			||||
    public Result getPostList(
 | 
				
			||||
            @RequestParam(defaultValue = "1") Integer page,
 | 
				
			||||
            @RequestParam(defaultValue = "10") Integer size,
 | 
				
			||||
            @RequestParam(required = false) String keyword,
 | 
				
			||||
            @RequestParam(required = false) Long categoryId,
 | 
				
			||||
            @RequestParam(required = false) Integer status) {
 | 
				
			||||
        return adminService.getPostList(page, size, keyword, categoryId, status);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "更新帖子状态")
 | 
				
			||||
    @PutMapping("/posts/{postId}/status")
 | 
				
			||||
    public Result updatePostStatus(@PathVariable Long postId, @RequestBody Map<String, Integer> request) {
 | 
				
			||||
        Integer status = request.get("status");
 | 
				
			||||
        return adminService.updatePostStatus(postId, status);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "删除帖子")
 | 
				
			||||
    @DeleteMapping("/posts/{postId}")
 | 
				
			||||
    public Result deletePost(@PathVariable Long postId) {
 | 
				
			||||
        return adminService.deletePost(postId);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "永久删除帖子")
 | 
				
			||||
    @DeleteMapping("/posts/{postId}/permanent")
 | 
				
			||||
    public Result permanentDeletePost(@PathVariable Long postId) {
 | 
				
			||||
        return adminService.permanentDeletePost(postId);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "获取评论列表")
 | 
				
			||||
    @GetMapping("/comments")
 | 
				
			||||
    public Result getCommentList(
 | 
				
			||||
            @RequestParam(defaultValue = "1") Integer page,
 | 
				
			||||
            @RequestParam(defaultValue = "10") Integer size,
 | 
				
			||||
            @RequestParam(required = false) String keyword,
 | 
				
			||||
            @RequestParam(required = false) Long postId,
 | 
				
			||||
            @RequestParam(required = false) Integer status) {
 | 
				
			||||
        return adminService.getCommentList(page, size, keyword, postId, status);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "删除评论")
 | 
				
			||||
    @DeleteMapping("/comments/{commentId}")
 | 
				
			||||
    public Result deleteComment(@PathVariable Long commentId) {
 | 
				
			||||
        return adminService.deleteComment(commentId);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "获取分类列表")
 | 
				
			||||
    @GetMapping("/categories")
 | 
				
			||||
    public Result getCategoryList() {
 | 
				
			||||
        return adminService.getCategoryList();
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "创建分类")
 | 
				
			||||
    @PostMapping("/categories")
 | 
				
			||||
    public Result createCategory(@RequestBody Map<String, Object> request) {
 | 
				
			||||
        return adminService.createCategory(request);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "更新分类")
 | 
				
			||||
    @PutMapping("/categories/{categoryId}")
 | 
				
			||||
    public Result updateCategory(@PathVariable Long categoryId, @RequestBody Map<String, Object> request) {
 | 
				
			||||
        return adminService.updateCategory(categoryId, request);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "删除分类")
 | 
				
			||||
    @DeleteMapping("/categories/{categoryId}")
 | 
				
			||||
    public Result deleteCategory(@PathVariable Long categoryId) {
 | 
				
			||||
        return adminService.deleteCategory(categoryId);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "获取资源列表")
 | 
				
			||||
    @GetMapping("/resources")
 | 
				
			||||
    public Result getResourceList(
 | 
				
			||||
            @RequestParam(defaultValue = "1") Integer page,
 | 
				
			||||
            @RequestParam(defaultValue = "10") Integer size,
 | 
				
			||||
            @RequestParam(required = false) String keyword,
 | 
				
			||||
            @RequestParam(required = false) Long categoryId,
 | 
				
			||||
            @RequestParam(required = false) Integer status) {
 | 
				
			||||
        return adminService.getResourceList(page, size, keyword, categoryId, status);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Operation(summary = "删除资源")
 | 
				
			||||
    @DeleteMapping("/resources/{resourceId}")
 | 
				
			||||
    public Result deleteResource(@PathVariable Long resourceId) {
 | 
				
			||||
        return adminService.deleteResource(resourceId);
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,39 @@
 | 
				
			||||
package com.unilife.mapper;
 | 
				
			||||
 | 
				
			||||
import org.apache.ibatis.annotations.Mapper;
 | 
				
			||||
import org.apache.ibatis.annotations.Param;
 | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * 资源点赞数据访问层
 | 
				
			||||
 */
 | 
				
			||||
@Mapper
 | 
				
			||||
public interface ResourceLikeMapper {
 | 
				
			||||
    /**
 | 
				
			||||
     * 检查用户是否已点赞资源
 | 
				
			||||
     * @param resourceId 资源ID
 | 
				
			||||
     * @param userId 用户ID
 | 
				
			||||
     * @return 是否已点赞
 | 
				
			||||
     */
 | 
				
			||||
    boolean isLiked(@Param("resourceId") Long resourceId, @Param("userId") Long userId);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 添加点赞记录
 | 
				
			||||
     * @param resourceId 资源ID
 | 
				
			||||
     * @param userId 用户ID
 | 
				
			||||
     */
 | 
				
			||||
    void insert(@Param("resourceId") Long resourceId, @Param("userId") Long userId);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 删除点赞记录
 | 
				
			||||
     * @param resourceId 资源ID
 | 
				
			||||
     * @param userId 用户ID
 | 
				
			||||
     */
 | 
				
			||||
    void delete(@Param("resourceId") Long resourceId, @Param("userId") Long userId);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 获取资源的点赞用户数量
 | 
				
			||||
     * @param resourceId 资源ID
 | 
				
			||||
     * @return 点赞数量
 | 
				
			||||
     */
 | 
				
			||||
    int getLikeCount(@Param("resourceId") Long resourceId);
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,15 @@
 | 
				
			||||
package com.unilife.model.dto;
 | 
				
			||||
 | 
				
			||||
import lombok.AllArgsConstructor;
 | 
				
			||||
import lombok.Data;
 | 
				
			||||
import lombok.NoArgsConstructor;
 | 
				
			||||
 | 
				
			||||
@Data
 | 
				
			||||
@AllArgsConstructor
 | 
				
			||||
@NoArgsConstructor
 | 
				
			||||
public class AiUpdateSessionDTO {
 | 
				
			||||
    /**
 | 
				
			||||
     * 更新后的会话标题
 | 
				
			||||
     */
 | 
				
			||||
    private String title;
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,20 @@
 | 
				
			||||
package com.unilife.model.vo;
 | 
				
			||||
 | 
				
			||||
import lombok.AllArgsConstructor;
 | 
				
			||||
import lombok.Data;
 | 
				
			||||
import lombok.NoArgsConstructor;
 | 
				
			||||
 | 
				
			||||
@Data
 | 
				
			||||
@AllArgsConstructor
 | 
				
			||||
@NoArgsConstructor
 | 
				
			||||
public class AiCreateSessionVO {
 | 
				
			||||
    /**
 | 
				
			||||
     * 会话ID
 | 
				
			||||
     */
 | 
				
			||||
    private String sessionId;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 会话标题
 | 
				
			||||
     */
 | 
				
			||||
    private String title;
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,27 @@
 | 
				
			||||
package com.unilife.model.vo;
 | 
				
			||||
 | 
				
			||||
import lombok.AllArgsConstructor;
 | 
				
			||||
import lombok.Data;
 | 
				
			||||
import lombok.NoArgsConstructor;
 | 
				
			||||
 | 
				
			||||
import java.util.List;
 | 
				
			||||
 | 
				
			||||
@Data
 | 
				
			||||
@AllArgsConstructor
 | 
				
			||||
@NoArgsConstructor
 | 
				
			||||
public class AiMessageHistoryVO {
 | 
				
			||||
    /**
 | 
				
			||||
     * 消息列表
 | 
				
			||||
     */
 | 
				
			||||
    private List<AiMessageVO> messages;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 总数量
 | 
				
			||||
     */
 | 
				
			||||
    private Long total;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 会话信息
 | 
				
			||||
     */
 | 
				
			||||
    private AiSessionVO sessionInfo;
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,30 @@
 | 
				
			||||
package com.unilife.model.vo;
 | 
				
			||||
 | 
				
			||||
import lombok.AllArgsConstructor;
 | 
				
			||||
import lombok.Data;
 | 
				
			||||
import lombok.NoArgsConstructor;
 | 
				
			||||
 | 
				
			||||
@Data
 | 
				
			||||
@AllArgsConstructor
 | 
				
			||||
@NoArgsConstructor
 | 
				
			||||
public class AiMessageVO {
 | 
				
			||||
    /**
 | 
				
			||||
     * 消息ID
 | 
				
			||||
     */
 | 
				
			||||
    private String id;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 角色
 | 
				
			||||
     */
 | 
				
			||||
    private String role;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 消息内容
 | 
				
			||||
     */
 | 
				
			||||
    private String content;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 时间戳
 | 
				
			||||
     */
 | 
				
			||||
    private String timestamp;
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,22 @@
 | 
				
			||||
package com.unilife.model.vo;
 | 
				
			||||
 | 
				
			||||
import lombok.AllArgsConstructor;
 | 
				
			||||
import lombok.Data;
 | 
				
			||||
import lombok.NoArgsConstructor;
 | 
				
			||||
 | 
				
			||||
import java.util.List;
 | 
				
			||||
 | 
				
			||||
@Data
 | 
				
			||||
@AllArgsConstructor
 | 
				
			||||
@NoArgsConstructor
 | 
				
			||||
public class AiSessionListVO {
 | 
				
			||||
    /**
 | 
				
			||||
     * 会话列表
 | 
				
			||||
     */
 | 
				
			||||
    private List<AiSessionVO> sessions;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 总数量
 | 
				
			||||
     */
 | 
				
			||||
    private Long total;
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,31 @@
 | 
				
			||||
package com.unilife.model.vo;
 | 
				
			||||
 | 
				
			||||
import lombok.AllArgsConstructor;
 | 
				
			||||
import lombok.Data;
 | 
				
			||||
import lombok.NoArgsConstructor;
 | 
				
			||||
 | 
				
			||||
@Data
 | 
				
			||||
@AllArgsConstructor
 | 
				
			||||
@NoArgsConstructor
 | 
				
			||||
public class AiSessionVO {
 | 
				
			||||
    /**
 | 
				
			||||
     * 会话ID
 | 
				
			||||
     */
 | 
				
			||||
    private String id;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 会话标题
 | 
				
			||||
     */
 | 
				
			||||
    private String title;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 创建时间
 | 
				
			||||
     */
 | 
				
			||||
    private String createdAt;
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 更新时间
 | 
				
			||||
     */
 | 
				
			||||
    private String updatedAt;
 | 
				
			||||
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,93 @@
 | 
				
			||||
package com.unilife.service;
 | 
				
			||||
 | 
				
			||||
import com.unilife.common.result.Result;
 | 
				
			||||
 | 
				
			||||
import java.util.Map;
 | 
				
			||||
 | 
				
			||||
public interface AdminService {
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 获取系统统计数据
 | 
				
			||||
     */
 | 
				
			||||
    Result getSystemStats();
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 获取用户列表
 | 
				
			||||
     */
 | 
				
			||||
    Result getUserList(Integer page, Integer size, String keyword, Integer role, Integer status);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 更新用户状态
 | 
				
			||||
     */
 | 
				
			||||
    Result updateUserStatus(Long userId, Integer status);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 更新用户角色
 | 
				
			||||
     */
 | 
				
			||||
    Result updateUserRole(Long userId, Integer role);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 删除用户
 | 
				
			||||
     */
 | 
				
			||||
    Result deleteUser(Long userId);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 获取帖子列表
 | 
				
			||||
     */
 | 
				
			||||
    Result getPostList(Integer page, Integer size, String keyword, Long categoryId, Integer status);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 更新帖子状态
 | 
				
			||||
     */
 | 
				
			||||
    Result updatePostStatus(Long postId, Integer status);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 删除帖子
 | 
				
			||||
     */
 | 
				
			||||
    Result deletePost(Long postId);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 永久删除帖子
 | 
				
			||||
     */
 | 
				
			||||
    Result permanentDeletePost(Long postId);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 获取评论列表
 | 
				
			||||
     */
 | 
				
			||||
    Result getCommentList(Integer page, Integer size, String keyword, Long postId, Integer status);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 删除评论
 | 
				
			||||
     */
 | 
				
			||||
    Result deleteComment(Long commentId);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 获取分类列表
 | 
				
			||||
     */
 | 
				
			||||
    Result getCategoryList();
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 创建分类
 | 
				
			||||
     */
 | 
				
			||||
    Result createCategory(Map<String, Object> request);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 更新分类
 | 
				
			||||
     */
 | 
				
			||||
    Result updateCategory(Long categoryId, Map<String, Object> request);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 删除分类
 | 
				
			||||
     */
 | 
				
			||||
    Result deleteCategory(Long categoryId);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 获取资源列表
 | 
				
			||||
     */
 | 
				
			||||
    Result getResourceList(Integer page, Integer size, String keyword, Long categoryId, Integer status);
 | 
				
			||||
    
 | 
				
			||||
    /**
 | 
				
			||||
     * 删除资源
 | 
				
			||||
     */
 | 
				
			||||
    Result deleteResource(Long resourceId);
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,356 @@
 | 
				
			||||
package com.unilife.service.impl;
 | 
				
			||||
 | 
				
			||||
import com.unilife.common.result.Result;
 | 
				
			||||
import com.unilife.mapper.*;
 | 
				
			||||
import com.unilife.model.entity.*;
 | 
				
			||||
import com.unilife.service.AdminService;
 | 
				
			||||
import com.unilife.service.UserService;
 | 
				
			||||
import lombok.extern.slf4j.Slf4j;
 | 
				
			||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||
import org.springframework.stereotype.Service;
 | 
				
			||||
 | 
				
			||||
import java.util.HashMap;
 | 
				
			||||
import java.util.List;
 | 
				
			||||
import java.util.Map;
 | 
				
			||||
 | 
				
			||||
@Slf4j
 | 
				
			||||
@Service
 | 
				
			||||
public class AdminServiceImpl implements AdminService {
 | 
				
			||||
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private UserMapper userMapper;
 | 
				
			||||
    
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private PostMapper postMapper;
 | 
				
			||||
    
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private CommentMapper commentMapper;
 | 
				
			||||
    
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private CategoryMapper categoryMapper;
 | 
				
			||||
    
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private ResourceMapper resourceMapper;
 | 
				
			||||
    
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private UserService userService;
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result getSystemStats() {
 | 
				
			||||
        try {
 | 
				
			||||
            Map<String, Object> stats = new HashMap<>();
 | 
				
			||||
            
 | 
				
			||||
            // 用户统计
 | 
				
			||||
            stats.put("totalUsers", userMapper.getTotalCount());
 | 
				
			||||
            stats.put("activeUsers", userMapper.getActiveUserCount());
 | 
				
			||||
            stats.put("newUsersToday", userMapper.getNewUserCountToday());
 | 
				
			||||
            
 | 
				
			||||
            // 帖子统计
 | 
				
			||||
            stats.put("totalPosts", postMapper.getTotalCount());
 | 
				
			||||
            stats.put("newPostsToday", postMapper.getNewPostCountToday());
 | 
				
			||||
            
 | 
				
			||||
            // 评论统计
 | 
				
			||||
            stats.put("totalComments", commentMapper.getTotalCount());
 | 
				
			||||
            stats.put("newCommentsToday", commentMapper.getNewCommentCountToday());
 | 
				
			||||
            
 | 
				
			||||
            // 资源统计
 | 
				
			||||
            stats.put("totalResources", resourceMapper.getTotalCount());
 | 
				
			||||
            stats.put("newResourcesToday", resourceMapper.getNewResourceCountToday());
 | 
				
			||||
            
 | 
				
			||||
            // 分类统计
 | 
				
			||||
            stats.put("totalCategories", categoryMapper.getTotalCount());
 | 
				
			||||
            
 | 
				
			||||
            return Result.success(stats);
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("获取系统统计数据失败", e);
 | 
				
			||||
            return Result.error(500, "获取系统统计数据失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result getUserList(Integer page, Integer size, String keyword, Integer role, Integer status) {
 | 
				
			||||
        try {
 | 
				
			||||
            int offset = (page - 1) * size;
 | 
				
			||||
            List<User> users = userMapper.getAdminUserList(offset, size, keyword, role, status);
 | 
				
			||||
            int total = userMapper.getAdminUserCount(keyword, role, status);
 | 
				
			||||
            
 | 
				
			||||
            Map<String, Object> result = new HashMap<>();
 | 
				
			||||
            result.put("list", users);
 | 
				
			||||
            result.put("total", total);
 | 
				
			||||
            result.put("pages", (total + size - 1) / size);
 | 
				
			||||
            
 | 
				
			||||
            return Result.success(result);
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("获取用户列表失败", e);
 | 
				
			||||
            return Result.error(500, "获取用户列表失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result updateUserStatus(Long userId, Integer status) {
 | 
				
			||||
        try {
 | 
				
			||||
            User user = userMapper.getUserById(userId);
 | 
				
			||||
            if (user == null) {
 | 
				
			||||
                return Result.error(404, "用户不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            userMapper.updateUserStatus(userId, status);
 | 
				
			||||
            return Result.success(null, "用户状态更新成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("更新用户状态失败", e);
 | 
				
			||||
            return Result.error(500, "更新用户状态失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result updateUserRole(Long userId, Integer role) {
 | 
				
			||||
        try {
 | 
				
			||||
            User user = userMapper.getUserById(userId);
 | 
				
			||||
            if (user == null) {
 | 
				
			||||
                return Result.error(404, "用户不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            userMapper.updateUserRole(userId, role);
 | 
				
			||||
            return Result.success(null, "用户角色更新成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("更新用户角色失败", e);
 | 
				
			||||
            return Result.error(500, "更新用户角色失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result deleteUser(Long userId) {
 | 
				
			||||
        try {
 | 
				
			||||
            User user = userMapper.getUserById(userId);
 | 
				
			||||
            if (user == null) {
 | 
				
			||||
                return Result.error(404, "用户不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            // 检查是否为管理员
 | 
				
			||||
            if (user.getRole() == 2) {
 | 
				
			||||
                return Result.error(400, "不能删除管理员账号");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            // 调用UserService的完整删除逻辑
 | 
				
			||||
            return userService.deleteUser(userId);
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("删除用户失败", e);
 | 
				
			||||
            return Result.error(500, "删除用户失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result getPostList(Integer page, Integer size, String keyword, Long categoryId, Integer status) {
 | 
				
			||||
        try {
 | 
				
			||||
            int offset = (page - 1) * size;
 | 
				
			||||
            List<Post> posts = postMapper.getAdminPostList(offset, size, keyword, categoryId, status);
 | 
				
			||||
            int total = postMapper.getAdminPostCount(keyword, categoryId, status);
 | 
				
			||||
            
 | 
				
			||||
            Map<String, Object> result = new HashMap<>();
 | 
				
			||||
            result.put("list", posts);
 | 
				
			||||
            result.put("total", total);
 | 
				
			||||
            result.put("pages", (total + size - 1) / size);
 | 
				
			||||
            
 | 
				
			||||
            return Result.success(result);
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("获取帖子列表失败", e);
 | 
				
			||||
            return Result.error(500, "获取帖子列表失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result updatePostStatus(Long postId, Integer status) {
 | 
				
			||||
        try {
 | 
				
			||||
            Post post = postMapper.getPostById(postId);
 | 
				
			||||
            if (post == null) {
 | 
				
			||||
                return Result.error(404, "帖子不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            postMapper.updatePostStatus(postId, status);
 | 
				
			||||
            return Result.success(null, "帖子状态更新成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("更新帖子状态失败", e);
 | 
				
			||||
            return Result.error(500, "更新帖子状态失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result deletePost(Long postId) {
 | 
				
			||||
        try {
 | 
				
			||||
            Post post = postMapper.getPostById(postId);
 | 
				
			||||
            if (post == null) {
 | 
				
			||||
                return Result.error(404, "帖子不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            postMapper.deletePost(postId);
 | 
				
			||||
            return Result.success(null, "帖子删除成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("删除帖子失败", e);
 | 
				
			||||
            return Result.error(500, "删除帖子失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result permanentDeletePost(Long postId) {
 | 
				
			||||
        try {
 | 
				
			||||
            Post post = postMapper.getPostById(postId);
 | 
				
			||||
            if (post == null) {
 | 
				
			||||
                return Result.error(404, "帖子不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            // 永久删除帖子(物理删除)
 | 
				
			||||
            postMapper.permanentDeletePost(postId);
 | 
				
			||||
            return Result.success(null, "帖子永久删除成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("永久删除帖子失败", e);
 | 
				
			||||
            return Result.error(500, "永久删除帖子失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result getCommentList(Integer page, Integer size, String keyword, Long postId, Integer status) {
 | 
				
			||||
        try {
 | 
				
			||||
            int offset = (page - 1) * size;
 | 
				
			||||
            List<Comment> comments = commentMapper.getAdminCommentList(offset, size, keyword, postId, status);
 | 
				
			||||
            int total = commentMapper.getAdminCommentCount(keyword, postId, status);
 | 
				
			||||
            
 | 
				
			||||
            Map<String, Object> result = new HashMap<>();
 | 
				
			||||
            result.put("list", comments);
 | 
				
			||||
            result.put("total", total);
 | 
				
			||||
            result.put("pages", (total + size - 1) / size);
 | 
				
			||||
            
 | 
				
			||||
            return Result.success(result);
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("获取评论列表失败", e);
 | 
				
			||||
            return Result.error(500, "获取评论列表失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result deleteComment(Long commentId) {
 | 
				
			||||
        try {
 | 
				
			||||
            Comment comment = commentMapper.getCommentById(commentId);
 | 
				
			||||
            if (comment == null) {
 | 
				
			||||
                return Result.error(404, "评论不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            commentMapper.deleteComment(commentId);
 | 
				
			||||
            return Result.success(null, "评论删除成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("删除评论失败", e);
 | 
				
			||||
            return Result.error(500, "删除评论失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result getCategoryList() {
 | 
				
			||||
        try {
 | 
				
			||||
            List<Category> categories = categoryMapper.getAllCategories();
 | 
				
			||||
            return Result.success(categories);
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("获取分类列表失败", e);
 | 
				
			||||
            return Result.error(500, "获取分类列表失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result createCategory(Map<String, Object> request) {
 | 
				
			||||
        try {
 | 
				
			||||
            Category category = new Category();
 | 
				
			||||
            category.setName((String) request.get("name"));
 | 
				
			||||
            category.setDescription((String) request.get("description"));
 | 
				
			||||
            category.setIcon((String) request.get("icon"));
 | 
				
			||||
            category.setSort((Integer) request.get("sort"));
 | 
				
			||||
            Integer statusInt = (Integer) request.get("status");
 | 
				
			||||
            category.setStatus(statusInt != null ? statusInt.byteValue() : (byte) 1);
 | 
				
			||||
            
 | 
				
			||||
            categoryMapper.insertCategory(category);
 | 
				
			||||
            return Result.success(null, "分类创建成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("创建分类失败", e);
 | 
				
			||||
            return Result.error(500, "创建分类失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result updateCategory(Long categoryId, Map<String, Object> request) {
 | 
				
			||||
        try {
 | 
				
			||||
            Category category = categoryMapper.getCategoryById(categoryId);
 | 
				
			||||
            if (category == null) {
 | 
				
			||||
                return Result.error(404, "分类不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            category.setName((String) request.get("name"));
 | 
				
			||||
            category.setDescription((String) request.get("description"));
 | 
				
			||||
            category.setIcon((String) request.get("icon"));
 | 
				
			||||
            category.setSort((Integer) request.get("sort"));
 | 
				
			||||
            Integer statusInt = (Integer) request.get("status");
 | 
				
			||||
            category.setStatus(statusInt != null ? statusInt.byteValue() : (byte) 1);
 | 
				
			||||
            
 | 
				
			||||
            categoryMapper.updateCategory(category);
 | 
				
			||||
            return Result.success(null, "分类更新成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("更新分类失败", e);
 | 
				
			||||
            return Result.error(500, "更新分类失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result deleteCategory(Long categoryId) {
 | 
				
			||||
        try {
 | 
				
			||||
            Category category = categoryMapper.getCategoryById(categoryId);
 | 
				
			||||
            if (category == null) {
 | 
				
			||||
                return Result.error(404, "分类不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            // 检查是否有帖子或资源使用该分类
 | 
				
			||||
            int postCount = postMapper.getCountByCategoryId(categoryId);
 | 
				
			||||
            int resourceCount = resourceMapper.getCountByCategoryId(categoryId);
 | 
				
			||||
            
 | 
				
			||||
            if (postCount > 0 || resourceCount > 0) {
 | 
				
			||||
                return Result.error(400, "该分类下还有帖子或资源,无法删除");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            categoryMapper.deleteCategory(categoryId);
 | 
				
			||||
            return Result.success(null, "分类删除成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("删除分类失败", e);
 | 
				
			||||
            return Result.error(500, "删除分类失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result getResourceList(Integer page, Integer size, String keyword, Long categoryId, Integer status) {
 | 
				
			||||
        try {
 | 
				
			||||
            int offset = (page - 1) * size;
 | 
				
			||||
            List<Resource> resources = resourceMapper.getAdminResourceList(offset, size, keyword, categoryId, status);
 | 
				
			||||
            int total = resourceMapper.getAdminResourceCount(keyword, categoryId, status);
 | 
				
			||||
            
 | 
				
			||||
            Map<String, Object> result = new HashMap<>();
 | 
				
			||||
            result.put("list", resources);
 | 
				
			||||
            result.put("total", total);
 | 
				
			||||
            result.put("pages", (total + size - 1) / size);
 | 
				
			||||
            
 | 
				
			||||
            return Result.success(result);
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("获取资源列表失败", e);
 | 
				
			||||
            return Result.error(500, "获取资源列表失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public Result deleteResource(Long resourceId) {
 | 
				
			||||
        try {
 | 
				
			||||
            Resource resource = resourceMapper.getResourceById(resourceId);
 | 
				
			||||
            if (resource == null) {
 | 
				
			||||
                return Result.error(404, "资源不存在");
 | 
				
			||||
            }
 | 
				
			||||
            
 | 
				
			||||
            resourceMapper.deleteResource(resourceId);
 | 
				
			||||
            return Result.success(null, "资源删除成功");
 | 
				
			||||
        } catch (Exception e) {
 | 
				
			||||
            log.error("删除资源失败", e);
 | 
				
			||||
            return Result.error(500, "删除资源失败");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,87 @@
 | 
				
			||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 | 
				
			||||
<mapper namespace="com.unilife.mapper.AiChatSessionMapper">
 | 
				
			||||
    
 | 
				
			||||
    <!-- 结果映射 -->
 | 
				
			||||
    <resultMap id="AiChatSessionResultMap" type="com.unilife.model.entity.AiChatSession">
 | 
				
			||||
        <id column="id" property="id"/>
 | 
				
			||||
        <result column="user_id" property="userId"/>
 | 
				
			||||
        <result column="title" property="title"/>
 | 
				
			||||
        <result column="created_at" property="createdAt"/>
 | 
				
			||||
        <result column="updated_at" property="updatedAt"/>
 | 
				
			||||
    </resultMap>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 插入会话 -->
 | 
				
			||||
    <insert id="insert" parameterType="com.unilife.model.entity.AiChatSession">
 | 
				
			||||
        INSERT INTO ai_chat_sessions (
 | 
				
			||||
            id, user_id, title, created_at, updated_at
 | 
				
			||||
        ) VALUES (
 | 
				
			||||
            #{id}, #{userId}, #{title}, #{createdAt}, #{updatedAt}
 | 
				
			||||
        )
 | 
				
			||||
    </insert>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 根据ID查询会话 -->
 | 
				
			||||
    <select id="selectById" resultMap="AiChatSessionResultMap">
 | 
				
			||||
        SELECT id, user_id, title, created_at, updated_at
 | 
				
			||||
        FROM ai_chat_sessions
 | 
				
			||||
        WHERE id = #{id}
 | 
				
			||||
    </select>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 根据用户ID分页查询会话列表 -->
 | 
				
			||||
    <select id="selectByUserId" resultMap="AiChatSessionResultMap">
 | 
				
			||||
        SELECT id, user_id, title, created_at, updated_at
 | 
				
			||||
        FROM ai_chat_sessions
 | 
				
			||||
        WHERE user_id = #{userId}
 | 
				
			||||
        ORDER BY updated_at DESC
 | 
				
			||||
        LIMIT #{offset}, #{limit}
 | 
				
			||||
    </select>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 查询匿名会话列表 -->
 | 
				
			||||
    <select id="selectAnonymousSessions" resultMap="AiChatSessionResultMap">
 | 
				
			||||
        SELECT id, user_id, title, created_at, updated_at
 | 
				
			||||
        FROM ai_chat_sessions
 | 
				
			||||
        WHERE user_id IS NULL
 | 
				
			||||
        ORDER BY updated_at DESC
 | 
				
			||||
        LIMIT #{offset}, #{limit}
 | 
				
			||||
    </select>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 统计用户会话总数 -->
 | 
				
			||||
    <select id="countByUserId" resultType="long">
 | 
				
			||||
        SELECT COUNT(*)
 | 
				
			||||
        FROM ai_chat_sessions
 | 
				
			||||
        WHERE user_id = #{userId}
 | 
				
			||||
    </select>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 统计匿名会话总数 -->
 | 
				
			||||
    <select id="countAnonymousSessions" resultType="long">
 | 
				
			||||
        SELECT COUNT(*)
 | 
				
			||||
        FROM ai_chat_sessions
 | 
				
			||||
        WHERE user_id IS NULL
 | 
				
			||||
    </select>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 更新会话标题 -->
 | 
				
			||||
    <update id="updateTitle">
 | 
				
			||||
        UPDATE ai_chat_sessions
 | 
				
			||||
        SET title = #{title}, updated_at = CURRENT_TIMESTAMP
 | 
				
			||||
        WHERE id = #{id}
 | 
				
			||||
    </update>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 更新会话的最后消息时间和消息数量(简化方案中保留方法但不使用) -->
 | 
				
			||||
    <update id="updateMessageInfo">
 | 
				
			||||
        UPDATE ai_chat_sessions
 | 
				
			||||
        SET updated_at = #{lastMessageTime}
 | 
				
			||||
        WHERE id = #{id}
 | 
				
			||||
    </update>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 删除会话 -->
 | 
				
			||||
    <delete id="deleteById">
 | 
				
			||||
        DELETE FROM ai_chat_sessions WHERE id = #{id}
 | 
				
			||||
    </delete>
 | 
				
			||||
    
 | 
				
			||||
    <!-- 批量删除过期会话 -->
 | 
				
			||||
    <delete id="deleteExpiredSessions">
 | 
				
			||||
        DELETE FROM ai_chat_sessions 
 | 
				
			||||
        WHERE updated_at < #{expireTime}
 | 
				
			||||
    </delete>
 | 
				
			||||
    
 | 
				
			||||
</mapper> 
 | 
				
			||||
@ -0,0 +1,25 @@
 | 
				
			||||
<?xml version="1.0" encoding="UTF-8" ?>
 | 
				
			||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 | 
				
			||||
<mapper namespace="com.unilife.mapper.ResourceLikeMapper">
 | 
				
			||||
    <select id="isLiked" resultType="boolean">
 | 
				
			||||
        SELECT COUNT(*) > 0
 | 
				
			||||
        FROM resource_likes
 | 
				
			||||
        WHERE resource_id = #{resourceId} AND user_id = #{userId}
 | 
				
			||||
    </select>
 | 
				
			||||
    
 | 
				
			||||
    <insert id="insert">
 | 
				
			||||
        INSERT INTO resource_likes (resource_id, user_id, created_at)
 | 
				
			||||
        VALUES (#{resourceId}, #{userId}, NOW())
 | 
				
			||||
    </insert>
 | 
				
			||||
    
 | 
				
			||||
    <delete id="delete">
 | 
				
			||||
        DELETE FROM resource_likes
 | 
				
			||||
        WHERE resource_id = #{resourceId} AND user_id = #{userId}
 | 
				
			||||
    </delete>
 | 
				
			||||
    
 | 
				
			||||
    <select id="getLikeCount" resultType="int">
 | 
				
			||||
        SELECT COUNT(*)
 | 
				
			||||
        FROM resource_likes
 | 
				
			||||
        WHERE resource_id = #{resourceId}
 | 
				
			||||
    </select>
 | 
				
			||||
</mapper> 
 | 
				
			||||
@ -0,0 +1,80 @@
 | 
				
			||||
package com.unilife.config;
 | 
				
			||||
 | 
				
			||||
import org.springframework.boot.test.context.TestConfiguration;
 | 
				
			||||
import org.springframework.context.annotation.Bean;
 | 
				
			||||
import org.springframework.context.annotation.Primary;
 | 
				
			||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
 | 
				
			||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
 | 
				
			||||
import org.springframework.data.redis.core.RedisTemplate;
 | 
				
			||||
import org.springframework.data.redis.core.StringRedisTemplate;
 | 
				
			||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
 | 
				
			||||
import org.springframework.mail.javamail.JavaMailSender;
 | 
				
			||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
 | 
				
			||||
 | 
				
			||||
import java.util.Properties;
 | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * 测试配置类
 | 
				
			||||
 * 为测试环境提供特定的Bean配置
 | 
				
			||||
 */
 | 
				
			||||
@TestConfiguration
 | 
				
			||||
public class TestConfig {
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 测试用的Redis连接工厂
 | 
				
			||||
     */
 | 
				
			||||
    @Bean
 | 
				
			||||
    @Primary
 | 
				
			||||
    public RedisConnectionFactory testRedisConnectionFactory() {
 | 
				
			||||
        LettuceConnectionFactory factory = new LettuceConnectionFactory("localhost", 6379);
 | 
				
			||||
        factory.setDatabase(1); // 使用数据库1进行测试
 | 
				
			||||
        return factory;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 测试用的RedisTemplate
 | 
				
			||||
     */
 | 
				
			||||
    @Bean
 | 
				
			||||
    @Primary
 | 
				
			||||
    public RedisTemplate<String, Object> testRedisTemplate(RedisConnectionFactory connectionFactory) {
 | 
				
			||||
        RedisTemplate<String, Object> template = new RedisTemplate<>();
 | 
				
			||||
        template.setConnectionFactory(connectionFactory);
 | 
				
			||||
        template.setKeySerializer(new StringRedisSerializer());
 | 
				
			||||
        template.setValueSerializer(new StringRedisSerializer());
 | 
				
			||||
        template.setHashKeySerializer(new StringRedisSerializer());
 | 
				
			||||
        template.setHashValueSerializer(new StringRedisSerializer());
 | 
				
			||||
        return template;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 测试用的StringRedisTemplate
 | 
				
			||||
     */
 | 
				
			||||
    @Bean
 | 
				
			||||
    @Primary
 | 
				
			||||
    public StringRedisTemplate testStringRedisTemplate(RedisConnectionFactory connectionFactory) {
 | 
				
			||||
        StringRedisTemplate template = new StringRedisTemplate();
 | 
				
			||||
        template.setConnectionFactory(connectionFactory);
 | 
				
			||||
        return template;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 测试用的邮件发送器
 | 
				
			||||
     */
 | 
				
			||||
    @Bean
 | 
				
			||||
    @Primary
 | 
				
			||||
    public JavaMailSender testJavaMailSender() {
 | 
				
			||||
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
 | 
				
			||||
        mailSender.setHost("smtp.example.com");
 | 
				
			||||
        mailSender.setPort(587);
 | 
				
			||||
        mailSender.setUsername("test@example.com");
 | 
				
			||||
        mailSender.setPassword("testpassword");
 | 
				
			||||
 | 
				
			||||
        Properties props = mailSender.getJavaMailProperties();
 | 
				
			||||
        props.put("mail.transport.protocol", "smtp");
 | 
				
			||||
        props.put("mail.smtp.auth", "true");
 | 
				
			||||
        props.put("mail.smtp.starttls.enable", "true");
 | 
				
			||||
        props.put("mail.debug", "false"); // 测试时关闭debug
 | 
				
			||||
 | 
				
			||||
        return mailSender;
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,169 @@
 | 
				
			||||
package com.unilife.controller;
 | 
				
			||||
 | 
				
			||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
				
			||||
import com.unilife.common.result.Result;
 | 
				
			||||
import com.unilife.model.dto.CreatePostDTO;
 | 
				
			||||
import com.unilife.model.dto.UpdatePostDTO;
 | 
				
			||||
import com.unilife.service.PostService;
 | 
				
			||||
import com.unilife.utils.BaseContext;
 | 
				
			||||
import org.junit.jupiter.api.BeforeEach;
 | 
				
			||||
import org.junit.jupiter.api.Test;
 | 
				
			||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
 | 
				
			||||
import org.springframework.boot.test.mock.mockito.MockBean;
 | 
				
			||||
import org.springframework.http.MediaType;
 | 
				
			||||
import org.springframework.test.web.servlet.MockMvc;
 | 
				
			||||
 | 
				
			||||
import static org.mockito.ArgumentMatchers.*;
 | 
				
			||||
import static org.mockito.Mockito.*;
 | 
				
			||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 | 
				
			||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
 | 
				
			||||
 | 
				
			||||
@WebMvcTest(PostController.class)
 | 
				
			||||
class PostControllerTest {
 | 
				
			||||
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private MockMvc mockMvc;
 | 
				
			||||
 | 
				
			||||
    @MockBean
 | 
				
			||||
    private PostService postService;
 | 
				
			||||
 | 
				
			||||
    @Autowired
 | 
				
			||||
    private ObjectMapper objectMapper;
 | 
				
			||||
 | 
				
			||||
    private CreatePostDTO createPostDTO;
 | 
				
			||||
    private UpdatePostDTO updatePostDTO;
 | 
				
			||||
 | 
				
			||||
    @BeforeEach
 | 
				
			||||
    void setUp() {
 | 
				
			||||
        createPostDTO = new CreatePostDTO();
 | 
				
			||||
        createPostDTO.setTitle("测试帖子");
 | 
				
			||||
        createPostDTO.setContent("测试内容");
 | 
				
			||||
        createPostDTO.setCategoryId(1L);
 | 
				
			||||
 | 
				
			||||
        updatePostDTO = new UpdatePostDTO();
 | 
				
			||||
        updatePostDTO.setTitle("更新标题");
 | 
				
			||||
        updatePostDTO.setContent("更新内容");
 | 
				
			||||
        updatePostDTO.setCategoryId(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreatePost_Success() throws Exception {
 | 
				
			||||
        // Mock用户已登录
 | 
				
			||||
        try (var mockedStatic = mockStatic(BaseContext.class)) {
 | 
				
			||||
            mockedStatic.when(BaseContext::getId).thenReturn(1L);
 | 
				
			||||
            
 | 
				
			||||
            when(postService.createPost(eq(1L), any(CreatePostDTO.class)))
 | 
				
			||||
                .thenReturn(Result.success("帖子发布成功"));
 | 
				
			||||
 | 
				
			||||
            mockMvc.perform(post("/posts")
 | 
				
			||||
                    .contentType(MediaType.APPLICATION_JSON)
 | 
				
			||||
                    .content(objectMapper.writeValueAsString(createPostDTO)))
 | 
				
			||||
                    .andExpect(status().isOk())
 | 
				
			||||
                    .andExpect(jsonPath("$.success").value(true))
 | 
				
			||||
                    .andExpect(jsonPath("$.message").value("帖子发布成功"));
 | 
				
			||||
 | 
				
			||||
            verify(postService).createPost(eq(1L), any(CreatePostDTO.class));
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreatePost_Unauthorized() throws Exception {
 | 
				
			||||
        // Mock用户未登录
 | 
				
			||||
        try (var mockedStatic = mockStatic(BaseContext.class)) {
 | 
				
			||||
            mockedStatic.when(BaseContext::getId).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
            mockMvc.perform(post("/posts")
 | 
				
			||||
                    .contentType(MediaType.APPLICATION_JSON)
 | 
				
			||||
                    .content(objectMapper.writeValueAsString(createPostDTO)))
 | 
				
			||||
                    .andExpect(status().isOk())
 | 
				
			||||
                    .andExpected(jsonPath("$.success").value(false))
 | 
				
			||||
                    .andExpected(jsonPath("$.code").value(401))
 | 
				
			||||
                    .andExpected(jsonPath("$.message").value("未登录"));
 | 
				
			||||
 | 
				
			||||
            verify(postService, never()).createPost(anyLong(), any(CreatePostDTO.class));
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetPostDetail_Success() throws Exception {
 | 
				
			||||
        when(postService.getPostDetail(eq(1L), any()))
 | 
				
			||||
            .thenReturn(Result.success("帖子详情"));
 | 
				
			||||
 | 
				
			||||
        mockMvc.perform(get("/posts/1"))
 | 
				
			||||
                .andExpect(status().isOk())
 | 
				
			||||
                .andExpected(jsonPath("$.success").value(true));
 | 
				
			||||
 | 
				
			||||
        verify(postService).getPostDetail(eq(1L), any());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetPostList_Success() throws Exception {
 | 
				
			||||
        when(postService.getPostList(any(), any(), anyInt(), anyInt(), any(), any()))
 | 
				
			||||
            .thenReturn(Result.success("帖子列表"));
 | 
				
			||||
 | 
				
			||||
        mockMvc.perform(get("/posts")
 | 
				
			||||
                .param("categoryId", "1")
 | 
				
			||||
                .param("keyword", "测试")
 | 
				
			||||
                .param("page", "1")
 | 
				
			||||
                .param("size", "10")
 | 
				
			||||
                .param("sort", "latest"))
 | 
				
			||||
                .andExpected(status().isOk())
 | 
				
			||||
                .andExpected(jsonPath("$.success").value(true));
 | 
				
			||||
 | 
				
			||||
        verify(postService).getPostList(eq(1L), eq("测试"), eq(1), eq(10), eq("latest"), any());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUpdatePost_Success() throws Exception {
 | 
				
			||||
        try (var mockedStatic = mockStatic(BaseContext.class)) {
 | 
				
			||||
            mockedStatic.when(BaseContext::getId).thenReturn(1L);
 | 
				
			||||
            
 | 
				
			||||
            when(postService.updatePost(eq(1L), eq(1L), any(UpdatePostDTO.class)))
 | 
				
			||||
                .thenReturn(Result.success("帖子更新成功"));
 | 
				
			||||
 | 
				
			||||
            mockMvc.perform(put("/posts/1")
 | 
				
			||||
                    .contentType(MediaType.APPLICATION_JSON)
 | 
				
			||||
                    .content(objectMapper.writeValueAsString(updatePostDTO)))
 | 
				
			||||
                    .andExpected(status().isOk())
 | 
				
			||||
                    .andExpected(jsonPath("$.success").value(true))
 | 
				
			||||
                    .andExpected(jsonPath("$.message").value("帖子更新成功"));
 | 
				
			||||
 | 
				
			||||
            verify(postService).updatePost(eq(1L), eq(1L), any(UpdatePostDTO.class));
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testDeletePost_Success() throws Exception {
 | 
				
			||||
        try (var mockedStatic = mockStatic(BaseContext.class)) {
 | 
				
			||||
            mockedStatic.when(BaseContext::getId).thenReturn(1L);
 | 
				
			||||
            
 | 
				
			||||
            when(postService.deletePost(eq(1L), eq(1L)))
 | 
				
			||||
                .thenReturn(Result.success("帖子删除成功"));
 | 
				
			||||
 | 
				
			||||
            mockMvc.perform(delete("/posts/1"))
 | 
				
			||||
                    .andExpected(status().isOk())
 | 
				
			||||
                    .andExpected(jsonPath("$.success").value(true))
 | 
				
			||||
                    .andExpected(jsonPath("$.message").value("帖子删除成功"));
 | 
				
			||||
 | 
				
			||||
            verify(postService).deletePost(eq(1L), eq(1L));
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testLikePost_Success() throws Exception {
 | 
				
			||||
        try (var mockedStatic = mockStatic(BaseContext.class)) {
 | 
				
			||||
            mockedStatic.when(BaseContext::getId).thenReturn(1L);
 | 
				
			||||
            
 | 
				
			||||
            when(postService.likePost(eq(1L), eq(1L)))
 | 
				
			||||
                .thenReturn(Result.success("点赞成功"));
 | 
				
			||||
 | 
				
			||||
            mockMvc.perform(post("/posts/1/like"))
 | 
				
			||||
                    .andExpected(status().isOk())
 | 
				
			||||
                    .andExpected(jsonPath("$.success").value(true))
 | 
				
			||||
                    .andExpected(jsonPath("$.message").value("点赞成功"));
 | 
				
			||||
 | 
				
			||||
            verify(postService).likePost(eq(1L), eq(1L));
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,287 @@
 | 
				
			||||
package com.unilife.service;
 | 
				
			||||
 | 
				
			||||
import com.unilife.common.result.Result;
 | 
				
			||||
import com.unilife.mapper.PostMapper;
 | 
				
			||||
import com.unilife.mapper.UserMapper;
 | 
				
			||||
import com.unilife.mapper.CategoryMapper;
 | 
				
			||||
import com.unilife.model.dto.CreatePostDTO;
 | 
				
			||||
import com.unilife.model.dto.UpdatePostDTO;
 | 
				
			||||
import com.unilife.model.entity.Post;
 | 
				
			||||
import com.unilife.model.entity.User;
 | 
				
			||||
import com.unilife.model.entity.Category;
 | 
				
			||||
import com.unilife.service.impl.PostServiceImpl;
 | 
				
			||||
import org.junit.jupiter.api.BeforeEach;
 | 
				
			||||
import org.junit.jupiter.api.Test;
 | 
				
			||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
				
			||||
import org.mockito.InjectMocks;
 | 
				
			||||
import org.mockito.Mock;
 | 
				
			||||
import org.mockito.junit.jupiter.MockitoExtension;
 | 
				
			||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
				
			||||
 | 
				
			||||
import java.time.LocalDateTime;
 | 
				
			||||
import java.util.Arrays;
 | 
				
			||||
import java.util.List;
 | 
				
			||||
 | 
				
			||||
import static org.junit.jupiter.api.Assertions.*;
 | 
				
			||||
import static org.mockito.ArgumentMatchers.*;
 | 
				
			||||
import static org.mockito.Mockito.*;
 | 
				
			||||
 | 
				
			||||
@ExtendWith(MockitoExtension.class)
 | 
				
			||||
@SpringBootTest
 | 
				
			||||
class PostServiceTest {
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private PostMapper postMapper;
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private UserMapper userMapper;
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private CategoryMapper categoryMapper;
 | 
				
			||||
 | 
				
			||||
    @InjectMocks
 | 
				
			||||
    private PostServiceImpl postService;
 | 
				
			||||
 | 
				
			||||
    private User testUser;
 | 
				
			||||
    private Category testCategory;
 | 
				
			||||
    private Post testPost;
 | 
				
			||||
    private CreatePostDTO createPostDTO;
 | 
				
			||||
    private UpdatePostDTO updatePostDTO;
 | 
				
			||||
 | 
				
			||||
    @BeforeEach
 | 
				
			||||
    void setUp() {
 | 
				
			||||
        // 初始化测试数据
 | 
				
			||||
        testUser = new User();
 | 
				
			||||
        testUser.setId(1L);
 | 
				
			||||
        testUser.setNickname("测试用户");
 | 
				
			||||
        testUser.setAvatar("avatar.jpg");
 | 
				
			||||
 | 
				
			||||
        testCategory = new Category();
 | 
				
			||||
        testCategory.setId(1L);
 | 
				
			||||
        testCategory.setName("学习讨论");
 | 
				
			||||
        testCategory.setStatus(1);
 | 
				
			||||
 | 
				
			||||
        testPost = new Post();
 | 
				
			||||
        testPost.setId(1L);
 | 
				
			||||
        testPost.setTitle("测试帖子");
 | 
				
			||||
        testPost.setContent("这是一个测试帖子的内容");
 | 
				
			||||
        testPost.setUserId(1L);
 | 
				
			||||
        testPost.setCategoryId(1L);
 | 
				
			||||
        testPost.setLikeCount(0);
 | 
				
			||||
        testPost.setViewCount(0);
 | 
				
			||||
        testPost.setCommentCount(0);
 | 
				
			||||
        testPost.setCreatedAt(LocalDateTime.now());
 | 
				
			||||
        testPost.setUpdatedAt(LocalDateTime.now());
 | 
				
			||||
 | 
				
			||||
        createPostDTO = new CreatePostDTO();
 | 
				
			||||
        createPostDTO.setTitle("新帖子标题");
 | 
				
			||||
        createPostDTO.setContent("新帖子内容");
 | 
				
			||||
        createPostDTO.setCategoryId(1L);
 | 
				
			||||
 | 
				
			||||
        updatePostDTO = new UpdatePostDTO();
 | 
				
			||||
        updatePostDTO.setTitle("更新后的标题");
 | 
				
			||||
        updatePostDTO.setContent("更新后的内容");
 | 
				
			||||
        updatePostDTO.setCategoryId(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreatePost_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(categoryMapper.findById(1L)).thenReturn(testCategory);
 | 
				
			||||
        when(postMapper.insert(any(Post.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.createPost(1L, createPostDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("帖子发布成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(userMapper).findById(1L);
 | 
				
			||||
        verify(categoryMapper).findById(1L);
 | 
				
			||||
        verify(postMapper).insert(any(Post.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreatePost_UserNotFound() {
 | 
				
			||||
        // Mock 用户不存在
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.createPost(1L, createPostDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("用户不存在", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证不会尝试创建帖子
 | 
				
			||||
        verify(postMapper, never()).insert(any(Post.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreatePost_CategoryNotFound() {
 | 
				
			||||
        // Mock 用户存在但分类不存在
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(categoryMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.createPost(1L, createPostDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("分类不存在", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreatePost_InvalidTitle() {
 | 
				
			||||
        // 测试空标题
 | 
				
			||||
        createPostDTO.setTitle("");
 | 
				
			||||
        
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.createPost(1L, createPostDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertTrue(result.getMessage().contains("标题不能为空"));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetPostDetail_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(postMapper.findById(1L)).thenReturn(testPost);
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(categoryMapper.findById(1L)).thenReturn(testCategory);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.getPostDetail(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
 | 
				
			||||
        // 验证浏览量增加
 | 
				
			||||
        verify(postMapper).updateViewCount(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetPostDetail_PostNotFound() {
 | 
				
			||||
        // Mock 帖子不存在
 | 
				
			||||
        when(postMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.getPostDetail(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("帖子不存在", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetPostList_Success() {
 | 
				
			||||
        // Mock 帖子列表
 | 
				
			||||
        List<Post> posts = Arrays.asList(testPost);
 | 
				
			||||
        when(postMapper.findByConditions(any(), any(), anyInt(), anyInt(), any())).thenReturn(posts);
 | 
				
			||||
        when(postMapper.countByConditions(any(), any())).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.getPostList(1L, "测试", 1, 10, "latest", 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUpdatePost_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(postMapper.findById(1L)).thenReturn(testPost);
 | 
				
			||||
        when(categoryMapper.findById(1L)).thenReturn(testCategory);
 | 
				
			||||
        when(postMapper.update(any(Post.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.updatePost(1L, 1L, updatePostDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("帖子更新成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(postMapper).update(any(Post.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUpdatePost_Unauthorized() {
 | 
				
			||||
        // Mock 其他用户的帖子
 | 
				
			||||
        testPost.setUserId(2L);
 | 
				
			||||
        when(postMapper.findById(1L)).thenReturn(testPost);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.updatePost(1L, 1L, updatePostDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(403, result.getCode());
 | 
				
			||||
        assertEquals("无权限修改此帖子", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testDeletePost_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(postMapper.findById(1L)).thenReturn(testPost);
 | 
				
			||||
        when(postMapper.delete(1L)).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.deletePost(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("帖子删除成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(postMapper).delete(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testLikePost_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(postMapper.findById(1L)).thenReturn(testPost);
 | 
				
			||||
        when(postMapper.isLikedByUser(1L, 1L)).thenReturn(false);
 | 
				
			||||
        when(postMapper.insertLike(1L, 1L)).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.likePost(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("点赞成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(postMapper).insertLike(1L, 1L);
 | 
				
			||||
        verify(postMapper).updateLikeCount(1L, 1);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUnlikePost_Success() {
 | 
				
			||||
        // Mock 已点赞状态
 | 
				
			||||
        when(postMapper.findById(1L)).thenReturn(testPost);
 | 
				
			||||
        when(postMapper.isLikedByUser(1L, 1L)).thenReturn(true);
 | 
				
			||||
        when(postMapper.deleteLike(1L, 1L)).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = postService.likePost(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("取消点赞成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(postMapper).deleteLike(1L, 1L);
 | 
				
			||||
        verify(postMapper).updateLikeCount(1L, -1);
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,348 @@
 | 
				
			||||
package com.unilife.service;
 | 
				
			||||
 | 
				
			||||
import com.unilife.common.result.Result;
 | 
				
			||||
import com.unilife.mapper.ResourceMapper;
 | 
				
			||||
import com.unilife.mapper.UserMapper;
 | 
				
			||||
import com.unilife.mapper.CategoryMapper;
 | 
				
			||||
import com.unilife.model.dto.CreateResourceDTO;
 | 
				
			||||
import com.unilife.model.entity.Resource;
 | 
				
			||||
import com.unilife.model.entity.User;
 | 
				
			||||
import com.unilife.model.entity.Category;
 | 
				
			||||
import com.unilife.service.impl.ResourceServiceImpl;
 | 
				
			||||
import org.junit.jupiter.api.BeforeEach;
 | 
				
			||||
import org.junit.jupiter.api.Test;
 | 
				
			||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
				
			||||
import org.mockito.InjectMocks;
 | 
				
			||||
import org.mockito.Mock;
 | 
				
			||||
import org.mockito.junit.jupiter.MockitoExtension;
 | 
				
			||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
				
			||||
import org.springframework.mock.web.MockMultipartFile;
 | 
				
			||||
 | 
				
			||||
import java.time.LocalDateTime;
 | 
				
			||||
import java.util.Arrays;
 | 
				
			||||
import java.util.List;
 | 
				
			||||
 | 
				
			||||
import static org.junit.jupiter.api.Assertions.*;
 | 
				
			||||
import static org.mockito.ArgumentMatchers.*;
 | 
				
			||||
import static org.mockito.Mockito.*;
 | 
				
			||||
 | 
				
			||||
@ExtendWith(MockitoExtension.class)
 | 
				
			||||
@SpringBootTest
 | 
				
			||||
class ResourceServiceTest {
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private ResourceMapper resourceMapper;
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private UserMapper userMapper;
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private CategoryMapper categoryMapper;
 | 
				
			||||
 | 
				
			||||
    @InjectMocks
 | 
				
			||||
    private ResourceServiceImpl resourceService;
 | 
				
			||||
 | 
				
			||||
    private User testUser;
 | 
				
			||||
    private Category testCategory;
 | 
				
			||||
    private Resource testResource;
 | 
				
			||||
    private CreateResourceDTO createResourceDTO;
 | 
				
			||||
    private MockMultipartFile mockFile;
 | 
				
			||||
 | 
				
			||||
    @BeforeEach
 | 
				
			||||
    void setUp() {
 | 
				
			||||
        // 初始化测试数据
 | 
				
			||||
        testUser = new User();
 | 
				
			||||
        testUser.setId(1L);
 | 
				
			||||
        testUser.setNickname("测试用户");
 | 
				
			||||
        testUser.setAvatar("avatar.jpg");
 | 
				
			||||
 | 
				
			||||
        testCategory = new Category();
 | 
				
			||||
        testCategory.setId(1L);
 | 
				
			||||
        testCategory.setName("学习资料");
 | 
				
			||||
        testCategory.setStatus(1);
 | 
				
			||||
 | 
				
			||||
        testResource = new Resource();
 | 
				
			||||
        testResource.setId(1L);
 | 
				
			||||
        testResource.setTitle("测试资源");
 | 
				
			||||
        testResource.setDescription("测试资源描述");
 | 
				
			||||
        testResource.setFileName("test.pdf");
 | 
				
			||||
        testResource.setFileUrl("http://example.com/test.pdf");
 | 
				
			||||
        testResource.setFileSize(1024L);
 | 
				
			||||
        testResource.setFileType("pdf");
 | 
				
			||||
        testResource.setUserId(1L);
 | 
				
			||||
        testResource.setCategoryId(1L);
 | 
				
			||||
        testResource.setDownloadCount(0);
 | 
				
			||||
        testResource.setLikeCount(0);
 | 
				
			||||
        testResource.setCreatedAt(LocalDateTime.now());
 | 
				
			||||
        testResource.setUpdatedAt(LocalDateTime.now());
 | 
				
			||||
 | 
				
			||||
        createResourceDTO = new CreateResourceDTO();
 | 
				
			||||
        createResourceDTO.setTitle("新资源标题");
 | 
				
			||||
        createResourceDTO.setDescription("新资源描述");
 | 
				
			||||
        createResourceDTO.setCategoryId(1L);
 | 
				
			||||
 | 
				
			||||
        mockFile = new MockMultipartFile(
 | 
				
			||||
            "file", 
 | 
				
			||||
            "test.pdf", 
 | 
				
			||||
            "application/pdf", 
 | 
				
			||||
            "test content".getBytes()
 | 
				
			||||
        );
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUploadResource_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(categoryMapper.findById(1L)).thenReturn(testCategory);
 | 
				
			||||
        when(resourceMapper.insert(any(Resource.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.uploadResource(1L, createResourceDTO, mockFile);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("资源上传成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(userMapper).findById(1L);
 | 
				
			||||
        verify(categoryMapper).findById(1L);
 | 
				
			||||
        verify(resourceMapper).insert(any(Resource.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUploadResource_UserNotFound() {
 | 
				
			||||
        // Mock 用户不存在
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.uploadResource(1L, createResourceDTO, mockFile);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("用户不存在", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证不会尝试上传资源
 | 
				
			||||
        verify(resourceMapper, never()).insert(any(Resource.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUploadResource_CategoryNotFound() {
 | 
				
			||||
        // Mock 用户存在但分类不存在
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(categoryMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.uploadResource(1L, createResourceDTO, mockFile);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("分类不存在", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUploadResource_EmptyFile() {
 | 
				
			||||
        // 测试空文件
 | 
				
			||||
        MockMultipartFile emptyFile = new MockMultipartFile(
 | 
				
			||||
            "file", 
 | 
				
			||||
            "empty.pdf", 
 | 
				
			||||
            "application/pdf", 
 | 
				
			||||
            new byte[0]
 | 
				
			||||
        );
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.uploadResource(1L, createResourceDTO, emptyFile);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertEquals("文件不能为空", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUploadResource_InvalidFileType() {
 | 
				
			||||
        // 测试不支持的文件类型
 | 
				
			||||
        MockMultipartFile invalidFile = new MockMultipartFile(
 | 
				
			||||
            "file", 
 | 
				
			||||
            "test.exe", 
 | 
				
			||||
            "application/octet-stream", 
 | 
				
			||||
            "test content".getBytes()
 | 
				
			||||
        );
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.uploadResource(1L, createResourceDTO, invalidFile);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertTrue(result.getMessage().contains("不支持的文件类型"));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetResourceDetail_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(resourceMapper.findById(1L)).thenReturn(testResource);
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(categoryMapper.findById(1L)).thenReturn(testCategory);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.getResourceDetail(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetResourceDetail_ResourceNotFound() {
 | 
				
			||||
        // Mock 资源不存在
 | 
				
			||||
        when(resourceMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.getResourceDetail(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("资源不存在", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetResourceList_Success() {
 | 
				
			||||
        // Mock 资源列表
 | 
				
			||||
        List<Resource> resources = Arrays.asList(testResource);
 | 
				
			||||
        when(resourceMapper.findByConditions(any(), any(), any(), anyInt(), anyInt())).thenReturn(resources);
 | 
				
			||||
        when(resourceMapper.countByConditions(any(), any(), any())).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.getResourceList(1L, 1L, "测试", 1, 10, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUpdateResource_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(resourceMapper.findById(1L)).thenReturn(testResource);
 | 
				
			||||
        when(categoryMapper.findById(1L)).thenReturn(testCategory);
 | 
				
			||||
        when(resourceMapper.update(any(Resource.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.updateResource(1L, 1L, createResourceDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("资源更新成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(resourceMapper).update(any(Resource.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUpdateResource_Unauthorized() {
 | 
				
			||||
        // Mock 其他用户的资源
 | 
				
			||||
        testResource.setUserId(2L);
 | 
				
			||||
        when(resourceMapper.findById(1L)).thenReturn(testResource);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.updateResource(1L, 1L, createResourceDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(403, result.getCode());
 | 
				
			||||
        assertEquals("无权限修改此资源", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testDeleteResource_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(resourceMapper.findById(1L)).thenReturn(testResource);
 | 
				
			||||
        when(resourceMapper.delete(1L)).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.deleteResource(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("资源删除成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(resourceMapper).delete(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testDownloadResource_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(resourceMapper.findById(1L)).thenReturn(testResource);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.downloadResource(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
 | 
				
			||||
        // 验证下载量增加
 | 
				
			||||
        verify(resourceMapper).updateDownloadCount(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testLikeResource_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(resourceMapper.findById(1L)).thenReturn(testResource);
 | 
				
			||||
        when(resourceMapper.isLikedByUser(1L, 1L)).thenReturn(false);
 | 
				
			||||
        when(resourceMapper.insertLike(1L, 1L)).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.likeResource(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("点赞成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(resourceMapper).insertLike(1L, 1L);
 | 
				
			||||
        verify(resourceMapper).updateLikeCount(1L, 1);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUnlikeResource_Success() {
 | 
				
			||||
        // Mock 已点赞状态
 | 
				
			||||
        when(resourceMapper.findById(1L)).thenReturn(testResource);
 | 
				
			||||
        when(resourceMapper.isLikedByUser(1L, 1L)).thenReturn(true);
 | 
				
			||||
        when(resourceMapper.deleteLike(1L, 1L)).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.likeResource(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("取消点赞成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(resourceMapper).deleteLike(1L, 1L);
 | 
				
			||||
        verify(resourceMapper).updateLikeCount(1L, -1);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetUserResources_Success() {
 | 
				
			||||
        // Mock 用户资源列表
 | 
				
			||||
        List<Resource> userResources = Arrays.asList(testResource);
 | 
				
			||||
        when(resourceMapper.findByUserId(eq(1L), anyInt(), anyInt())).thenReturn(userResources);
 | 
				
			||||
        when(resourceMapper.countByUserId(1L)).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = resourceService.getUserResources(1L, 1, 10);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(resourceMapper).findByUserId(eq(1L), anyInt(), anyInt());
 | 
				
			||||
        verify(resourceMapper).countByUserId(1L);
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,370 @@
 | 
				
			||||
package com.unilife.service;
 | 
				
			||||
 | 
				
			||||
import com.unilife.common.result.Result;
 | 
				
			||||
import com.unilife.mapper.ScheduleMapper;
 | 
				
			||||
import com.unilife.mapper.UserMapper;
 | 
				
			||||
import com.unilife.model.dto.CreateScheduleDTO;
 | 
				
			||||
import com.unilife.model.entity.Schedule;
 | 
				
			||||
import com.unilife.model.entity.User;
 | 
				
			||||
import com.unilife.service.impl.ScheduleServiceImpl;
 | 
				
			||||
import org.junit.jupiter.api.BeforeEach;
 | 
				
			||||
import org.junit.jupiter.api.Test;
 | 
				
			||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
				
			||||
import org.mockito.InjectMocks;
 | 
				
			||||
import org.mockito.Mock;
 | 
				
			||||
import org.mockito.junit.jupiter.MockitoExtension;
 | 
				
			||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
				
			||||
 | 
				
			||||
import java.time.LocalDateTime;
 | 
				
			||||
import java.util.Arrays;
 | 
				
			||||
import java.util.List;
 | 
				
			||||
 | 
				
			||||
import static org.junit.jupiter.api.Assertions.*;
 | 
				
			||||
import static org.mockito.ArgumentMatchers.*;
 | 
				
			||||
import static org.mockito.Mockito.*;
 | 
				
			||||
 | 
				
			||||
@ExtendWith(MockitoExtension.class)
 | 
				
			||||
@SpringBootTest
 | 
				
			||||
class ScheduleServiceTest {
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private ScheduleMapper scheduleMapper;
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private UserMapper userMapper;
 | 
				
			||||
 | 
				
			||||
    @InjectMocks
 | 
				
			||||
    private ScheduleServiceImpl scheduleService;
 | 
				
			||||
 | 
				
			||||
    private User testUser;
 | 
				
			||||
    private Schedule testSchedule;
 | 
				
			||||
    private CreateScheduleDTO createScheduleDTO;
 | 
				
			||||
 | 
				
			||||
    @BeforeEach
 | 
				
			||||
    void setUp() {
 | 
				
			||||
        // 初始化测试数据
 | 
				
			||||
        testUser = new User();
 | 
				
			||||
        testUser.setId(1L);
 | 
				
			||||
        testUser.setNickname("测试用户");
 | 
				
			||||
        testUser.setAvatar("avatar.jpg");
 | 
				
			||||
 | 
				
			||||
        testSchedule = new Schedule();
 | 
				
			||||
        testSchedule.setId(1L);
 | 
				
			||||
        testSchedule.setTitle("测试课程");
 | 
				
			||||
        testSchedule.setDescription("测试课程描述");
 | 
				
			||||
        testSchedule.setStartTime(LocalDateTime.of(2024, 1, 15, 9, 0));
 | 
				
			||||
        testSchedule.setEndTime(LocalDateTime.of(2024, 1, 15, 10, 30));
 | 
				
			||||
        testSchedule.setLocation("教学楼A101");
 | 
				
			||||
        testSchedule.setType("COURSE");
 | 
				
			||||
        testSchedule.setRepeatType("WEEKLY");
 | 
				
			||||
        testSchedule.setRepeatEnd(LocalDateTime.of(2024, 6, 15, 10, 30));
 | 
				
			||||
        testSchedule.setUserId(1L);
 | 
				
			||||
        testSchedule.setCreatedAt(LocalDateTime.now());
 | 
				
			||||
        testSchedule.setUpdatedAt(LocalDateTime.now());
 | 
				
			||||
 | 
				
			||||
        createScheduleDTO = new CreateScheduleDTO();
 | 
				
			||||
        createScheduleDTO.setTitle("新课程");
 | 
				
			||||
        createScheduleDTO.setDescription("新课程描述");
 | 
				
			||||
        createScheduleDTO.setStartTime(LocalDateTime.of(2024, 1, 16, 14, 0));
 | 
				
			||||
        createScheduleDTO.setEndTime(LocalDateTime.of(2024, 1, 16, 15, 30));
 | 
				
			||||
        createScheduleDTO.setLocation("教学楼B201");
 | 
				
			||||
        createScheduleDTO.setType("COURSE");
 | 
				
			||||
        createScheduleDTO.setRepeatType("WEEKLY");
 | 
				
			||||
        createScheduleDTO.setRepeatEnd(LocalDateTime.of(2024, 6, 16, 15, 30));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreateSchedule_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(scheduleMapper.findConflictingSchedules(eq(1L), any(), any(), any())).thenReturn(Arrays.asList());
 | 
				
			||||
        when(scheduleMapper.insert(any(Schedule.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.createSchedule(1L, createScheduleDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("日程创建成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(userMapper).findById(1L);
 | 
				
			||||
        verify(scheduleMapper).findConflictingSchedules(eq(1L), any(), any(), any());
 | 
				
			||||
        verify(scheduleMapper).insert(any(Schedule.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreateSchedule_UserNotFound() {
 | 
				
			||||
        // Mock 用户不存在
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.createSchedule(1L, createScheduleDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("用户不存在", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证不会尝试创建日程
 | 
				
			||||
        verify(scheduleMapper, never()).insert(any(Schedule.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreateSchedule_TimeConflict() {
 | 
				
			||||
        // Mock 时间冲突
 | 
				
			||||
        Schedule conflictingSchedule = new Schedule();
 | 
				
			||||
        conflictingSchedule.setId(2L);
 | 
				
			||||
        conflictingSchedule.setTitle("冲突课程");
 | 
				
			||||
        conflictingSchedule.setStartTime(LocalDateTime.of(2024, 1, 16, 14, 30));
 | 
				
			||||
        conflictingSchedule.setEndTime(LocalDateTime.of(2024, 1, 16, 16, 0));
 | 
				
			||||
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(scheduleMapper.findConflictingSchedules(eq(1L), any(), any(), any()))
 | 
				
			||||
            .thenReturn(Arrays.asList(conflictingSchedule));
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.createSchedule(1L, createScheduleDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertTrue(result.getMessage().contains("时间冲突"));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreateSchedule_InvalidTimeRange() {
 | 
				
			||||
        // 测试结束时间早于开始时间
 | 
				
			||||
        createScheduleDTO.setStartTime(LocalDateTime.of(2024, 1, 16, 16, 0));
 | 
				
			||||
        createScheduleDTO.setEndTime(LocalDateTime.of(2024, 1, 16, 14, 0));
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.createSchedule(1L, createScheduleDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertEquals("结束时间不能早于开始时间", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetScheduleDetail_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(scheduleMapper.findById(1L)).thenReturn(testSchedule);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.getScheduleDetail(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetScheduleDetail_NotFound() {
 | 
				
			||||
        // Mock 日程不存在
 | 
				
			||||
        when(scheduleMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.getScheduleDetail(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("日程不存在", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetScheduleDetail_Unauthorized() {
 | 
				
			||||
        // Mock 其他用户的日程
 | 
				
			||||
        testSchedule.setUserId(2L);
 | 
				
			||||
        when(scheduleMapper.findById(1L)).thenReturn(testSchedule);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.getScheduleDetail(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(403, result.getCode());
 | 
				
			||||
        assertEquals("无权限查看此日程", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetScheduleList_Success() {
 | 
				
			||||
        // Mock 日程列表
 | 
				
			||||
        List<Schedule> schedules = Arrays.asList(testSchedule);
 | 
				
			||||
        when(scheduleMapper.findByUserId(1L)).thenReturn(schedules);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.getScheduleList(1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
        
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(scheduleMapper).findByUserId(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetScheduleListByTimeRange_Success() {
 | 
				
			||||
        LocalDateTime startTime = LocalDateTime.of(2024, 1, 1, 0, 0);
 | 
				
			||||
        LocalDateTime endTime = LocalDateTime.of(2024, 1, 31, 23, 59);
 | 
				
			||||
        
 | 
				
			||||
        // Mock 时间范围内的日程列表
 | 
				
			||||
        List<Schedule> schedules = Arrays.asList(testSchedule);
 | 
				
			||||
        when(scheduleMapper.findByUserIdAndTimeRange(1L, startTime, endTime)).thenReturn(schedules);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.getScheduleListByTimeRange(1L, startTime, endTime);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
        
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(scheduleMapper).findByUserIdAndTimeRange(1L, startTime, endTime);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUpdateSchedule_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(scheduleMapper.findById(1L)).thenReturn(testSchedule);
 | 
				
			||||
        when(scheduleMapper.findConflictingSchedules(eq(1L), any(), any(), eq(1L))).thenReturn(Arrays.asList());
 | 
				
			||||
        when(scheduleMapper.update(any(Schedule.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.updateSchedule(1L, 1L, createScheduleDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("日程更新成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(scheduleMapper).update(any(Schedule.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUpdateSchedule_Unauthorized() {
 | 
				
			||||
        // Mock 其他用户的日程
 | 
				
			||||
        testSchedule.setUserId(2L);
 | 
				
			||||
        when(scheduleMapper.findById(1L)).thenReturn(testSchedule);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.updateSchedule(1L, 1L, createScheduleDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(403, result.getCode());
 | 
				
			||||
        assertEquals("无权限修改此日程", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testDeleteSchedule_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(scheduleMapper.findById(1L)).thenReturn(testSchedule);
 | 
				
			||||
        when(scheduleMapper.delete(1L)).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.deleteSchedule(1L, 1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("日程删除成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(scheduleMapper).delete(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCheckScheduleConflict_NoConflict() {
 | 
				
			||||
        LocalDateTime startTime = LocalDateTime.of(2024, 1, 16, 14, 0);
 | 
				
			||||
        LocalDateTime endTime = LocalDateTime.of(2024, 1, 16, 15, 30);
 | 
				
			||||
        
 | 
				
			||||
        // Mock 无冲突
 | 
				
			||||
        when(scheduleMapper.findConflictingSchedules(eq(1L), eq(startTime), eq(endTime), any()))
 | 
				
			||||
            .thenReturn(Arrays.asList());
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.checkScheduleConflict(1L, startTime, endTime, null);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("无时间冲突", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCheckScheduleConflict_HasConflict() {
 | 
				
			||||
        LocalDateTime startTime = LocalDateTime.of(2024, 1, 16, 14, 0);
 | 
				
			||||
        LocalDateTime endTime = LocalDateTime.of(2024, 1, 16, 15, 30);
 | 
				
			||||
        
 | 
				
			||||
        // Mock 有冲突
 | 
				
			||||
        when(scheduleMapper.findConflictingSchedules(eq(1L), eq(startTime), eq(endTime), any()))
 | 
				
			||||
            .thenReturn(Arrays.asList(testSchedule));
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.checkScheduleConflict(1L, startTime, endTime, null);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertTrue(result.getMessage().contains("时间冲突"));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testProcessScheduleReminders_Success() {
 | 
				
			||||
        // Mock 需要提醒的日程
 | 
				
			||||
        List<Schedule> upcomingSchedules = Arrays.asList(testSchedule);
 | 
				
			||||
        when(scheduleMapper.findUpcomingSchedules(any())).thenReturn(upcomingSchedules);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.processScheduleReminders();
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("提醒处理完成", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(scheduleMapper).findUpcomingSchedules(any());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreateSchedule_WeeklyRepeat() {
 | 
				
			||||
        // 测试周重复日程
 | 
				
			||||
        createScheduleDTO.setRepeatType("WEEKLY");
 | 
				
			||||
        createScheduleDTO.setRepeatEnd(LocalDateTime.of(2024, 3, 16, 15, 30));
 | 
				
			||||
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(scheduleMapper.findConflictingSchedules(eq(1L), any(), any(), any())).thenReturn(Arrays.asList());
 | 
				
			||||
        when(scheduleMapper.insert(any(Schedule.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.createSchedule(1L, createScheduleDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        
 | 
				
			||||
        // 验证会创建多个重复的日程实例
 | 
				
			||||
        verify(scheduleMapper, atLeast(1)).insert(any(Schedule.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testCreateSchedule_DailyRepeat() {
 | 
				
			||||
        // 测试日重复日程
 | 
				
			||||
        createScheduleDTO.setRepeatType("DAILY");
 | 
				
			||||
        createScheduleDTO.setRepeatEnd(LocalDateTime.of(2024, 1, 20, 15, 30));
 | 
				
			||||
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(scheduleMapper.findConflictingSchedules(eq(1L), any(), any(), any())).thenReturn(Arrays.asList());
 | 
				
			||||
        when(scheduleMapper.insert(any(Schedule.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = scheduleService.createSchedule(1L, createScheduleDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        
 | 
				
			||||
        // 验证会创建多个重复的日程实例
 | 
				
			||||
        verify(scheduleMapper, atLeast(1)).insert(any(Schedule.class));
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,438 @@
 | 
				
			||||
package com.unilife.service;
 | 
				
			||||
 | 
				
			||||
import com.unilife.common.result.Result;
 | 
				
			||||
import com.unilife.mapper.UserMapper;
 | 
				
			||||
import com.unilife.model.dto.CreateUserDTO;
 | 
				
			||||
import com.unilife.model.dto.UpdateUserDTO;
 | 
				
			||||
import com.unilife.model.dto.LoginDTO;
 | 
				
			||||
import com.unilife.model.entity.User;
 | 
				
			||||
import com.unilife.service.impl.UserServiceImpl;
 | 
				
			||||
import com.unilife.utils.JwtUtil;
 | 
				
			||||
import com.unilife.utils.PasswordUtil;
 | 
				
			||||
import org.junit.jupiter.api.BeforeEach;
 | 
				
			||||
import org.junit.jupiter.api.Test;
 | 
				
			||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
				
			||||
import org.mockito.InjectMocks;
 | 
				
			||||
import org.mockito.Mock;
 | 
				
			||||
import org.mockito.MockedStatic;
 | 
				
			||||
import org.mockito.junit.jupiter.MockitoExtension;
 | 
				
			||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
				
			||||
import org.springframework.data.redis.core.StringRedisTemplate;
 | 
				
			||||
import org.springframework.mail.SimpleMailMessage;
 | 
				
			||||
import org.springframework.mail.javamail.JavaMailSender;
 | 
				
			||||
 | 
				
			||||
import java.time.LocalDateTime;
 | 
				
			||||
import java.util.Arrays;
 | 
				
			||||
import java.util.List;
 | 
				
			||||
import java.util.concurrent.TimeUnit;
 | 
				
			||||
 | 
				
			||||
import static org.junit.jupiter.api.Assertions.*;
 | 
				
			||||
import static org.mockito.ArgumentMatchers.*;
 | 
				
			||||
import static org.mockito.Mockito.*;
 | 
				
			||||
 | 
				
			||||
@ExtendWith(MockitoExtension.class)
 | 
				
			||||
@SpringBootTest
 | 
				
			||||
class UserServiceTest {
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private UserMapper userMapper;
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private StringRedisTemplate redisTemplate;
 | 
				
			||||
 | 
				
			||||
    @Mock
 | 
				
			||||
    private JavaMailSender mailSender;
 | 
				
			||||
 | 
				
			||||
    @InjectMocks
 | 
				
			||||
    private UserServiceImpl userService;
 | 
				
			||||
 | 
				
			||||
    private User testUser;
 | 
				
			||||
    private CreateUserDTO createUserDTO;
 | 
				
			||||
    private UpdateUserDTO updateUserDTO;
 | 
				
			||||
    private LoginDTO loginDTO;
 | 
				
			||||
 | 
				
			||||
    @BeforeEach
 | 
				
			||||
    void setUp() {
 | 
				
			||||
        // 初始化测试数据
 | 
				
			||||
        testUser = new User();
 | 
				
			||||
        testUser.setId(1L);
 | 
				
			||||
        testUser.setUsername("testuser");
 | 
				
			||||
        testUser.setEmail("test@example.com");
 | 
				
			||||
        testUser.setNickname("测试用户");
 | 
				
			||||
        testUser.setPassword("$2a$10$encrypted_password"); // 模拟加密后的密码
 | 
				
			||||
        testUser.setAvatar("avatar.jpg");
 | 
				
			||||
        testUser.setStatus(1);
 | 
				
			||||
        testUser.setCreatedAt(LocalDateTime.now());
 | 
				
			||||
        testUser.setUpdatedAt(LocalDateTime.now());
 | 
				
			||||
 | 
				
			||||
        createUserDTO = new CreateUserDTO();
 | 
				
			||||
        createUserDTO.setUsername("newuser");
 | 
				
			||||
        createUserDTO.setEmail("newuser@example.com");
 | 
				
			||||
        createUserDTO.setNickname("新用户");
 | 
				
			||||
        createUserDTO.setPassword("password123");
 | 
				
			||||
 | 
				
			||||
        updateUserDTO = new UpdateUserDTO();
 | 
				
			||||
        updateUserDTO.setNickname("更新后的昵称");
 | 
				
			||||
        updateUserDTO.setAvatar("new_avatar.jpg");
 | 
				
			||||
 | 
				
			||||
        loginDTO = new LoginDTO();
 | 
				
			||||
        loginDTO.setUsername("testuser");
 | 
				
			||||
        loginDTO.setPassword("password123");
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testRegister_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findByUsername("newuser")).thenReturn(null);
 | 
				
			||||
        when(userMapper.findByEmail("newuser@example.com")).thenReturn(null);
 | 
				
			||||
        when(userMapper.insert(any(User.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        try (MockedStatic<PasswordUtil> passwordUtil = mockStatic(PasswordUtil.class)) {
 | 
				
			||||
            passwordUtil.when(() -> PasswordUtil.encode("password123"))
 | 
				
			||||
                .thenReturn("$2a$10$encrypted_password");
 | 
				
			||||
 | 
				
			||||
            // 执行测试
 | 
				
			||||
            Result<?> result = userService.register(createUserDTO);
 | 
				
			||||
 | 
				
			||||
            // 验证结果
 | 
				
			||||
            assertTrue(result.isSuccess());
 | 
				
			||||
            assertEquals("注册成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
            // 验证方法调用
 | 
				
			||||
            verify(userMapper).findByUsername("newuser");
 | 
				
			||||
            verify(userMapper).findByEmail("newuser@example.com");
 | 
				
			||||
            verify(userMapper).insert(any(User.class));
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testRegister_UsernameExists() {
 | 
				
			||||
        // Mock 用户名已存在
 | 
				
			||||
        when(userMapper.findByUsername("newuser")).thenReturn(testUser);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.register(createUserDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertEquals("用户名已存在", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证不会尝试插入用户
 | 
				
			||||
        verify(userMapper, never()).insert(any(User.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testRegister_EmailExists() {
 | 
				
			||||
        // Mock 邮箱已存在
 | 
				
			||||
        when(userMapper.findByUsername("newuser")).thenReturn(null);
 | 
				
			||||
        when(userMapper.findByEmail("newuser@example.com")).thenReturn(testUser);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.register(createUserDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertEquals("邮箱已存在", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testLogin_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findByUsername("testuser")).thenReturn(testUser);
 | 
				
			||||
 | 
				
			||||
        try (MockedStatic<PasswordUtil> passwordUtil = mockStatic(PasswordUtil.class);
 | 
				
			||||
             MockedStatic<JwtUtil> jwtUtil = mockStatic(JwtUtil.class)) {
 | 
				
			||||
            
 | 
				
			||||
            passwordUtil.when(() -> PasswordUtil.matches("password123", "$2a$10$encrypted_password"))
 | 
				
			||||
                .thenReturn(true);
 | 
				
			||||
            jwtUtil.when(() -> JwtUtil.generateToken(1L))
 | 
				
			||||
                .thenReturn("mock_jwt_token");
 | 
				
			||||
 | 
				
			||||
            // 执行测试
 | 
				
			||||
            Result<?> result = userService.login(loginDTO);
 | 
				
			||||
 | 
				
			||||
            // 验证结果
 | 
				
			||||
            assertTrue(result.isSuccess());
 | 
				
			||||
            assertEquals("登录成功", result.getMessage());
 | 
				
			||||
            assertNotNull(result.getData());
 | 
				
			||||
 | 
				
			||||
            // 验证方法调用
 | 
				
			||||
            verify(userMapper).findByUsername("testuser");
 | 
				
			||||
            verify(userMapper).updateLastLoginTime(1L);
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testLogin_UserNotFound() {
 | 
				
			||||
        // Mock 用户不存在
 | 
				
			||||
        when(userMapper.findByUsername("testuser")).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.login(loginDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(401, result.getCode());
 | 
				
			||||
        assertEquals("用户名或密码错误", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testLogin_PasswordIncorrect() {
 | 
				
			||||
        // Mock 密码错误
 | 
				
			||||
        when(userMapper.findByUsername("testuser")).thenReturn(testUser);
 | 
				
			||||
 | 
				
			||||
        try (MockedStatic<PasswordUtil> passwordUtil = mockStatic(PasswordUtil.class)) {
 | 
				
			||||
            passwordUtil.when(() -> PasswordUtil.matches("password123", "$2a$10$encrypted_password"))
 | 
				
			||||
                .thenReturn(false);
 | 
				
			||||
 | 
				
			||||
            // 执行测试
 | 
				
			||||
            Result<?> result = userService.login(loginDTO);
 | 
				
			||||
 | 
				
			||||
            // 验证结果
 | 
				
			||||
            assertFalse(result.isSuccess());
 | 
				
			||||
            assertEquals(401, result.getCode());
 | 
				
			||||
            assertEquals("用户名或密码错误", result.getMessage());
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testLogin_UserDisabled() {
 | 
				
			||||
        // Mock 用户被禁用
 | 
				
			||||
        testUser.setStatus(0);
 | 
				
			||||
        when(userMapper.findByUsername("testuser")).thenReturn(testUser);
 | 
				
			||||
 | 
				
			||||
        try (MockedStatic<PasswordUtil> passwordUtil = mockStatic(PasswordUtil.class)) {
 | 
				
			||||
            passwordUtil.when(() -> PasswordUtil.matches("password123", "$2a$10$encrypted_password"))
 | 
				
			||||
                .thenReturn(true);
 | 
				
			||||
 | 
				
			||||
            // 执行测试
 | 
				
			||||
            Result<?> result = userService.login(loginDTO);
 | 
				
			||||
 | 
				
			||||
            // 验证结果
 | 
				
			||||
            assertFalse(result.isSuccess());
 | 
				
			||||
            assertEquals(403, result.getCode());
 | 
				
			||||
            assertEquals("账户已被禁用", result.getMessage());
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetUserInfo_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.getUserInfo(1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(userMapper).findById(1L);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetUserInfo_UserNotFound() {
 | 
				
			||||
        // Mock 用户不存在
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.getUserInfo(1L);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(404, result.getCode());
 | 
				
			||||
        assertEquals("用户不存在", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testUpdateUserInfo_Success() {
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(userMapper.update(any(User.class))).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.updateUserInfo(1L, updateUserDTO);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("用户信息更新成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(userMapper).update(any(User.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testSendEmailVerificationCode_Success() {
 | 
				
			||||
        String email = "test@example.com";
 | 
				
			||||
        String verificationCode = "123456";
 | 
				
			||||
 | 
				
			||||
        // Mock Redis操作
 | 
				
			||||
        when(redisTemplate.opsForValue()).thenReturn(mock(org.springframework.data.redis.core.ValueOperations.class));
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.sendEmailVerificationCode(email);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("验证码发送成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证邮件发送
 | 
				
			||||
        verify(mailSender).send(any(SimpleMailMessage.class));
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testVerifyEmailCode_Success() {
 | 
				
			||||
        String email = "test@example.com";
 | 
				
			||||
        String code = "123456";
 | 
				
			||||
 | 
				
			||||
        // Mock Redis操作
 | 
				
			||||
        when(redisTemplate.opsForValue()).thenReturn(mock(org.springframework.data.redis.core.ValueOperations.class));
 | 
				
			||||
        when(redisTemplate.opsForValue().get("email_code:" + email)).thenReturn(code);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.verifyEmailCode(email, code);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertEquals("验证码验证成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
        // 验证删除验证码
 | 
				
			||||
        verify(redisTemplate).delete("email_code:" + email);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testVerifyEmailCode_CodeExpired() {
 | 
				
			||||
        String email = "test@example.com";
 | 
				
			||||
        String code = "123456";
 | 
				
			||||
 | 
				
			||||
        // Mock 验证码不存在(已过期)
 | 
				
			||||
        when(redisTemplate.opsForValue()).thenReturn(mock(org.springframework.data.redis.core.ValueOperations.class));
 | 
				
			||||
        when(redisTemplate.opsForValue().get("email_code:" + email)).thenReturn(null);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.verifyEmailCode(email, code);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertEquals("验证码已过期", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testVerifyEmailCode_CodeIncorrect() {
 | 
				
			||||
        String email = "test@example.com";
 | 
				
			||||
        String code = "123456";
 | 
				
			||||
        String wrongCode = "654321";
 | 
				
			||||
 | 
				
			||||
        // Mock 验证码错误
 | 
				
			||||
        when(redisTemplate.opsForValue()).thenReturn(mock(org.springframework.data.redis.core.ValueOperations.class));
 | 
				
			||||
        when(redisTemplate.opsForValue().get("email_code:" + email)).thenReturn(wrongCode);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.verifyEmailCode(email, code);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertFalse(result.isSuccess());
 | 
				
			||||
        assertEquals(400, result.getCode());
 | 
				
			||||
        assertEquals("验证码错误", result.getMessage());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testResetPassword_Success() {
 | 
				
			||||
        String email = "test@example.com";
 | 
				
			||||
        String newPassword = "newpassword123";
 | 
				
			||||
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findByEmail(email)).thenReturn(testUser);
 | 
				
			||||
        when(userMapper.updatePassword(eq(1L), anyString())).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        try (MockedStatic<PasswordUtil> passwordUtil = mockStatic(PasswordUtil.class)) {
 | 
				
			||||
            passwordUtil.when(() -> PasswordUtil.encode(newPassword))
 | 
				
			||||
                .thenReturn("$2a$10$new_encrypted_password");
 | 
				
			||||
 | 
				
			||||
            // 执行测试
 | 
				
			||||
            Result<?> result = userService.resetPassword(email, newPassword);
 | 
				
			||||
 | 
				
			||||
            // 验证结果
 | 
				
			||||
            assertTrue(result.isSuccess());
 | 
				
			||||
            assertEquals("密码重置成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
            // 验证方法调用
 | 
				
			||||
            verify(userMapper).updatePassword(eq(1L), eq("$2a$10$new_encrypted_password"));
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testGetUserList_Success() {
 | 
				
			||||
        // Mock 用户列表
 | 
				
			||||
        List<User> users = Arrays.asList(testUser);
 | 
				
			||||
        when(userMapper.findByConditions(any(), any(), anyInt(), anyInt())).thenReturn(users);
 | 
				
			||||
        when(userMapper.countByConditions(any(), any())).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        // 执行测试
 | 
				
			||||
        Result<?> result = userService.getUserList("测试", 1, 1, 10);
 | 
				
			||||
 | 
				
			||||
        // 验证结果
 | 
				
			||||
        assertTrue(result.isSuccess());
 | 
				
			||||
        assertNotNull(result.getData());
 | 
				
			||||
 | 
				
			||||
        // 验证方法调用
 | 
				
			||||
        verify(userMapper).findByConditions(any(), any(), anyInt(), anyInt());
 | 
				
			||||
        verify(userMapper).countByConditions(any(), any());
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testChangePassword_Success() {
 | 
				
			||||
        String oldPassword = "oldpassword";
 | 
				
			||||
        String newPassword = "newpassword123";
 | 
				
			||||
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
        when(userMapper.updatePassword(eq(1L), anyString())).thenReturn(1);
 | 
				
			||||
 | 
				
			||||
        try (MockedStatic<PasswordUtil> passwordUtil = mockStatic(PasswordUtil.class)) {
 | 
				
			||||
            passwordUtil.when(() -> PasswordUtil.matches(oldPassword, "$2a$10$encrypted_password"))
 | 
				
			||||
                .thenReturn(true);
 | 
				
			||||
            passwordUtil.when(() -> PasswordUtil.encode(newPassword))
 | 
				
			||||
                .thenReturn("$2a$10$new_encrypted_password");
 | 
				
			||||
 | 
				
			||||
            // 执行测试
 | 
				
			||||
            Result<?> result = userService.changePassword(1L, oldPassword, newPassword);
 | 
				
			||||
 | 
				
			||||
            // 验证结果
 | 
				
			||||
            assertTrue(result.isSuccess());
 | 
				
			||||
            assertEquals("密码修改成功", result.getMessage());
 | 
				
			||||
 | 
				
			||||
            // 验证方法调用
 | 
				
			||||
            verify(userMapper).updatePassword(eq(1L), eq("$2a$10$new_encrypted_password"));
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Test
 | 
				
			||||
    void testChangePassword_OldPasswordIncorrect() {
 | 
				
			||||
        String oldPassword = "wrongpassword";
 | 
				
			||||
        String newPassword = "newpassword123";
 | 
				
			||||
 | 
				
			||||
        // Mock 依赖方法
 | 
				
			||||
        when(userMapper.findById(1L)).thenReturn(testUser);
 | 
				
			||||
 | 
				
			||||
        try (MockedStatic<PasswordUtil> passwordUtil = mockStatic(PasswordUtil.class)) {
 | 
				
			||||
            passwordUtil.when(() -> PasswordUtil.matches(oldPassword, "$2a$10$encrypted_password"))
 | 
				
			||||
                .thenReturn(false);
 | 
				
			||||
 | 
				
			||||
            // 执行测试
 | 
				
			||||
            Result<?> result = userService.changePassword(1L, oldPassword, newPassword);
 | 
				
			||||
 | 
				
			||||
            // 验证结果
 | 
				
			||||
            assertFalse(result.isSuccess());
 | 
				
			||||
            assertEquals(400, result.getCode());
 | 
				
			||||
            assertEquals("原密码错误", result.getMessage());
 | 
				
			||||
 | 
				
			||||
            // 验证不会更新密码
 | 
				
			||||
            verify(userMapper, never()).updatePassword(anyLong(), anyString());
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,117 @@
 | 
				
			||||
package com.unilife.utils;
 | 
				
			||||
 | 
				
			||||
import com.unilife.model.dto.*;
 | 
				
			||||
import com.unilife.model.entity.*;
 | 
				
			||||
 | 
				
			||||
import java.time.LocalDateTime;
 | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * 测试数据构建工具类
 | 
				
			||||
 * 提供各种实体和DTO的测试数据构建方法
 | 
				
			||||
 */
 | 
				
			||||
public class TestDataBuilder {
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 构建测试用户
 | 
				
			||||
     */
 | 
				
			||||
    public static User buildTestUser() {
 | 
				
			||||
        User user = new User();
 | 
				
			||||
        user.setId(1L);
 | 
				
			||||
        user.setUsername("testuser");
 | 
				
			||||
        user.setEmail("test@example.com");
 | 
				
			||||
        user.setNickname("测试用户");
 | 
				
			||||
        user.setPassword("$2a$10$encrypted_password");
 | 
				
			||||
        user.setAvatar("avatar.jpg");
 | 
				
			||||
        user.setStatus(1);
 | 
				
			||||
        user.setCreatedAt(LocalDateTime.now());
 | 
				
			||||
        user.setUpdatedAt(LocalDateTime.now());
 | 
				
			||||
        return user;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 构建测试分类
 | 
				
			||||
     */
 | 
				
			||||
    public static Category buildTestCategory() {
 | 
				
			||||
        Category category = new Category();
 | 
				
			||||
        category.setId(1L);
 | 
				
			||||
        category.setName("测试分类");
 | 
				
			||||
        category.setDescription("测试分类描述");
 | 
				
			||||
        category.setIcon("test-icon");
 | 
				
			||||
        category.setSort(1);
 | 
				
			||||
        category.setStatus(1);
 | 
				
			||||
        category.setCreatedAt(LocalDateTime.now());
 | 
				
			||||
        category.setUpdatedAt(LocalDateTime.now());
 | 
				
			||||
        return category;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 构建测试帖子
 | 
				
			||||
     */
 | 
				
			||||
    public static Post buildTestPost() {
 | 
				
			||||
        Post post = new Post();
 | 
				
			||||
        post.setId(1L);
 | 
				
			||||
        post.setTitle("测试帖子");
 | 
				
			||||
        post.setContent("测试帖子内容");
 | 
				
			||||
        post.setUserId(1L);
 | 
				
			||||
        post.setCategoryId(1L);
 | 
				
			||||
        post.setLikeCount(0);
 | 
				
			||||
        post.setViewCount(0);
 | 
				
			||||
        post.setCommentCount(0);
 | 
				
			||||
        post.setCreatedAt(LocalDateTime.now());
 | 
				
			||||
        post.setUpdatedAt(LocalDateTime.now());
 | 
				
			||||
        return post;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 构建测试资源
 | 
				
			||||
     */
 | 
				
			||||
    public static Resource buildTestResource() {
 | 
				
			||||
        Resource resource = new Resource();
 | 
				
			||||
        resource.setId(1L);
 | 
				
			||||
        resource.setTitle("测试资源");
 | 
				
			||||
        resource.setDescription("测试资源描述");
 | 
				
			||||
        resource.setFileName("test.pdf");
 | 
				
			||||
        resource.setFileUrl("http://example.com/test.pdf");
 | 
				
			||||
        resource.setFileSize(1024L);
 | 
				
			||||
        resource.setFileType("pdf");
 | 
				
			||||
        resource.setUserId(1L);
 | 
				
			||||
        resource.setCategoryId(1L);
 | 
				
			||||
        resource.setDownloadCount(0);
 | 
				
			||||
        resource.setLikeCount(0);
 | 
				
			||||
        resource.setCreatedAt(LocalDateTime.now());
 | 
				
			||||
        resource.setUpdatedAt(LocalDateTime.now());
 | 
				
			||||
        return resource;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 构建创建帖子DTO
 | 
				
			||||
     */
 | 
				
			||||
    public static CreatePostDTO buildCreatePostDTO() {
 | 
				
			||||
        CreatePostDTO dto = new CreatePostDTO();
 | 
				
			||||
        dto.setTitle("新帖子标题");
 | 
				
			||||
        dto.setContent("新帖子内容");
 | 
				
			||||
        dto.setCategoryId(1L);
 | 
				
			||||
        return dto;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 构建创建用户DTO
 | 
				
			||||
     */
 | 
				
			||||
    public static CreateUserDTO buildCreateUserDTO() {
 | 
				
			||||
        CreateUserDTO dto = new CreateUserDTO();
 | 
				
			||||
        dto.setUsername("newuser");
 | 
				
			||||
        dto.setEmail("newuser@example.com");
 | 
				
			||||
        dto.setNickname("新用户");
 | 
				
			||||
        dto.setPassword("password123");
 | 
				
			||||
        return dto;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    /**
 | 
				
			||||
     * 构建带有指定ID的用户
 | 
				
			||||
     */
 | 
				
			||||
    public static User buildTestUser(Long id) {
 | 
				
			||||
        User user = buildTestUser();
 | 
				
			||||
        user.setId(id);
 | 
				
			||||
        return user;
 | 
				
			||||
    }
 | 
				
			||||
} 
 | 
				
			||||
@ -0,0 +1,66 @@
 | 
				
			||||
spring:
 | 
				
			||||
  datasource:
 | 
				
			||||
    driver-class-name: org.h2.Driver
 | 
				
			||||
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
 | 
				
			||||
    username: sa
 | 
				
			||||
    password: 
 | 
				
			||||
  
 | 
				
			||||
  h2:
 | 
				
			||||
    console:
 | 
				
			||||
      enabled: true
 | 
				
			||||
  
 | 
				
			||||
  jpa:
 | 
				
			||||
    database-platform: org.hibernate.dialect.H2Dialect
 | 
				
			||||
    hibernate:
 | 
				
			||||
      ddl-auto: create-drop
 | 
				
			||||
    show-sql: true
 | 
				
			||||
  
 | 
				
			||||
  redis:
 | 
				
			||||
    host: localhost
 | 
				
			||||
    port: 6379
 | 
				
			||||
    database: 1
 | 
				
			||||
    timeout: 2000ms
 | 
				
			||||
  
 | 
				
			||||
  mail:
 | 
				
			||||
    host: smtp.example.com
 | 
				
			||||
    port: 587
 | 
				
			||||
    username: test@example.com
 | 
				
			||||
    password: testpassword
 | 
				
			||||
    properties:
 | 
				
			||||
      mail:
 | 
				
			||||
        smtp:
 | 
				
			||||
          auth: true
 | 
				
			||||
          starttls:
 | 
				
			||||
            enable: true
 | 
				
			||||
 | 
				
			||||
mybatis:
 | 
				
			||||
  mapper-locations: classpath:mapper/*.xml
 | 
				
			||||
  type-aliases-package: com.unilife.model.entity
 | 
				
			||||
  configuration:
 | 
				
			||||
    map-underscore-to-camel-case: true
 | 
				
			||||
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
 | 
				
			||||
 | 
				
			||||
logging:
 | 
				
			||||
  level:
 | 
				
			||||
    com.unilife: DEBUG
 | 
				
			||||
    org.springframework.web: DEBUG
 | 
				
			||||
  pattern:
 | 
				
			||||
    console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
 | 
				
			||||
 | 
				
			||||
# JWT配置
 | 
				
			||||
jwt:
 | 
				
			||||
  secret: test-secret-key-for-unit-testing-purposes-only
 | 
				
			||||
  expiration: 3600000
 | 
				
			||||
 | 
				
			||||
# 文件上传配置
 | 
				
			||||
file:
 | 
				
			||||
  upload:
 | 
				
			||||
    path: /tmp/unilife-test/uploads/
 | 
				
			||||
    max-size: 10MB
 | 
				
			||||
 | 
				
			||||
# 测试特定配置
 | 
				
			||||
test:
 | 
				
			||||
  mock:
 | 
				
			||||
    enabled: true
 | 
				
			||||
  database:
 | 
				
			||||
    cleanup: true 
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue