基于java的社交新闻媒体平台网站(源码+sql文件+开发报告+附下载链接)Java+Maven+sql+vue

社交新闻媒体平台网站

点我下载此资源》》》》》》》》》》》》》

capture_20250629034949458
capture_20250629035103754

一、开发环境介绍

使用软件:

  • 前端开发:IntelliJ IDEA 2025.1.2
  • 后端开发:IntelliJ IDEA 2025.1.2
  • 接口测试:Postman

前端开发:

  • 项目依赖:

    生产依赖(dependencies):

    • vue@3.5.17(核心框架)
    • vue-router@4.5.1(路由管理)
    • vuex@4.1.0(状态管理)
    • element-plus@2.10.2(UI 组件库)
    • @element-plus/icons-vue@2.3.1(Element Plus 图标库)
    • axios@1.10.0(HTTP 请求库)
    • core-js@3.43.0(JavaScript polyfill 库)
    • date-fns@4.1.0(日期处理工具)

    开发依赖(devDependencies):

    • @vue/cli-service@5.0.8(Vue CLI 核心服务)
    • @vue/cli-plugin-babel@5.0.8(Babel 插件)
    • @vue/cli-plugin-eslint@5.0.8(ESLint 插件)
    • @vue/cli-plugin-router@5.0.8(路由插件)
    • @vue/cli-plugin-vuex@5.0.8(Vuex 插件)
    • @babel/core@7.27.4(Babel 核心)
    • @babel/eslint-parser@7.27.5(Babel ESLint 解析器)
    • eslint@7.32.0(代码检查工具)
    • eslint-plugin-vue@8.7.1(Vue 专用 ESLint 插件)
    • sass@1.89.2(SASS 编译器)
    • sass-loader@12.6.0(Webpack 处理 SASS 的加载器)

后端开发:

  • 开发语言:Java

  • 包管理:Maven

  • 项目依赖

    主要依赖:

    • jackson-datatype-jsr310 (Jackson JSR310 时间支持)

    • lombok (简化 Java 代码的注解工具)

    • mysql-connector-j (MySQL 驱动)

    • mybatis-spring-boot-starter:3.0.2 (MyBatis 框架)

    • spring-boot-starter-web (Spring Boot Web 支持)

    测试相关依赖:spring-boot-starter-test

    构建插件:spring-boot-maven-plugin

三、数据库设计

3.1 用户表 (users)

存储用户的基本信息,包括用户名、密码、邮箱、头像、角色等,并确保用户名唯一。
CREATE TABLE IF NOT EXISTS users (
    id BIGINT NOT NULL AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(100) NOT NULL,
    email VARCHAR(100),
    avatar VARCHAR(255),
    bio VARCHAR(255),
    role VARCHAR(10) DEFAULT 'USER' COMMENT '用户角色:ADMIN-管理员,USER-普通用户',
    create_time DATETIME NOT NULL,
    update_time DATETIME NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY uk_username (username)
);

capture_20250629004600323

3.2 帖子表(posts)

功能:存储帖子内容,关联发帖用户(外键引用 users 表),并记录点赞数和评论数。
CREATE TABLE IF NOT EXISTS posts (
    id BIGINT NOT NULL AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    content TEXT NOT NULL,
    image MEDIUMTEXT,
    create_time DATETIME NOT NULL,
    update_time DATETIME NOT NULL,
    like_count INT DEFAULT 0,
    comment_count INT DEFAULT 0,
    PRIMARY KEY (id),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

capture_20250629004633613

3.3 评论表(comments)

功能:存储用户对帖子的评论内容,关联评论用户和对应的帖子。
CREATE TABLE IF NOT EXISTS comments (
    id BIGINT NOT NULL AUTO_INCREMENT,
    post_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    content TEXT NOT NULL,
    create_time DATETIME NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (post_id) REFERENCES posts(id),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

capture_20250629004659803

3.4 点赞表(likes)

功能:记录用户对帖子的点赞行为,防止重复点赞(通过唯一索引 uk_post_user)。
CREATE TABLE IF NOT EXISTS likes (
    id BIGINT NOT NULL AUTO_INCREMENT,
    post_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    create_time DATETIME NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY uk_post_user (post_id, user_id),
    FOREIGN KEY (post_id) REFERENCES posts(id),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

capture_20250629004659803

3.5 私信表(messages)

功能:存储用户之间的私信内容,包含发送者、接收者、消息是否已读状态及发送时间。
CREATE TABLE IF NOT EXISTS messages (
    id BIGINT NOT NULL AUTO_INCREMENT,
    sender_id BIGINT NOT NULL,
    receiver_id BIGINT NOT NULL,
    content TEXT NOT NULL,
    is_read BOOLEAN DEFAULT FALSE,
    create_time DATETIME NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (sender_id) REFERENCES users(id),
    FOREIGN KEY (receiver_id) REFERENCES users(id)
);

capture_20250629004651891

3.6 通知表(notifications)

功能:记录系统生成的通知(如点赞、评论、私信),包含通知类型、来源对象、目标用户及是否已读状态。
CREATE TABLE IF NOT EXISTS notifications (
    id BIGINT NOT NULL AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    type VARCHAR(20) NOT NULL, -- LIKE, COMMENT, MESSAGE
    source_id BIGINT NOT NULL,
    source_user_id BIGINT NOT NULL,
    is_read BOOLEAN DEFAULT FALSE,
    content VARCHAR(255) NOT NULL,
    create_time DATETIME NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (source_user_id) REFERENCES users(id)
);

capture_20250629004643254

四、后端结构简介

4.1 配置类(config包)

  • CorsConfig.java: 实现跨域请求配置。

    • 实现跨域请求配置。
    • 允许所有来源访问所有路径 (/**)
    • 支持 GET/POST/PUT/DELETE/OPTIONS 方法
    • 允许所有请求头,支持凭据,最大预检请求缓存时间为 3600 秒
    // ... existing code ...
    @Configuration
    public class CorsConfig {
    
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurer() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                            .allowedOrigins("*")
                            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                            .allowedHeaders("*")
                            .allowCredentials(true)
                            .maxAge(3600);
                }
            };
        }
    }
    
  • JacksonConfig.java: 定义JSON序列化方式,特别是处理LocalDateTime类型。

    • 定义 JSON 序列化方式。
    • 注册 JavaTimeModule 模块以支持 LocalDateTime 类型
    • 自定义 LocalDateTime 的序列化格式为 “yyyy-MM-dd HH:mm:ss”
    package com.socialplatform.config;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    
    import java.time.format.DateTimeFormatter;
    import java.time.LocalDateTime;
    import java.util.Locale;
    
    @Configuration
    public class JacksonConfig {
    
        @Bean
        public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
            ObjectMapper mapper = new ObjectMapper();
            
            // 注册 JavaTimeModule 模块以支持 Java 8 的日期/时间类型
            mapper.registerModule(new JavaTimeModule());
            
            // 自定义 LocalDateTime 序列化格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
            mapper.setDateFormat(new LocalDateTimeSerializer(formatter).getDateFormat());
            
            MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
            converter.setObjectMapper(mapper);
            return converter;
        }
    }
    
  • WebConfig.java: Web层通用配置,包括静态资源路径、拦截器注册等。

    • Web 层通用配置。
    • 静态资源路径映射:
      • /uploads/** 映射到 file:uploads/
      • 所有路径 /** 映射到 classpath:/static/
    • 拦截器注册:实现会话拦截器,对未登录用户返回 401 状态码
    // ... existing code ...
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(sessionInterceptor())
                    .addPathPatterns("/**")
                    .excludePathPatterns("/api/auth/login", "/api/auth/register");
        }
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/uploads/**")
                    .addResourceLocations("file:uploads/");
                    
            registry.addResourceHandler("/**")
                    .addResourceLocations("classpath:/static/");
        }
    
        @Bean
        public HandlerInterceptor sessionInterceptor() {
            return new HandlerInterceptor() {
                @Override
                public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                    HttpSession session = request.getSession(false);
                    if (session == null && !request.getRequestURI().startsWith("/api/auth")) {
                        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                        return false;
                    }
                    return true;
                }
            };
        }
    }
    

4.2 控制器层(controller包)

负责接收 HTTP 请求,调用服务层并返回响应

AuthController.java

  • 认证接口。
  • 登录接口 /login:接收用户名密码,返回用户基本信息并设置 Session
  • 注册接口 /register:创建新用户并自动登录
// ... existing code ...
    /**
     * 用户登录
     */
    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody Map<String, String> loginForm, HttpSession session) {
        String username = loginForm.get("username");
        String password = loginForm.get("password");
        
        Optional<User> userOpt = userService.login(username, password);
        
        if (userOpt.isPresent()) {
            User user = userOpt.get();
            session.setAttribute("currentUser", user);
            
            // 返回用户信息(不包含密码)
            Map<String, Object> response = new HashMap<>();
            response.put("id", user.getId());
            response.put("username", user.getUsername());
            response.put("avatar", user.getAvatar());
            response.put("role", user.getRole());
            return ResponseEntity.ok(response);
        } else {
            Map<String, String> error = new HashMap<>();
            error.put("message", "用户名或密码错误");
            return ResponseEntity.badRequest().body(error);
        }
    }
    
    /**
     * 用户注册
     */
    @PostMapping("/register")
    public ResponseEntity<?> register(@RequestBody User user, HttpSession session) {
        User currentSessionUser = (User) session.getAttribute("currentUser");
        if (currentSessionUser != null) {
            session.invalidate();
            session = null;
        }
        
        try {
            Optional<User> registeredUserOpt = userService.register(user);
            
            if (registeredUserOpt.isPresent()) {
                User registeredUser = registeredUserOpt.get();
                Map<String, Object> response = new HashMap<>();
                response.put("message", "注册成功");
                response.put("id", registeredUser.getId());
                response.put("username", registeredUser.getUsername());
                return ResponseEntity.ok(response);
            } else {
                Map<String, String> error = new HashMap<>();
                error.put("message", "用户名已存在");
                return ResponseEntity.badRequest().body(error);
            }
        } catch (Exception e) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "注册失败:" + e.getMessage());
            return ResponseEntity.status(500).body(error);
        }
    }
// ... existing code ...

UserController.java

  • 用户接口。
  • 获取用户详情 /users/{id}:过滤敏感字段(如密码)
  • 获取所有用户列表 /users:返回用户列表并过滤敏感字段
  • 更新用户信息 /users/{id}:只更新非空字段
  • 删除用户 /users/{id}:删除指定 ID 的用户
// ... existing code ...
    /**
     * 获取所有用户列表
     */
    @GetMapping
    public ResponseEntity<ApiResponse<Iterable<Map<String, Object>>>> getAllUsers() {
        Iterable<User> users = userService.getAllUsers();
        Iterable<Map<String, Object>> filteredUsers = () -> {
            return new Iterator<>() {
                private final Iterator<User> userIterator = users.iterator();
                
                @Override
                public boolean hasNext() {
                    return userIterator.hasNext();
                }

                @Override
                public Map<String, Object> next() {
                    User user = userIterator.next();
                    Map<String, Object> filteredUser = new HashMap<>();
                    filteredUser.put("id", user.getId());
                    filteredUser.put("username", user.getUsername());
                    filteredUser.put("avatar", user.getAvatar());
                    filteredUser.put("role", user.getRole());
                    return filteredUser;
                }
            };
        };
        
        return ResponseEntity.ok(ApiResponse.success(filteredUsers));
    }
    
    /**
     * 更新用户信息
     */
    @PutMapping("/{id}")
    public ResponseEntity<ApiResponse<?>> updateUser(@PathVariable Long id, @RequestBody User userUpdate) {
        Optional<User> updatedUserOpt = userService.updateUser(id, userUpdate);
        
        if (updatedUserOpt.isPresent()) {
            Map<String, String> response = new HashMap<>();
            response.put("message", "用户更新成功");
            return ResponseEntity.ok(ApiResponse.success(response));
        } else {
            return ResponseEntity.ok(ApiResponse.error("用户不存在"));
        }
    }
    
    /**
     * 删除用户
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<ApiResponse<?>> deleteUser(@PathVariable Long id) {
        boolean deleted = userService.deleteUser(id);
        
        if (deleted) {
            Map<String, String> response = new HashMap<>();
            response.put("message", "用户删除成功");
            return ResponseEntity.ok(ApiResponse.success(response));
        } else {
            return ResponseEntity.ok(ApiResponse.error("用户不存在"));
        }
    }
// ... existing code ...

PostController.java

  • 帖子接口。
  • 创建帖子 /posts:需登录后操作,自动绑定当前用户 ID
  • 获取所有帖子 /posts:返回所有帖子数据
  • 根据 ID 获取帖子 /posts/{id}:返回指定 ID 的帖子
  • 更新帖子 /posts/{id}:仅限原作者修改
  • 删除帖子 /posts/{id}:仅限原作者删除
// ... existing code ...
    /**
     * 获取所有帖子
     */
    @GetMapping
    public ResponseEntity<List<Post>> getAllPosts(HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        List<Post> posts;
        
        if (currentUser != null) {
            posts = postService.getAllPostsWithUserInfo(currentUser.getId());
        } else {
            posts = postService.getAllPosts();
        }
        
        return ResponseEntity.ok(posts);
    }
    
    /**
     * 获取帖子详情
     */
    @GetMapping("/{id}")
    public ResponseEntity<?> getPostById(@PathVariable Long id, HttpSession session) {
        Post post = postService.getPostById(id);
        
        if (post != null) {
            User currentUser = (User) session.getAttribute("currentUser");
            if (currentUser != null) {
                // 这里应该调用LikeService检查用户是否点赞过帖子
            }
            
            return ResponseEntity.ok(post);
        } else {
            Map<String, String> error = new HashMap<>();
            error.put("message", "帖子不存在");
            return ResponseEntity.badRequest().body(error);
        }
    }
    
    /**
     * 创建帖子
     */
    @PostMapping
    public ResponseEntity<?> createPost(@RequestBody Post post, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        
        if (currentUser == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "未登录");
            return ResponseEntity.status(401).body(error);
        }
        
        try {
            if (post.getImage() != null && post.getImage().length() > 0) {
                if (post.getImage().length() > 1024 * 1024) {
                    Map<String, String> error = new HashMap<>();
                    error.put("message", "图片数据过大,请压缩后重试");
                    return ResponseEntity.badRequest().body(error);
                }
            }
            
            post.setUserId(currentUser.getId());
            Post createdPost = postService.createPost(post);
            
            return ResponseEntity.ok(createdPost);
        } catch (Exception e) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "发布失败:" + e.getMessage());
            return ResponseEntity.status(500).body(error);
        }
    }
    
    /**
     * 更新帖子
     */
    @PutMapping("/{id}")
    public ResponseEntity<?> updatePost(@PathVariable Long id, @RequestBody Post post, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        
        if (currentUser == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "未登录");
            return ResponseEntity.status(401).body(error);
        }
        
        Post existingPost = postService.getPostById(id);
        
        if (existingPost == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "帖子不存在");
            return ResponseEntity.badRequest().body(error);
        }
        
        if (!existingPost.getUserId().equals(currentUser.getId())) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "无权限修改此帖子");
            return ResponseEntity.status(403).body(error);
        }
        
        try {
            if (post.getImage() != null && post.getImage().length() > 0) {
                if (post.getImage().length() > 1024 * 1024) {
                    Map<String, String> error = new HashMap<>();
                    error.put("message", "图片数据过大,请压缩后重试");
                    return ResponseEntity.badRequest().body(error);
                }
            }
            
            post.setId(id);
            post.setUserId(currentUser.getId());
            Post updatedPost = postService.updatePost(post);
            
            return ResponseEntity.ok(updatedPost);
        } catch (Exception e) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "更新失败:" + e.getMessage());
            return ResponseEntity.status(500).body(error);
        }
    }
    
    /**
     * 删除帖子
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<?> deletePost(@PathVariable Long id, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        
        if (currentUser == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "未登录");
            return ResponseEntity.status(401).body(error);
        }
        
        boolean success = false;
        String successMessage = "";
        
        if (currentUser.isAdmin()) {
            success = postService.deletePostByAdmin(id);
            successMessage = "管理员删除帖子成功";
        } else {
            success = postService.deletePost(id, currentUser.getId());
            successMessage = "帖子删除成功";
        }
        
        if (success) {
            Map<String, String> response = new HashMap<>();
            response.put("message", successMessage);
            return ResponseEntity.ok(response);
        } else {
            Map<String, String> error = new HashMap<>();
            error.put("message", "帖子不存在或无权限删除");
            return ResponseEntity.badRequest().body(error);
        }
    }
// ... existing code ...

CommentController.java

  • 评论接口。

  • 添加评论 /comments:需登录后操作,自动绑定当前用户 ID

  • 获取帖子的所有评论 /comments/post/{postId}:返回指定帖子的评论

列表

  • 更新评论 /comments/{id}:仅限原评论者修改
  • 删除评论 /comments/{id}:仅限原评论者删除
// ... existing code ...
    /**
     * 获取帖子评论列表
     */
    @GetMapping("/post/{postId}")
    public ResponseEntity<List<Comment>> getCommentsByPostId(@PathVariable Long postId) {
        List<Comment> comments = commentService.getCommentsByPostId(postId);
        return ResponseEntity.ok(comments);
    }
    
    /**
     * 添加评论
     */
    @PostMapping
    public ResponseEntity<?> addComment(@RequestBody Comment comment, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        
        if (currentUser == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "未登录");
            return ResponseEntity.status(401).body(error);
        }
        
        comment.setUserId(currentUser.getId());
        
        try {
            Comment addedComment = commentService.addComment(comment);
            return ResponseEntity.ok(addedComment);
        } catch (Exception e) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "添加评论失败: " + e.getMessage());
            return ResponseEntity.status(500).body(error);
        }
    }
    
    /**
     * 删除评论(用户删除自己的评论,管理员可删除任意评论)
     */
    @DeleteMapping("/{commentId}")
    public ResponseEntity<?> deleteComment(@PathVariable Long commentId, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        
        if (currentUser == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "未登录");
            return ResponseEntity.status(401).body(error);
        }
        
        Comment comment = commentService.getCommentById(commentId);
        
        if (comment == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "评论不存在");
            return ResponseEntity.badRequest().body(error);
        }
        
        boolean success = false;
        
        if (currentUser.isAdmin()) {
            success = commentService.deleteCommentByAdmin(commentId);
        } else if (currentUser.getId().equals(comment.getUserId())) {
            success = commentService.deleteComment(commentId, currentUser.getId());
        } else {
            Map<String, String> error = new HashMap<>();
            error.put("message", "无权限删除此评论");
            return ResponseEntity.status(403).body(error);
        }
        
        if (success) {
            Map<String, Object> response = new HashMap<>();
            response.put("message", "评论删除成功");
            return ResponseEntity.ok(response);
        } else {
            Map<String, String> error = new HashMap<>();
            error.put("message", "评论删除失败");
            return ResponseEntity.status(500).body(error);
        }
    }
// ... existing code ...

LikeController.java

  • 点赞接口。
  • 点赞帖子 /likes/{postId}:需登录后操作,防止重复点赞
  • 取消点赞 /likes/{postId}:根据用户ID和帖子ID删除点赞记录
  • 获取帖子的点赞数 /likes/{postId}/count:返回帖子的点赞总数
// ... existing code ...
    /**
     * 点赞帖子
     */
    @PostMapping("/{postId}")
    public ResponseEntity<?> likePost(@PathVariable Long postId, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        
        if (currentUser == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "未登录");
            return ResponseEntity.status(401).body(error);
        }
        
        Like like = likeService.likePost(postId, currentUser.getId());
        
        if (like != null) {
            Map<String, Object> response = new HashMap<>();
            response.put("message", "点赞成功");
            response.put("likeCount", likeService.getLikeCount(postId));
            return ResponseEntity.ok(response);
        } else {
            Map<String, String> error = new HashMap<>();
            error.put("message", "已经点赞过了");
            return ResponseEntity.badRequest().body(error);
        }
    }
    
    /**
     * 取消点赞
     */
    @DeleteMapping("/{postId}")
    public ResponseEntity<?> unlikePost(@PathVariable Long postId, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        
        if (currentUser == null) {
            Map<String, String> error = new HashMap<>();
            error.put("message", "未登录");
            return ResponseEntity.status(401).body(error);
        }
        
        boolean success = likeService.unlikePost(postId, currentUser.getId());
        
        if (success) {
            Map<String, Object> response = new HashMap<>();
            response.put("message", "取消点赞成功");
            response.put("likeCount", likeService.getLikeCount(postId));
            return ResponseEntity.ok(response);
        } else {
            Map<String, String> error = new HashMap<>();
            error.put("message", "未点赞或操作失败");
            return ResponseEntity.badRequest().body(error);
        }
    }
// ... existing code ...

MessageController.java

  • 发送私信:用户可以向其他用户发送私信。
  • 获取对话记录:查看与某个用户的完整私信往来,并标记对方发送的消息为已读。
  • 获取联系人列表:列出所有有私信往来的用户。
  • 获取未读消息:获取当前用户所有未读的私信内容。
  • 获取未读消息数量:统计当前用户的未读私信总数。
  • 标记消息为已读:将某条消息标记为已读状态。
  • 删除消息:删除指定的私信。
// ... existing code ...
    /**
     * 发送私信
     */
    @PostMapping
    public ResponseEntity<?> sendMessage(@RequestBody Message message, @SessionAttribute("currentUser") User user) {
        message.setSenderId(user.getId());
        messageService.sendMessage(message);
        return ResponseEntity.ok(Map.of("success", true));
    }

    /**
     * 获取与特定用户的对话
     */
    @GetMapping("/conversation/{userId}")
    public ResponseEntity<?> getConversation(@PathVariable Long userId, @SessionAttribute("currentUser") User user) {
        List<Message> conversation = messageService.getConversation(user.getId(), userId);
        List<MessageDTO> messageDTOs = conversation.stream()
                .map(MessageDTO::new)
                .peek(dto -> dto.setSelf(dto.getSenderId().equals(user.getId())))
                .collect(Collectors.toList());
                
        messageService.markConversationAsRead(user.getId(), userId);                
        return ResponseEntity.ok(messageDTOs);
    }

    /**
     * 获取联系人列表
     */
    @GetMapping("/contacts")
    public ResponseEntity<?> getContacts(@SessionAttribute("currentUser") User user) {
        List<Map<String, Object>> contacts = messageService.getContacts(user.getId());
        return ResponseEntity.ok(contacts);
    }

    /**
     * 获取未读消息
     */
    @GetMapping("/unread")
    public ResponseEntity<?> getUnreadMessages(@SessionAttribute("currentUser") User user) {
        List<Message> unreadMessages = messageService.getUnreadMessages(user.getId());
        List<MessageDTO> messageDTOs = unreadMessages.stream()
                .map(MessageDTO::new)
                .collect(Collectors.toList());
        return ResponseEntity.ok(messageDTOs);
    }

    /**
     * 获取未读消息数量
     */
    @GetMapping("/unread/count")
    public ResponseEntity<?> getUnreadMessagesCount(@SessionAttribute("currentUser")

NotificationController.java

  • 通知接口。
  • 获取用户的通知列表 /notifications/user/{userId}:返回指定用户的全部通知
  • 标记通知为已读 /notifications/{id}/read:将指定 ID 的通知标记为已读
  • 删除通知 /notifications/{id}:删除指定 ID 的通知
// ... existing code ...
    /**
     * 获取通知列表(分页)
     */
    @GetMapping
    public ResponseEntity<?> getNotifications(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int pageSize,
            @SessionAttribute("currentUser") User user) {
        
        List<Notification> notifications = notificationService.getNotifications(user.getId(), page, pageSize);
        int total = notificationService.getNotificationCount(user.getId());
        
        Map<String, Object> response = new HashMap<>();
        response.put("notifications", notifications);
        response.put("total", total);
        response.put("page", page);
        response.put("pageSize", pageSize);
        
        return ResponseEntity.ok(response);
    }

    /**
     * 标记通知为已读
     */
    @PutMapping("/{id}/read")
    public ResponseEntity<?> markAsRead(@PathVariable Long id) {
        notificationService.markAsRead(id);
        return ResponseEntity.ok(Map.of("success", true));
    }

    /**
     * 删除通知
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteNotification(@PathVariable Long id) {
        notificationService.deleteNotification(id);
        return ResponseEntity.ok(Map.of("success", true));
    }
// ... existing code ...

4.3 数据传输对象(dto包)

功能: 定义了统一的 API 响应结构。

  • ApiResponse.java: 封装统一的API响应格式。
/**
 * 统一API响应类
 */
public class ApiResponse<T> {
    
    private Integer code;
    private String message;
    private T data;
    private Boolean success;
    
    public ApiResponse() {}
    
    public ApiResponse(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
        this.success = code == 200;
    }

4.4 模型层(model包)

功能: 定义了业务实体类,映射数据库表。

  • User.java - 用户实体

    •     private Long id;
          private Long postId;
          private Long userId;
          private String content;
          private Date createTime;
          private User user;
      
  • Post.java - 帖子实体

  • Comment.java - 评论实体

  • Like.java - 点赞实体

    •     private Long id;
          private Long postId;
          private Long userId;
          private Date createTime;
      
  • Message.java - 私信实体

    •     private Long id;
          private Long senderId;
          private Long receiverId;
          private String content;
          private boolean isRead;
          
          @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
          private LocalDateTime createTime;
          
          // Additional fields for frontend display
          private String senderUsername;
          private String senderAvatar;
          private String receiverUsername;
          private String receiverAvatar;
      
  • MessageDTO.java - 私信数据传输对象

    •     private Long id;
          private Long senderId;
          private Long receiverId;
          private String content;
          private boolean isRead;
          private String createTime; 
          
          // Additional fields for frontend display
          private String senderUsername;
          private String senderAvatar;
          private String receiverUsername;
          private String receiverAvatar;
          private boolean isSelf; // 前端需要的字段
      
  • Notification.java - 通知实体

    •     private Long id;
          private Long userId;          // 接收通知的用户ID
          private String type;          // 通知类型: LIKE, COMMENT, MESSAGE
          private Long sourceId;        // 通知来源ID (例如: 帖子ID, 评论ID, 消息ID)
          private Long sourceUserId;    // 触发通知的用户ID
          private boolean isRead;       // 是否已读
          private String content;       // 通知内容
          
          @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
          private LocalDateTime createTime;
          
          // Additional fields for display
          private String sourceUsername;
          private String sourceUserAvatar;
      

4.5 数据访问层(repository包)

  • 功能: 数据访问层,定义了与数据库交互的接口。

  • 关键方法:

    • MessageMapper: 管理私信数据,支持发送、读取、标记为已读等操作。

      @Insert("INSERT INTO messages (sender_id, receiver_id, content, is_read, create_time) " +
                  "VALUES (#{senderId}, #{receiverId}, #{content}, #{isRead}, #{createTime})")
          @Options(useGeneratedKeys = true, keyProperty = "id")
          int insert(Message message);
          
          @Select("SELECT m.*, " +
                  "sender.username as senderUsername, sender.avatar as senderAvatar, " +
                  "receiver.username as receiverUsername, receiver.avatar as receiverAvatar " +
                  "FROM messages m " +
                  "JOIN users sender ON m.sender_id = sender.id " +
                  "JOIN users receiver ON m.receiver_id = receiver.id " +
                  "WHERE m.id = #{id}")
          Message findById(Long id);
          
          @Select("SELECT m.*, " +
                  "sender.username as senderUsername, sender.avatar as senderAvatar, " +
                  "receiver.username as receiverUsername, receiver.avatar as receiverAvatar " +
                  "FROM messages m " +
                  "JOIN users sender ON m.sender_id = sender.id " +
                  "JOIN users receiver ON m.receiver_id = receiver.id " +
                  "WHERE (m.sender_id = #{userId1} AND m.receiver_id = #{userId2}) " +
                  "OR (m.sender_id = #{userId2} AND m.receiver_id = #{userId1}) " +
                  "ORDER BY m.create_time ASC")
          List<Message> findConversation(@Param("userId1") Long userId1, @Param("userId2") Long userId2);
          
          @Select("SELECT m.*, " +
                  "sender.username as senderUsername, sender.avatar as senderAvatar " +
                  "FROM messages m " +
                  "JOIN users sender ON m.sender_id = sender.id " +
                  "WHERE m.receiver_id = #{userId} " +
                  "AND m.is_read = false " +
                  "ORDER BY m.create_time DESC")
          List<Message> findUnreadMessages(Long userId);
          
          @Update("UPDATE messages SET is_read = true WHERE id = #{id}")
          int markAsRead(Long id);
          
          @Update("UPDATE messages SET is_read = true WHERE receiver_id = #{receiverId} AND sender_id = #{senderId}")
          int markConversationAsRead(@Param("receiverId") Long receiverId, @Param("senderId") Long senderId);
          
          @Delete("DELETE FROM messages WHERE id = #{id}")
          int delete(Long id);
          
          /**
           * 删除用户发送的所有消息(用于删除用户时的级联删除)
           */
          @Delete("DELETE FROM messages WHERE sender_id = #{senderId}")
          int deleteBySenderId(@Param("senderId") Long senderId);
          
          /**
           * 删除用户接收的所有消息(用于删除用户时的级联删除)
           */
          @Delete("DELETE FROM messages WHERE receiver_id = #{receiverId}")
          int deleteByReceiverId(@Param("receiverId") Long receiverId);
          
          // Get a list of distinct users who have sent or received messages from/to the specified user
          @Select("SELECT DISTINCT " +
                  "u.id, u.username, u.avatar, " +
                  "(SELECT MAX(m2.create_time) FROM messages m2 " +
                  " WHERE (m2.sender_id = #{userId} AND m2.receiver_id = u.id) " +
                  "    OR (m2.sender_id = u.id AND m2.receiver_id = #{userId})) as last_message_time " +
                  "FROM users u " +
                  "WHERE u.id IN (" +
                  "  SELECT DISTINCT CASE " +
                  "    WHEN m.sender_id = #{userId} THEN m.receiver_id " +
                  "    ELSE m.sender_id " +
                  "  END " +
                  "  FROM messages m " +
                  "  WHERE m.sender_id = #{userId} OR m.receiver_id = #{userId}" +
                  ") " +
                  "ORDER BY last_message_time DESC")
          List<Map<String, Object>> findContactsByUserId(Long userId);
      
    • CommentMapper: 管理评论数据,支持增删查改。

      /**
           * 添加评论
           */
          @Insert("INSERT INTO comments(post_id, user_id, content, create_time) VALUES(#{postId}, #{userId}, #{content}, NOW())")
          @Options(useGeneratedKeys = true, keyProperty = "id")
          int insert(Comment comment);
          
          /**
           * 删除评论(用户只能删除自己的评论)
           */
          @Delete("DELETE FROM comments WHERE id = #{id} AND user_id = #{userId}")
          int delete(@Param("id") Long id, @Param("userId") Long userId);
          
          /**
           * 管理员删除评论(可删除任意评论)
           */
          @Delete("DELETE FROM comments WHERE id = #{id}")
          int deleteByAdmin(@Param("id") Long id);
          
          /**
           * 删除帖子的所有评论(用于级联删除)
           */
          @Delete("DELETE FROM comments WHERE post_id = #{postId}")
          int deleteByPostId(@Param("postId") Long postId);
          
          /**
           * 根据ID查询评论
           */
          @Select("SELECT * FROM comments WHERE id = #{id}")
          Comment findById(Long id);
          
          /**
           * 获取帖子评论数
           */
          @Select("SELECT COUNT(*) FROM comments WHERE post_id = #{postId}")
          int countByPostId(Long postId);
          
          /**
           * 获取帖子的所有评论
           */
          @Select("SELECT * FROM comments WHERE post_id = #{postId} ORDER BY create_time DESC")
          List<Comment> findByPostId(Long postId);
          
          /**
           * 获取所有评论(管理员功能)
           */
          @Select("SELECT * FROM comments ORDER BY create_time DESC")
          List<Comment> findAll();
          
          /**
           * 获取用户的所有评论
           */
          @Select("SELECT * FROM comments WHERE user_id = #{userId} ORDER BY create_time DESC")
          List<Comment> findByUserId(Long userId);
          
          /**
           * 批量获取帖子的评论数
           */
          @Select({
              "<script>",
              "SELECT post_id, COUNT(*) as count FROM comments",
              "WHERE post_id IN",
              "<foreach collection='postIds' item='id' open='(' separator=',' close=')'>",
              "#{id}",
              "</foreach>",
              "GROUP BY post_id",
              "</script>"
          })
          List<Object[]> countByPostIds(@Param("postIds") List<Long> postIds);
      
    • LikeMapper: 管理点赞数据,支持点赞、取消点赞。

      /**
           * 添加点赞
           */
          @Insert("INSERT INTO likes(post_id, user_id, create_time) VALUES(#{postId}, #{userId}, NOW())")
          @Options(useGeneratedKeys = true, keyProperty = "id")
          int insert(Like like);
          
          /**
           * 取消点赞
           */
          @Delete("DELETE FROM likes WHERE post_id = #{postId} AND user_id = #{userId}")
          int delete(@Param("postId") Long postId, @Param("userId") Long userId);
          
          /**
           * 删除帖子的所有点赞记录(用于级联删除)
           */
          @Delete("DELETE FROM likes WHERE post_id = #{postId}")
          int deleteByPostId(@Param("postId") Long postId);
          
          /**
           * 删除用户的所有点赞记录(用于删除用户时的级联删除)
           */
          @Delete("DELETE FROM likes WHERE user_id = #{userId}")
          int deleteByUserId(@Param("userId") Long userId);
          
          /**
           * 查询用户是否点赞过帖子
           */
          @Select("SELECT COUNT(*) FROM likes WHERE post_id = #{postId} AND user_id = #{userId}")
          boolean exists(@Param("postId") Long postId, @Param("userId") Long userId);
          
          /**
           * 获取帖子点赞数
           */
          @Select("SELECT COUNT(*) FROM likes WHERE post_id = #{postId}")
          int countByPostId(Long postId);
          
          /**
           * 获取帖子的所有点赞
           */
          @Select("SELECT * FROM likes WHERE post_id = #{postId}")
          List<Like> findByPostId(Long postId);
          
          /**
           * 获取用户的所有点赞
           */
          @Select("SELECT * FROM likes WHERE user_id = #{userId}")
          List<Like> findByUserId(Long userId);
          
          /**
           * 批量获取帖子的点赞数
           */
          @Select({
              "<script>",
              "SELECT post_id, COUNT(*) as count FROM likes",
              "WHERE post_id IN",
              "<foreach collection='postIds' item='id' open='(' separator=',' close=')'>",
              "#{id}",
              "</foreach>",
              "GROUP BY post_id",
              "</script>"
          })
          List<Object[]> countByPostIds(@Param("postIds") List<Long> postIds);
      
    • NotificationMapper: 管理通知数据,支持创建、查询、标记已读。

      @Insert("INSERT INTO notifications (user_id, type, source_id, source_user_id, is_read, content, create_time) " +
                  "VALUES (#{userId}, #{type}, #{sourceId}, #{sourceUserId}, #{isRead}, #{content}, #{createTime})")
          @Options(useGeneratedKeys = true, keyProperty = "id")
          int insert(Notification notification);
          
          @Select("SELECT n.*, u.username as sourceUsername, u.avatar as sourceUserAvatar " +
                  "FROM notifications n " +
                  "LEFT JOIN users u ON n.source_user_id = u.id " +
                  "WHERE n.id = #{id}")
          Notification findById(Long id);
          
          @Select("SELECT n.*, u.username as sourceUsername, u.avatar as sourceUserAvatar " +
                  "FROM notifications n " +
                  "LEFT JOIN users u ON n.source_user_id = u.id " +
                  "WHERE n.user_id = #{userId} " +
                  "ORDER BY n.create_time DESC " +
                  "LIMIT #{limit} OFFSET #{offset}")
          List<Notification> findByUserId(@Param("userId") Long userId, 
                                         @Param("offset") int offset, 
                                         @Param("limit") int limit);
          
          @Select("SELECT COUNT(*) FROM notifications WHERE user_id = #{userId}")
          int countByUserId(Long userId);
          
          @Select("SELECT COUNT(*) FROM notifications WHERE user_id = #{userId} AND is_read = false")
          int countUnreadByUserId(Long userId);
          
          @Update("UPDATE notifications SET is_read = true WHERE id = #{id}")
          int markAsRead(Long id);
          
          @Update("UPDATE notifications SET is_read = true WHERE user_id = #{userId}")
          int markAllAsRead(Long userId);
          
          @Delete("DELETE FROM notifications WHERE id = #{id}")
          int delete(Long id);
          
          @Delete("DELETE FROM notifications WHERE user_id = #{userId} AND is_read = true")
          int deleteAllRead(Long userId);
          
          /**
           * 删除用户的所有通知记录(用于删除用户时的级联删除)
           */
          @Delete("DELETE FROM notifications WHERE user_id = #{userId}")
          int deleteByUserId(@Param("userId") Long userId);
      
    • PostMapper: 管理帖子数据,支持增删查改。

      /**
           * 插入帖子
           */
          @Insert("INSERT INTO posts (user_id, content, image, create_time, update_time) VALUES (#{userId}, #{content}, #{image}, NOW(), NOW())")
          @Options(useGeneratedKeys = true, keyProperty = "id")
          int insert(Post post);
          
          /**
           * 根据ID查询帖子
           */
          @Select("SELECT * FROM posts WHERE id = #{id}")
          Post findById(Long id);
          
          /**
           * 查询全部帖子,按创建时间倒序排序
           */
          @Select("SELECT * FROM posts ORDER BY create_time DESC")
          List<Post> findAll();
          
          /**
           * 查询用户的所有帖子
           */
          @Select("SELECT * FROM posts WHERE user_id = #{userId} ORDER BY create_time DESC")
          List<Post> findByUserId(Long userId);
          
          /**
           * 更新帖子
           */
          @Update("UPDATE posts SET content = #{content}, image = #{image}, update_time = NOW() WHERE id = #{id}")
          int update(Post post);
          
          /**
           * 删除帖子
           */
          @Delete("DELETE FROM posts WHERE id = #{id}")
          int deleteById(Long id);
      
    • UserMapper: 管理用户数据,支持注册、登录、增删查改。

      /**
       * 根据用户名查询用户
       */
      @Select("SELECT * FROM users WHERE username = #{username}")
      User findByUsername(String username);
      
      /**
       * 根据ID查询用户
       */
      @Select("SELECT * FROM users WHERE id = #{id}")
      User findById(Long id);
      
      /**
       * 插入新用户
       */
      @Insert("INSERT INTO users(username, password, avatar, email, bio, role, create_time, update_time) VALUES(#{username}, #{password}, #{avatar}, #{email}, #{bio}, #{role}, NOW(), NOW())")
      @Options(useGeneratedKeys = true, keyProperty = "id")
      int insert(User user);
      
      /**
       * 更新用户信息
       */
      @Update("UPDATE users SET username = #{username}, password = #{password}, avatar = #{avatar}, email = #{email}, bio = #{bio}, role = #{role}, update_time = NOW() WHERE id = #{id}")
      int update(User user);
      
      /**
       * 获取所有用户
       */
      @Select("SELECT * FROM users")
      List<User> findAll();
      
      /**
       * 删除用户
       */
      @Delete("DELETE FROM users WHERE id = #{id}")
      int deleteById(Long id);
      

4.6 业务逻辑层(service包)

  • 功能: 业务逻辑层,处理核心功能。

  • 关键接口及实现:

    • MessageService: 处理私信发送、获取对话记录、标记为已读等。

      @Autowired
      private MessageMapper messageMapper;
      
      @Autowired
      private NotificationService notificationService;
      
      @Override
      public Message sendMessage(Message message) {
          message.setCreateTime(LocalDateTime.now());
          message.setRead(false);
          messageMapper.insert(message);
          
          // Create a notification for the message recipient
          try {
              notificationService.createMessageNotification(message.getId(), message.getSenderId());
          } catch (Exception e) {
              // 记录异常但不影响消息发送功能
              System.err.println("创建消息通知失败: " + e.getMessage());
              // 不要将异常向上传播
          }
          
          return message;
      }
      
      @Override
      public Message getMessageById(Long id) {
          return messageMapper.findById(id);
      }
      
      @Override
      public List<Message> getConversation(Long userId1, Long userId2) {
          return messageMapper.findConversation(userId1, userId2);
      }
      
      @Override
      public List<Message> getUnreadMessages(Long userId) {
          return messageMapper.findUnreadMessages(userId);
      }
      
      @Override
      public void markAsRead(Long id) {
          messageMapper.markAsRead(id);
      }
      
      @Override
      public void markConversationAsRead(Long receiverId, Long senderId) {
          messageMapper.markConversationAsRead(receiverId, senderId);
      }
      
      @Override
      public void deleteMessage(Long id) {
          messageMapper.delete(id);
      }
      
      @Override
      public List<Map<String, Object>> getContacts(Long userId) {
          try {
              List<Map<String, Object>> contacts = messageMapper.findContactsByUserId(userId);
              
              // 为每个联系人添加最后一条消息内容和未读状态
              for (Map<String, Object> contact : contacts) {
                  Long contactId = ((Number) contact.get("id")).longValue();
                  
                  // 获取与此联系人的最后一条消息
                  List<Message> conversation = messageMapper.findConversation(userId, contactId);
                  if (!conversation.isEmpty()) {
                      Message lastMessage = conversation.get(conversation.size() - 1);
                      contact.put("lastMessage", lastMessage.getContent());
                      // 将LocalDateTime转换为字符串以避免序列化问题
                      contact.put("lastTime", lastMessage.getCreateTime().toString());
                  } else {
                      contact.put("lastMessage", "");
                      // 处理可能的null值并转换为字符串
                      Object lastMessageTime = contact.get("last_message_time");
                      if (lastMessageTime != null) {
                          contact.put("lastTime", lastMessageTime.toString());
                      } else {
                          contact.put("lastTime", "");
                      }
                  }
                  
                  // 检查是否有未读消息
                  List<Message> unreadMessages = messageMapper.findUnreadMessages(userId);
                  boolean hasUnread = unreadMessages.stream()
                          .anyMatch(msg -> msg.getSenderId().equals(contactId));
                  contact.put("hasUnread", hasUnread);
                  
                  // 移除内部字段
                  contact.remove("last_message_time");
              }
              
              return contacts;
          } catch (Exception e) {
              // 记录错误并返回空列表,避免500错误
              System.err.println("获取联系人列表失败: " + e.getMessage());
              e.printStackTrace();
              return new ArrayList<>();
          }
      }
      
    • CommentService: 处理评论添加、删除、查询。

      @Autowired
      private CommentMapper commentMapper;
      
      @Autowired
      private UserMapper userMapper;
      
      @Autowired
      private NotificationService notificationService;
      
      @Override
      public Comment addComment(Comment comment) {
          // 确保评论数据完整性
          if (comment.getUserId() == null) {
              throw new IllegalArgumentException("用户ID不能为空");
          }
          
          // 验证用户是否存在
          User user = userMapper.findById(comment.getUserId());
          if (user == null) {
              throw new IllegalArgumentException("用户不存在: " + comment.getUserId());
          }
          
          System.out.println("添加评论 - 用户ID: " + comment.getUserId() + ", 用户名: " + user.getUsername());
          
          commentMapper.insert(comment);
          
          // 创建评论通知,添加错误处理避免影响主要功能
          try {
              notificationService.createCommentNotification(comment.getPostId(), comment.getId(), comment.getUserId());
          } catch (Exception e) {
              // 记录错误但继续执行
              System.err.println("创建评论通知失败,但不影响评论功能: " + e.getMessage());
          }
          
          // 重新查询用户信息确保数据一致性
          User freshUser = userMapper.findById(comment.getUserId());
          comment.setUser(freshUser);
          
          System.out.println("评论创建成功 - 评论ID: " + comment.getId() + ", 关联用户: " + (freshUser != null ? freshUser.getUsername() : "null"));
          
          return comment;
      }
      
      @Override
      public boolean deleteComment(Long commentId, Long userId) {
          return commentMapper.delete(commentId, userId) > 0;
      }
      
      @Override
      public boolean deleteCommentByAdmin(Long commentId) {
          return commentMapper.deleteByAdmin(commentId) > 0;
      }
      
      @Override
      public Comment getCommentById(Long commentId) {
          Comment comment = commentMapper.findById(commentId);
          if (comment != null) {
              // 查询评论用户信息
              User user = userMapper.findById(comment.getUserId());
              comment.setUser(user);
              
              System.out.println("查询评论 - ID: " + commentId + ", user_id: " + comment.getUserId() + ", 用户名: " + (user != null ? user.getUsername() : "null"));
          }
          return comment;
      }
      
      @Override
      public List<Comment> getCommentsByPostId(Long postId) {
          List<Comment> comments = commentMapper.findByPostId(postId);
          System.out.println("查询帖子评论 - 帖子ID: " + postId + ", 评论数量: " + comments.size());
          
          return enrichCommentsWithUserInfo(comments);
      }
      
      @Override
      public List<Comment> getAllComments() {
          List<Comment> comments = commentMapper.findAll();
          System.out.println("管理员查询所有评论 - 评论数量: " + comments.size());
          
          return enrichCommentsWithUserInfo(comments);
      }
      
      @Override
      public int getCommentCount(Long postId) {
          return commentMapper.countByPostId(postId);
      }
      
      @Override
      public Map<Long, Integer> batchGetCommentCounts(List<Long> postIds) {
          Map<Long, Integer> result = new HashMap<>();
          if (postIds == null || postIds.isEmpty()) {
              return result;
          }
          
          List<Object[]> counts = commentMapper.countByPostIds(postIds);
          for (Object[] count : counts) {
              Long postId = (Long) count[0];
              Integer commentCount = ((Number) count[1]).intValue();
              result.put(postId, commentCount);
          }
          
          // 确保所有帖子ID都有对应的评论数
          for (Long postId : postIds) {
              if (!result.containsKey(postId)) {
                  result.put(postId, 0);
              }
          }
          
          return result;
      }
      
      @Override
      public boolean deleteAllCommentsForPost(Long postId) {
          try {
              int deletedCount = commentMapper.deleteByPostId(postId);
              System.out.println("删除帖子 " + postId + " 的 " + deletedCount + " 条评论记录");
              return true; // 即使没有评论也算成功
          } catch (Exception e) {
              System.err.println("删除帖子评论失败: " + e.getMessage());
              return false;
          }
      }
      
      /**
       * 为评论列表添加用户信息
       */
      private List<Comment> enrichCommentsWithUserInfo(List<Comment> comments) {
          return comments.stream().map(comment -> {
              try {
                  User user = userMapper.findById(comment.getUserId());
                  comment.setUser(user);
                  
                  // 添加调试日志
                  System.out.println("关联用户信息 - 评论ID: " + comment.getId() + 
                                   ", user_id: " + comment.getUserId() + 
                                   ", 查询到的用户: " + (user != null ? user.getUsername() : "null"));
                  
                  return comment;
              } catch (Exception e) {
                  System.err.println("查询用户信息失败 - 评论ID: " + comment.getId() + ", user_id: " + comment.getUserId() + ", 错误: " + e.getMessage());
                  return comment;
              }
          }).collect(Collectors.toList());
      }
      
    • LikeService: 处理点赞、取消点赞、批量统计。

      @Autowired
      private LikeMapper likeMapper;
      
      @Autowired
      private NotificationService notificationService;
      
      @Override
      public Like likePost(Long postId, Long userId) {
          // 检查是否已经点赞
          if (hasLiked(postId, userId)) {
              return null;
          }
          
          Like like = new Like();
          like.setPostId(postId);
          like.setUserId(userId);
          
          likeMapper.insert(like);
          
          // 创建点赞通知,但不影响点赞功能
          try {
              notificationService.createLikeNotification(postId, userId);
          } catch (Exception e) {
              // 记录错误但继续执行
              System.err.println("创建点赞通知失败,但不影响点赞功能: " + e.getMessage());
          }
          
          return like;
      }
      
      @Override
      public boolean unlikePost(Long postId, Long userId) {
          return likeMapper.delete(postId, userId) > 0;
      }
      
      @Override
      public boolean hasLiked(Long postId, Long userId) {
          return likeMapper.exists(postId, userId);
      }
      
      @Override
      public int getLikeCount(Long postId) {
          return likeMapper.countByPostId(postId);
      }
      
      @Override
      public Map<Long, Integer> batchGetLikeCounts(List<Long> postIds) {
          Map<Long, Integer> result = new HashMap<>();
          if (postIds == null || postIds.isEmpty()) {
              return result;
          }
          
          List<Object[]> counts = likeMapper.countByPostIds(postIds);
          for (Object[] count : counts) {
              Long postId = (Long) count[0];
              Integer likeCount = ((Number) count[1]).intValue();
              result.put(postId, likeCount);
          }
          
          // 确保所有帖子ID都有对应的点赞数
          for (Long postId : postIds) {
              if (!result.containsKey(postId)) {
                  result.put(postId, 0);
              }
          }
          
          return result;
      }
      
      @Override
      public Map<Long, Boolean> batchCheckUserLikes(List<Long> postIds, Long userId) {
          Map<Long, Boolean> result = new HashMap<>();
          if (postIds == null || postIds.isEmpty() || userId == null) {
              return result;
          }
          
          // 获取用户所有点赞
          List<Like> userLikes = likeMapper.findByUserId(userId);
          Map<Long, Like> likeMap = new HashMap<>();
          for (Like like : userLikes) {
              likeMap.put(like.getPostId(), like);
          }
          
          // 检查每个帖子是否被点赞
          for (Long postId : postIds) {
              result.put(postId, likeMap.containsKey(postId));
          }
          
          return result;
      }
      
      @Override
      public boolean deleteAllLikesForPost(Long postId) {
          try {
              int deletedCount = likeMapper.deleteByPostId(postId);
              System.out.println("删除帖子 " + postId + " 的 " + deletedCount + " 个点赞记录");
              return true; // 即使没有点赞记录也算成功
          } catch (Exception e) {
              System.err.println("删除帖子点赞记录失败: " + e.getMessage());
              return false;
          }
      }
      
    • NotificationService: 创建通知(如点赞、评论、私信)、标记为已读。

      @Autowired
      private NotificationMapper notificationMapper;
      
      @Autowired
      private PostMapper postMapper;
      
      @Autowired
      private CommentMapper commentMapper;
      
      @Autowired
      private MessageMapper messageMapper;
      
      @Override
      public void createLikeNotification(Long postId, Long sourceUserId) {
          Post post = postMapper.findById(postId);
          if (post == null || post.getUserId().equals(sourceUserId)) {
              return; // Don't notify if post doesn't exist or user is liking their own post
          }
          
          Notification notification = new Notification();
          notification.setUserId(post.getUserId());
          notification.setType("LIKE");
          notification.setSourceId(postId);
          notification.setSourceUserId(sourceUserId);
          notification.setRead(false);
          notification.setContent("有人赞了你的帖子");
          notification.setCreateTime(LocalDateTime.now());
          
          notificationMapper.insert(notification);
      }
      
      @Override
      public void createCommentNotification(Long postId, Long commentId, Long sourceUserId) {
          Post post = postMapper.findById(postId);
          if (post == null) {
              return; // Don't notify if post doesn't exist
          }
          
          Comment comment = commentMapper.findById(commentId);
          if (comment == null) {
              return; // Don't notify if comment doesn't exist
          }
          
          // Don't notify if user is commenting on their own post
          if (!post.getUserId().equals(sourceUserId)) {
              Notification notification = new Notification();
              notification.setUserId(post.getUserId());
              notification.setType("COMMENT");
              notification.setSourceId(commentId);
              notification.setSourceUserId(sourceUserId);
              notification.setRead(false);
              notification.setContent("有人评论了你的帖子");
              notification.setCreateTime(LocalDateTime.now());
              
              notificationMapper.insert(notification);
          }
      }
      
      @Override
      public void createMessageNotification(Long messageId, Long sourceUserId) {
          if (messageId == null || sourceUserId == null) {
              return; // 如果messageId或sourceUserId为null,直接返回
          }
          
          Message message = messageMapper.findById(messageId);
          if (message == null) {
              return; // Don't notify if message doesn't exist
          }
          
          // 消息接收者和发送者相同时不创建通知
          if (message.getReceiverId().equals(sourceUserId)) {
              return;
          }
          
          try {
              Notification notification = new Notification();
              notification.setUserId(message.getReceiverId());
              notification.setType("MESSAGE");
              notification.setSourceId(messageId);
              notification.setSourceUserId(sourceUserId);
              notification.setRead(false);
              notification.setContent("你收到了一条新私信");
              notification.setCreateTime(LocalDateTime.now());
              
              notificationMapper.insert(notification);
          } catch (Exception e) {
              // 记录错误但不抛出异常
              System.err.println("保存消息通知出错: " + e.getMessage());
          }
      }
      
      @Override
      public Notification getNotificationById(Long id) {
          return notificationMapper.findById(id);
      }
      
      @Override
      public List<Notification> getNotifications(Long userId, int page, int pageSize) {
          int offset = (page - 1) * pageSize;
          return notificationMapper.findByUserId(userId, offset, pageSize);
      }
      
      @Override
      public int getNotificationCount(Long userId) {
          return notificationMapper.countByUserId(userId);
      }
      
      @Override
      public int getUnreadNotificationCount(Long userId) {
          return notificationMapper.countUnreadByUserId(userId);
      }
      
      @Override
      public void markAsRead(Long id) {
          notificationMapper.markAsRead(id);
      }
      
      @Override
      public void markAllAsRead(Long userId) {
          notificationMapper.markAllAsRead(userId);
      }
      
      @Override
      public void deleteNotification(Long id) {
          notificationMapper.delete(id);
      }
      
      @Override
      public void deleteAllReadNotifications(Long userId) {
          notificationMapper.deleteAllRead(userId);
      }
      
    • PostService: 处理帖子发布、删除、更新。

      @Autowired
      private PostMapper postMapper;
      
      @Autowired
      private UserMapper userMapper;
      
      @Autowired
      private LikeService likeService;
      
      @Autowired
      private CommentService commentService;
      
      @Override
      public Post createPost(Post post) {
          postMapper.insert(post);
          return post;
      }
      
      @Override
      public Post getPostById(Long id) {
          Post post = postMapper.findById(id);
          if (post != null) {
              // 查询帖子关联的用户信息
              User user = userMapper.findById(post.getUserId());
              post.setUser(user);
              
              // 查询点赞数和评论数
              post.setLikeCount(likeService.getLikeCount(id));
              post.setCommentCount(commentService.getCommentCount(id));
          }
          return post;
      }
      
      @Override
      public List<Post> getAllPosts() {
          List<Post> posts = postMapper.findAll();
          return enrichPostsWithUserInfo(posts);
      }
      
      @Override
      public List<Post> getAllPostsWithUserInfo(Long currentUserId) {
          List<Post> posts = postMapper.findAll();
          return enrichPostsWithUserInfoAndLikeStatus(posts, currentUserId);
      }
      
      @Override
      public List<Post> getPostsByUserId(Long userId) {
          List<Post> posts = postMapper.findByUserId(userId);
          return enrichPostsWithUserInfo(posts);
      }
      
      @Override
      public List<Post> getPostsByUserIdWithUserInfo(Long userId, Long currentUserId) {
          List<Post> posts = postMapper.findByUserId(userId);
          return enrichPostsWithUserInfoAndLikeStatus(posts, currentUserId);
      }
      
      @Override
      public Post updatePost(Post post) {
          int result = postMapper.update(post);
          if (result > 0) {
              return postMapper.findById(post.getId());
          }
          return null;
      }
      
      @Override
      public boolean deletePost(Long id, Long userId) {
          Post post = postMapper.findById(id);
          if (post != null && post.getUserId().equals(userId)) {
              return deletePostWithCascade(id);
          }
          return false;
      }
      
      @Override
      public boolean deletePostByAdmin(Long id) {
          Post post = postMapper.findById(id);
          System.out.println("=== 管理员删除帖子服务 ===");
          System.out.println("要删除的帖子ID: " + id);
          System.out.println("帖子存在: " + (post != null));
          if (post != null) {
              System.out.println("帖子作者ID: " + post.getUserId());
              System.out.println("帖子内容: " + (post.getContent() != null ? post.getContent().substring(0, Math.min(20, post.getContent().length())) + "..." : "null"));
              boolean result = deletePostWithCascade(id);
              System.out.println("删除结果: " + result);
              return result;
          }
          return false;
      }
      
      /**
       * 级联删除帖子(先删除相关评论和点赞,再删除帖子)
       */
      private boolean deletePostWithCascade(Long postId) {
          try {
              System.out.println("开始级联删除帖子 " + postId);
              
              // 1. 删除帖子的所有评论(批量删除)
              try {
                  boolean commentResult = commentService.deleteAllCommentsForPost(postId);
                  System.out.println("删除帖子评论结果: " + commentResult);
              } catch (Exception e) {
                  System.err.println("删除评论时出错: " + e.getMessage());
                  // 继续执行,不要因为评论删除失败而停止
              }
              
              // 2. 删除帖子的所有点赞(批量删除)
              try {
                  boolean likeResult = likeService.deleteAllLikesForPost(postId);
                  System.out.println("删除帖子点赞结果: " + likeResult);
              } catch (Exception e) {
                  System.err.println("删除点赞时出错: " + e.getMessage());
                  // 继续执行,不要因为点赞删除失败而停止
              }
              
              // 3. 最后删除帖子本身
              boolean result = postMapper.deleteById(postId) > 0;
              System.out.println("帖子删除结果: " + result);
              return result;
              
          } catch (Exception e) {
              System.err.println("级联删除帖子失败: " + e.getMessage());
              e.printStackTrace();
              return false;
          }
      }
      
      /**
       * 为帖子列表添加用户信息
       */
      private List<Post> enrichPostsWithUserInfo(List<Post> posts) {
          if (posts == null || posts.isEmpty()) {
              return posts;
          }
          
          try {
              // 获取所有帖子ID
              List<Long> postIds = posts.stream().map(Post::getId).collect(Collectors.toList());
              
              // 批量获取点赞数和评论数
              Map<Long, Integer> likeCounts = new HashMap<>();
              Map<Long, Integer> commentCounts = new HashMap<>();
              
              try {
                  likeCounts = likeService.batchGetLikeCounts(postIds);
              } catch (Exception e) {
                  System.err.println("获取点赞数失败: " + e.getMessage());
              }
              
              try {
                  commentCounts = commentService.batchGetCommentCounts(postIds);
              } catch (Exception e) {
                  System.err.println("获取评论数失败: " + e.getMessage());
              }
              
              Map<Long, Integer> finalLikeCounts = likeCounts;
              Map<Long, Integer> finalCommentCounts = commentCounts;
              
              return posts.stream().map(post -> {
                  try {
                      // 添加用户信息
                      User user = userMapper.findById(post.getUserId());
                      post.setUser(user);
                      
                      // 添加点赞数和评论数
                      post.setLikeCount(finalLikeCounts.getOrDefault(post.getId(), 0));
                      post.setCommentCount(finalCommentCounts.getOrDefault(post.getId(), 0));
                  } catch (Exception e) {
                      System.err.println("处理帖子数据失败: " + e.getMessage());
                  }
                  
                  return post;
              }).collect(Collectors.toList());
          } catch (Exception e) {
              System.err.println("处理帖子列表失败: " + e.getMessage());
              return posts;
          }
      }
      
      /**
       * 为帖子列表添加用户信息和点赞状态
       */
      private List<Post> enrichPostsWithUserInfoAndLikeStatus(List<Post> posts, Long currentUserId) {
          if (posts == null || posts.isEmpty()) {
              return posts;
          }
          
          try {
              // 获取基本用户信息和统计数据
              List<Post> enrichedPosts = enrichPostsWithUserInfo(posts);
              
              // 如果当前用户已登录,获取点赞状态
              if (currentUserId != null) {
                  try {
                      List<Long> postIds = posts.stream().map(Post::getId).collect(Collectors.toList());
                      Map<Long, Boolean> userLikes = likeService.batchCheckUserLikes(postIds, currentUserId);
                      
                      // 添加用户点赞状态
                      for (Post post : enrichedPosts) {
                          post.setHasLiked(userLikes.getOrDefault(post.getId(), false));
                      }
                  } catch (Exception e) {
                      System.err.println("获取用户点赞状态失败: " + e.getMessage());
                  }
              }
              
              return enrichedPosts;
          } catch (Exception e) {
              System.err.println("处理帖子列表和点赞状态失败: " + e.getMessage());
              return posts;
          }
      }
      
    • UserService: 处理用户注册、登录、查询。

      @Autowired
      private UserMapper userMapper;
      
      @Override
      public Optional<User> login(String username, String password) {
          if (!StringUtils.hasText(username) || !StringUtils.hasText(password)) {
              return Optional.empty();
          }
          
          User user = userMapper.findByUsername(username);
          if (user != null && password.equals(user.getPassword())) {
              return Optional.of(user);
          }
          return Optional.empty();
      }
      
      @Override
      public Optional<User> register(User user) {
          System.out.println("=== UserService.register 开始 ===");
          
          // 参数验证
          if (!StringUtils.hasText(user.getUsername())) {
              System.out.println("注册失败:用户名为空");
              return Optional.empty();
          }
          
          if (!StringUtils.hasText(user.getPassword())) {
              System.out.println("注册失败:密码为空");
              return Optional.empty();
          }
          
          System.out.println("用户名: " + user.getUsername());
          System.out.println("密码长度: " + user.getPassword().length());
          System.out.println("邮箱: " + (user.getEmail() != null ? user.getEmail() : "null"));
          
          try {
              // 检查用户名是否已存在
              System.out.println("检查用户名是否已存在...");
              User existingUser = userMapper.findByUsername(user.getUsername());
              if (existingUser != null) {
                  System.out.println("用户名已存在,注册失败");
                  return Optional.empty();
              }
              
              System.out.println("用户名可用,开始创建用户...");
              
              // 设置默认值
              if (user.getEmail() == null) {
                  user.setEmail("");
              }
              if (user.getBio() == null) {
                  user.setBio("");
              }
              if (user.getAvatar() == null) {
                  user.setAvatar("/avatar-placeholder.png");
              }
              if (user.getRole() == null) {
                  user.setRole("USER");
              }
              
              // 设置时间
              Date now = new Date();
              user.setCreateTime(now);
              user.setUpdateTime(now);
              
              System.out.println("准备插入数据库...");
              System.out.println("最终用户数据:");
              System.out.println("- 用户名: " + user.getUsername());
              System.out.println("- 邮箱: " + user.getEmail());
              System.out.println("- 头像: " + user.getAvatar());
              System.out.println("- 个人简介: " + user.getBio());
              System.out.println("- 角色: " + user.getRole());
              
              // 保存到数据库
              int result = userMapper.insert(user);
              System.out.println("数据库插入结果: " + result);
              
              if (result > 0) {
                  System.out.println("注册成功!用户ID: " + user.getId());
                  // 返回注册成功的用户(不包含密码)
                  user.setPassword(null);
                  return Optional.of(user);
              } else {
                  System.out.println("数据库插入失败");
                  return Optional.empty();
              }
              
          } catch (Exception e) {
              System.err.println("注册过程中发生异常: " + e.getMessage());
              e.printStackTrace();
              return Optional.empty();
          }
      }
      
      @Override
      public Optional<User> getUserById(Long id) {
          if (id == null || id <= 0) {
              return Optional.empty();
          }
          
          return Optional.ofNullable(userMapper.findById(id));
      }
      
      @Override
      public Optional<User> getUserByUsername(String username) {
          if (!StringUtils.hasText(username)) {
              return Optional.empty();
          }
          
          return Optional.ofNullable(userMapper.findByUsername(username));
      }
      
      @Override
      public List<User> getAllUsers() {
          return userMapper.findAll();
      }
      
      @Override
      public boolean deleteUser(Long id) {
          if (id == null || id <= 0) {
              return false;
          }
          
          try {
              // 检查用户是否存在
              User user = userMapper.findById(id);
              if (user == null) {
                  return false;
              }
              
              // 防止删除管理员账户
              if ("ADMIN".equals(user.getRole())) {
                  System.out.println("警告:不能删除管理员账户,用户ID: " + id);
                  return false;
              }
              
              // 暂时禁用用户删除功能,因为需要先解决外键约束问题
              System.out.println("警告:用户删除功能暂时禁用,因为存在外键约束");
              return false;
          } catch (Exception e) {
              System.err.println("删除用户时发生异常: " + e.getMessage());
              e.printStackTrace();
              return false;
          }
      }
      

4.7 主启动类(SocialPlatformApplication.java)

  • Spring Boot主启动类
  • 扫描repository包
  • 初始化时创建uploads目录
@SpringBootApplication
@MapperScan("com.socialplatform.repository")
public class SocialPlatformApplication {

    public static void main(String[] args) {
        SpringApplication.run(SocialPlatformApplication.class, args);
    }

    @PostConstruct
    public void init() {
        // 确保上传目录存在
        File uploadsDir = new File("uploads");
        if (!uploadsDir.exists()) {
            uploadsDir.mkdirs();
        }
    }

}

4.8 工具类(util包)

UserValidationUtil.java: 提供用户验证和会话管理相关的工具方法。

@Autowired
private UserService userService;

/**
 * 验证并刷新Session中的用户信息
 * 确保Session中的用户数据与数据库一致
 */
public User validateAndRefreshSessionUser(HttpSession session) {
    User sessionUser = (User) session.getAttribute("currentUser");
    
    if (sessionUser == null) {
        return null;
    }
    
    // 从数据库重新获取用户信息,确保数据一致性
    Optional<User> dbUserOpt = userService.getUserById(sessionUser.getId());
    
    if (dbUserOpt.isPresent()) {
        User dbUser = dbUserOpt.get();
        
        // 检查用户名是否一致
        if (!sessionUser.getUsername().equals(dbUser.getUsername())) {
            System.err.println("警告:Session用户信息与数据库不一致!");
            System.err.println("Session用户: " + sessionUser.getUsername() + " (ID: " + sessionUser.getId() + ")");
            System.err.println("数据库用户: " + dbUser.getUsername() + " (ID: " + dbUser.getId() + ")");
            
            // 使用数据库中的最新信息更新Session
            session.setAttribute("currentUser", dbUser);
            return dbUser;
        }
        
        return sessionUser;
    } else {
        // 用户在数据库中不存在,清除Session
        System.err.println("Session中的用户在数据库中不存在,清除Session");
        session.invalidate();
        return null;
    }
}

/**
 * 创建安全的用户信息副本(不包含密码)
 */
public User createSafeUserCopy(User user) {
    if (user == null) {
        return null;
    }
    
    User safeUser = new User();
    safeUser.setId(user.getId());
    safeUser.setUsername(user.getUsername());
    safeUser.setEmail(user.getEmail());
    safeUser.setAvatar(user.getAvatar());
    safeUser.setBio(user.getBio());
    safeUser.setCreateTime(user.getCreateTime());
    safeUser.setUpdateTime(user.getUpdateTime());
    // 不复制密码字段
    
    return safeUser;
}

/**
 * 记录用户操作日志
 */
public void logUserAction(String action, User user, String details) {
    System.out.println("=== 用户操作日志 ===");
    System.out.println("操作: " + action);
    System.out.println("用户: " + (user != null ? user.getUsername() : "null") + 
                     " (ID: " + (user != null ? user.getId() : "null") + ")");
    System.out.println("详情: " + details);
    System.out.println("时间: " + new java.util.Date());
    System.out.println("==================");
}

五、前端结构简介

5.1 根目录

作用:管理项目基础配置和依赖关系

功能:

  • package.json:定义项目元信息、管理生产/开发依赖、定义构建脚本
  • vue.config.js:配置API代理、图标支持、ESLint规则
  • babel.config.js:配置JavaScript语法转换规则
  • public/:存放静态资源文件(如占位脚本)

5.2 components/(组件目录)

作用:提供可复用的UI组件,实现页面功能模块化

功能:

  • CreatePost.vue:图文混排编辑、图片上传预览、话题标签识别
  • NotificationList.vue:未读/已读状态区分、通知分类筛选、批量操作
  • PostItem.vue:标准化内容展示、点赞评论交互、响应式媒体支持

5.3 router/(路由目录)

作用:管理应用路由和导航逻辑

功能:

  • 定义12个核心路由(首页、登录、注册等)
  • 实现路由懒加载策略优化性能
  • 配置导航守卫处理认证状态验证
  • 支持动态路由参数(帖子ID、用户ID)

5.4 store/(状态管理目录)

作用:集中管理应用全局状态数据

功能:

  • 用户认证状态管理(登录、登出、自动续签)
  • 数据持久化存储(用户信息、帖子列表、消息通知)
  • 响应式更新机制支持多组件共享状态
  • 异步操作封装(API请求统一处理)

5.5 views/(页面目录)

作用:实现具体业务场景的可视化界面

功能:

  • Home.vue:动态流式布局、发帖组件集成、用户推荐展示
  • Login.vue:表单验证、记住我功能、移动端验证码登录
  • Register.vue:多步骤流程、邀请码输入、协议勾选确认
  • Profile.vue:资料编辑、头像上传、发帖历史展示
  • Messages.vue:联系人列表管理、消息发送接收、新消息通知
  • Trending.vue:热门话题榜单、话题分类浏览、趋势箭头指示
  • Search.vue:多标签搜索、高级筛选、搜索结果高亮
  • Discover.vue:用户推荐系统、热门用户展示、社交邀请功能
  • Notifications.vue:通知分类管理、免打扰时段设置、批量操作
  • PostDetail.vue:内容完整展示、评论发布功能、分享与举报
  • PostEdit.vue:图文编辑、图片删除、草稿自动保存
  • Admin.vue:用户管理、数据统计、权限分配
  • NotFound.vue:友好错误提示、搜索框快捷入口

5.6 入口文件 main.js

作用:初始化Vue应用并挂载全局依赖

功能:

  • 创建Vue应用实例
  • 引入Element Plus和全局样式
  • 配置Axios请求拦截器
  • 挂载Vue Router和Vuex
  • 检查用户认证状态

5.7 根组件 App.vue

作用:提供全局布局和基础功能支持

功能:

  • 使用渲染动态路由
  • 实现响应式导航栏
  • 集成Element Plus图标系统
  • 处理移动端适配逻辑
  • 管理用户认证状态显示

5.8 构建与依赖管理

作用:确保项目可构建和依赖可维护

功能:

  • 构建脚本:serve启动开发服务器、build打包生产环境代码
  • 代理配置:/api → 后端服务
  • 图标支持:处理i-ep-自定义元素
  • 代码规范:ESLint校验Vue 3语法

六、 项目展示

6.1 登录与注册

注册
  • 管理员:在数据库脚本运行后初始化

    默认账号:root

    默认密码:root123

    capture_20250629034709584

  • 普通用户

    capture_20250629035036550

    • 输入两次密码不一致会报错:

      capture_20250629040051291

登录
  • 管理员:

    capture_20250629034949458

  • 普通用户:

    capture_20250629035103754

6.2 评论和点赞

6.2.1 评论和点赞

capture_20250629035346249

6.2.2 帖内回复

capture_20250629035417152

6.2.3 删除评论(只能由评论者和管理员删除)

capture_20250629035427657

capture_20250629040924333

6.2.4 编辑评论内容

capture_20250629035821054

capture_20250629035835358

6.3 聊天室对话

capture_20250629035607622

capture_20250629035644836

6.4 个人资料编辑

capture_20250629035738230

capture_20250629035747542

七、总结

这次课设相对以往的课设,更具备挑战性。时间的有限和仓促的准备,让我感受到前所未有的紧迫感。多亏了网络上高度发达的资源,学习借鉴是解决问题的一个很好的办法。与此同时,也很感谢愿意抽出休息时间帮助我的同学和老师。

通过这次课设,逐步对项目有了初步的了解,也理解了在项目开发过程中会不断面临的窘境。在此之后的学习中,会逐渐养成良好的开发习惯。痛苦于启动时的命名不规范、本地仓库的胡乱构建…同时我也逐渐意识到老师们的良苦用心。

任何事情都不是一蹴而就的,日后将努力提高自身的开发能力。

最后,再次感谢所有老师的付出和同学的陪伴!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程ID

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值