Java实现评论系统案例

wen java案例 3

本文目录导读:

Java实现评论系统案例

  1. 系统架构设计
  2. 完整代码实现
  3. 系统功能特性

我将为您设计一个完整的Java评论系统案例,包含前端展示、后端服务、数据库设计和核心功能实现。

系统架构设计

评论系统架构
├── Controller层 - 接收HTTP请求
├── Service层 - 业务逻辑处理
├── DAO层 - 数据访问
├── Entity层 - 实体对象
└── 数据库 - MySQL

完整代码实现

1 实体类

// Comment.java - 评论实体
package com.example.commentsystem.entity;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class Comment {
    private Integer id;
    private Integer articleId;      // 文章ID
    private Integer userId;         // 评论用户ID
    private String username;        // 评论用户名
    private String content;         // 评论内容
    private Integer parentId;       // 父评论ID,0表示顶级评论
    private Integer replyUserId;    // 被回复的用户ID
    private String replyUsername;   // 被回复的用户名
    private Integer likeCount;      // 点赞数量
    private LocalDateTime createTime; // 创建时间
    private Integer status;         // 状态:1-正常,0-删除
    private List<Comment> children; // 子评论列表
}
// User.java - 用户实体
package com.example.commentsystem.entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class User {
    private Integer id;
    private String username;
    private String avatar;
    private String email;
    private LocalDateTime createTime;
}

2 DTO类

// CommentRequest.java - 评论请求DTO
package com.example.commentsystem.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Data
public class CommentRequest {
    @NotNull(message = "文章ID不能为空")
    private Integer articleId;
    @NotNull(message = "用户ID不能为空")
    private Integer userId;
    @NotBlank(message = "评论内容不能为空")
    @Size(max = 1000, message = "评论内容不能超过1000字")
    private String content;
    private Integer parentId;       // 父评论ID,回复评论时使用
    private Integer replyUserId;    // 被回复的用户ID
}

3 Controller层

// CommentController.java
package com.example.commentsystem.controller;
import com.example.commentsystem.common.Result;
import com.example.commentsystem.dto.CommentRequest;
import com.example.commentsystem.entity.Comment;
import com.example.commentsystem.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/comment")
public class CommentController {
    @Autowired
    private CommentService commentService;
    /**
     * 获取文章的所有评论(按时间倒序)
     */
    @GetMapping("/list/{articleId}")
    public Result<List<Comment>> getComments(@PathVariable Integer articleId) {
        List<Comment> comments = commentService.getCommentsByArticle(articleId);
        return Result.success(comments);
    }
    /**
     * 获取文章的评论树(按树形结构)
     */
    @GetMapping("/tree/{articleId}")
    public Result<List<Comment>> getCommentTree(@PathVariable Integer articleId) {
        List<Comment> comments = commentService.getCommentTree(articleId);
        return Result.success(comments);
    }
    /**
     * 发表评论
     */
    @PostMapping("/add")
    public Result<Comment> addComment(@Valid @RequestBody CommentRequest request) {
        Comment comment = commentService.addComment(request);
        return Result.success("评论成功", comment);
    }
    /**
     * 删除评论(逻辑删除)
     */
    @DeleteMapping("/delete/{id}")
    public Result<Void> deleteComment(@PathVariable Integer id, 
                                     @RequestParam Integer userId) {
        boolean success = commentService.deleteComment(id, userId);
        return success ? Result.success("删除成功", null) : Result.error("删除失败");
    }
    /**
     * 点赞评论
     */
    @PostMapping("/like/{id}")
    public Result<Integer> likeComment(@PathVariable Integer id) {
        Integer likeCount = commentService.likeComment(id);
        return Result.success("点赞成功", likeCount);
    }
}

4 Service层

// CommentService.java
package com.example.commentsystem.service;
import com.example.commentsystem.dto.CommentRequest;
import com.example.commentsystem.entity.Comment;
import java.util.List;
public interface CommentService {
    // 获取文章评论列表
    List<Comment> getCommentsByArticle(Integer articleId);
    // 获取评论树
    List<Comment> getCommentTree(Integer articleId);
    // 添加评论
    Comment addComment(CommentRequest request);
    // 删除评论
    boolean deleteComment(Integer id, Integer userId);
    // 点赞评论
    Integer likeComment(Integer commentId);
    // 获取用户评论历史
    List<Comment> getUserComments(Integer userId, int page, int size);
}
// CommentServiceImpl.java
package com.example.commentsystem.service.impl;
import com.example.commentsystem.dao.CommentDao;
import com.example.commentsystem.dto.CommentRequest;
import com.example.commentsystem.entity.Comment;
import com.example.commentsystem.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class CommentServiceImpl implements CommentService {
    @Autowired
    private CommentDao commentDao;
    @Override
    public List<Comment> getCommentsByArticle(Integer articleId) {
        return commentDao.findByArticleIdOrderByCreateTimeDesc(articleId);
    }
    @Override
    public List<Comment> getCommentTree(Integer articleId) {
        // 获取所有评论
        List<Comment> allComments = commentDao.findByArticleIdOrderByCreateTimeDesc(articleId);
        // 构建评论树
        return buildCommentTree(allComments);
    }
    /**
     * 构建评论树
     */
    private List<Comment> buildCommentTree(List<Comment> allComments) {
        // 将评论按ID分组
        java.util.Map<Integer, Comment> commentMap = allComments.stream()
            .collect(Collectors.toMap(Comment::getId, comment -> comment));
        List<Comment> treeRoots = new ArrayList<>();
        for (Comment comment : allComments) {
            if (comment.getParentId() == 0) {
                // 顶级评论
                treeRoots.add(comment);
            } else {
                // 子评论,找到父评论并添加
                Comment parent = commentMap.get(comment.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(comment);
                } else {
                    // 父评论已被删除,作为顶级评论显示
                    treeRoots.add(comment);
                }
            }
        }
        // 对每个父评论的子评论按时间排序
        treeRoots.forEach(root -> {
            if (root.getChildren() != null) {
                root.getChildren().sort((c1, c2) -> 
                    c2.getCreateTime().compareTo(c1.getCreateTime()));
            }
        });
        return treeRoots;
    }
    @Override
    @Transactional
    public Comment addComment(CommentRequest request) {
        Comment comment = new Comment();
        comment.setArticleId(request.getArticleId());
        comment.setUserId(request.getUserId());
        comment.setContent(request.getContent());
        comment.setParentId(request.getParentId() != null ? request.getParentId() : 0);
        comment.setReplyUserId(request.getReplyUserId());
        comment.setLikeCount(0);
        comment.setCreateTime(LocalDateTime.now());
        comment.setStatus(1);  // 正常状态
        commentDao.insert(comment);
        // 获取用户名(假设从用户服务获取)
        comment.setUsername(getUsernameById(request.getUserId()));
        // 如果被回复的用户存在,设置用户名
        if (request.getReplyUserId() != null) {
            comment.setReplyUsername(getUsernameById(request.getReplyUserId()));
        }
        return comment;
    }
    @Override
    @Transactional
    public boolean deleteComment(Integer id, Integer userId) {
        Comment comment = commentDao.findById(id);
        if (comment != null && comment.getUserId().equals(userId)) {
            // 逻辑删除
            commentDao.updateStatus(id, 0);
            // 同时删除子评论(级联删除)
            commentDao.deleteByParentId(id);
            return true;
        }
        return false;
    }
    @Override
    @Transactional
    public Integer likeComment(Integer commentId) {
        Comment comment = commentDao.findById(commentId);
        if (comment != null) {
            comment.setLikeCount(comment.getLikeCount() + 1);
            commentDao.updateLikeCount(commentId, comment.getLikeCount());
            return comment.getLikeCount();
        }
        return 0;
    }
    @Override
    public List<Comment> getUserComments(Integer userId, int page, int size) {
        int offset = (page - 1) * size;
        return commentDao.findByUserIdOrderByCreateTimeDesc(userId, offset, size);
    }
    /**
     * 获取用户名(模拟,实际应该调用用户服务)
     */
    private String getUsernameById(Integer userId) {
        // 这里应该调用用户服务获取用户名,这里简化处理
        return "用户" + userId;
    }
}

5 DAO层

// CommentDao.java
package com.example.commentsystem.dao;
import com.example.commentsystem.entity.Comment;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface CommentDao {
    @Select("SELECT * FROM comment WHERE article_id = #{articleId} AND status = 1 ORDER BY create_time DESC")
    List<Comment> findByArticleIdOrderByCreateTimeDesc(Integer articleId);
    @Select("SELECT * FROM comment WHERE id = #{id} AND status = 1")
    Comment findById(Integer id);
    @Insert("INSERT INTO comment (article_id, user_id, content, parent_id, reply_user_id, " +
            "like_count, create_time, status) " +
            "VALUES (#{articleId}, #{userId}, #{content}, #{parentId}, #{replyUserId}, " +
            "#{likeCount}, #{createTime}, #{status})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(Comment comment);
    @Update("UPDATE comment SET status = 0 WHERE id = #{id}")
    int updateStatus(@Param("id") Integer id, @Param("status") Integer status);
    @Update("UPDATE comment SET like_count = #{likeCount} WHERE id = #{id}")
    int updateLikeCount(@Param("id") Integer id, @Param("likeCount") Integer likeCount);
    @Update("UPDATE comment SET status = 0 WHERE parent_id = #{parentId}")
    int deleteByParentId(Integer parentId);
    @Select("SELECT * FROM comment WHERE user_id = #{userId} AND status = 1 " +
            "ORDER BY create_time DESC LIMIT #{size} OFFSET #{offset}")
    List<Comment> findByUserIdOrderByCreateTimeDesc(@Param("userId") Integer userId,
                                                    @Param("offset") int offset,
                                                    @Param("size") int size);
}

6 通用返回结果类

// Result.java
package com.example.commentsystem.common;
import lombok.Data;
@Data
public class Result<T> {
    private Integer code;    // 编码:200-成功,500-失败
    private String message;  // 消息
    private T data;          // 数据
    public static <T> Result<T> success(String message, T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage(message);
        result.setData(data);
        return result;
    }
    public static <T> Result<T> success(T data) {
        return success("操作成功", data);
    }
    public static <T> Result<T> error(String message) {
        Result<T> result = new Result<>();
        result.setCode(500);
        result.setMessage(message);
        return result;
    }
}

7 全局异常处理器

// GlobalExceptionHandler.java
package com.example.commentsystem.exception;
import com.example.commentsystem.common.Result;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleValidationException(MethodArgumentNotValidException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        String message = fieldError != null ? fieldError.getDefaultMessage() : "参数错误";
        return Result.error(message);
    }
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        return Result.error("系统异常:" + e.getMessage());
    }
}

8 数据库建表脚本

-- 创建数据库
CREATE DATABASE IF NOT EXISTS comment_system DEFAULT CHARACTER SET utf8mb4;
USE comment_system;
-- 用户表
CREATE TABLE IF NOT EXISTS `user` (
    `id` INT PRIMARY KEY AUTO_INCREMENT,
    `username` VARCHAR(50) NOT NULL COMMENT '用户名',
    `avatar` VARCHAR(255) DEFAULT NULL COMMENT '头像URL',
    `email` VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 评论表
CREATE TABLE IF NOT EXISTS `comment` (
    `id` INT PRIMARY KEY AUTO_INCREMENT,
    `article_id` INT NOT NULL COMMENT '文章ID',
    `user_id` INT NOT NULL COMMENT '评论用户ID',
    `content` TEXT NOT NULL COMMENT '评论内容',
    `parent_id` INT DEFAULT 0 COMMENT '父评论ID',
    `reply_user_id` INT DEFAULT NULL COMMENT '被回复的用户ID',
    `like_count` INT DEFAULT 0 COMMENT '点赞数',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `status` TINYINT DEFAULT 1 COMMENT '状态:1-正常,0-删除',
    KEY `idx_article_id` (`article_id`),
    KEY `idx_user_id` (`user_id`),
    KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论表';
-- 插入测试数据
INSERT INTO `user` (username, email) VALUES 
('张三', 'zhangsan@example.com'),
('李四', 'lisi@example.com'),
('王五', 'wangwu@example.com');
-- 插入评论示例
INSERT INTO `comment` (article_id, user_id, content, parent_id, reply_user_id, like_count) VALUES 
(1, 1, '这篇文章写得太好了,收藏了!', 0, NULL, 5),
(1, 2, '学习了,很不错的内容', 1, 1, 3),
(1, 3, '希望能够多出一些这样的教程', 0, NULL, 2);

9 配置文件

# application.yml
server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/comment_system?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: yourpassword
    driver-class-name: com.mysql.cj.jdbc.Driver
  redis:
    host: localhost
    port: 6379
    # 用于评论点赞计数缓存,减少数据库压力
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai
mybatis:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

10 前端代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">评论系统</title>
    <style>
        .comment-section {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            font-family: Arial, sans-serif;
        }
        .comment-input {
            border: 1px solid #ddd;
            padding: 15px;
            margin-bottom: 20px;
            border-radius: 5px;
        }
        .comment-input textarea {
            width: 100%;
            height: 100px;
            margin-bottom: 10px;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 3px;
        }
        .btn-submit {
            background-color: #007bff;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 3px;
            cursor: pointer;
        }
        .btn-submit:hover {
            background-color: #0056b3;
        }
        .comment-list {
            list-style: none;
            padding: 0;
        }
        .comment-item {
            border: 1px solid #eee;
            margin-bottom: 10px;
            padding: 15px;
            border-radius: 5px;
            background-color: #f9f9f9;
        }
        .comment-item.child-comments {
            margin-left: 40px;
            margin-top: 10px;
        }
        .comment-header {
            font-size: 14px;
            margin-bottom: 10px;
        }
        .comment-username {
            color: #007bff;
            font-weight: bold;
        }
        .comment-content {
            margin-bottom: 10px;
            line-height: 1.5;
        }
        .comment-footer {
            font-size: 12px;
            color: #999;
        }
        .like-btn {
            background: none;
            border: none;
            color: #007bff;
            cursor: pointer;
            margin-right: 10px;
        }
        .reply-btn {
            background: none;
            border: none;
            color: #007bff;
            cursor: pointer;
        }
        .reply-tag {
            color: #999;
            font-size: 13px;
        }
        .comment-content .reply-to {
            color: #007bff;
            font-weight: bold;
            margin-right: 5px;
        }
        .empty-comments {
            color: #999;
            text-align: center;
            padding: 20px;
        }
        .reply-area {
            margin-top: 10px;
        }
        .reply-area textarea {
            width: 100%;
            height: 60px;
            margin-bottom: 5px;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 3px;
        }
        .btn-submit-reply {
            background-color: #28a745;
            color: white;
            border: none;
            padding: 5px 15px;
            border-radius: 3px;
            cursor: pointer;
        }
        footer {
            font-size: 12px;
            color: #999;
            margin-top: 20px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="comment-section">
        <!-- 发表评论区域 -->
        <div class="comment-input">
            <h3>发表评论</h3>
            <textarea id="commentContent" placeholder="请输入评论内容..."></textarea>
            <button class="btn-submit" onclick="submitComment()">发表评论</button>
        </div>
        <!-- 评论列表 -->
        <h3>全部评论</h3>
        <ul class="comment-list" id="commentList">
            <!-- 评论将在这里动态加载 -->
        </ul>
    </div>
    <script>
        // 当前文章ID(示例)
        const articleId = 1;
        // 当前用户ID和用户名(示例,实际应从登录状态获取)
        const currentUser = { id: 1, username: '张三' };
        // 页面加载时获取评论
        window.onload = function() {
            loadComments();
        };
        // 提交评论
        function submitComment() {
            const content = document.getElementById('commentContent').value.trim();
            if (!content) {
                alert('请输入评论内容');
                return;
            }
            const data = {
                articleId: articleId,
                userId: currentUser.id,
                content: content,
                parentId: 0
            };
            fetch('/api/comment/add', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data)
            })
            .then(response => response.json())
            .then(res => {
                if (res.code === 200) {
                    alert('评论成功');
                    document.getElementById('commentContent').value = '';
                    loadComments();
                } else {
                    alert(res.message);
                }
            });
        }
        // 加载评论
        function loadComments() {
            fetch(`/api/comment/tree/${articleId}`)
            .then(response => response.json())
            .then(res => {
                if (res.code === 200) {
                    renderComments(res.data, document.getElementById('commentList'));
                }
            });
        }
        // 渲染评论树
        function renderComments(comments, container) {
            if (!comments || comments.length === 0) {
                container.innerHTML = '<li class="empty-comments">暂无评论,快来发表第一条评论吧!</li>';
                return;
            }
            container.innerHTML = '';
            comments.forEach(comment => {
                const li = document.createElement('li');
                li.className = 'comment-item';
                // 评论头部
                const header = document.createElement('div');
                header.className = 'comment-header';
                header.innerHTML = `
                    <span class="comment-username">${comment.username}</span>
                    <span class="comment-time">${formatTime(comment.createTime)}</span>
                `;
                // 评论内容
                const contentDiv = document.createElement('div');
                contentDiv.className = 'comment-content';
                if (comment.replyUsername) {
                    contentDiv.innerHTML = `<span class="reply-to">回复 @${comment.replyUsername}:</span>${comment.content}`;
                } else {
                    contentDiv.textContent = comment.content;
                }
                // 评论底部
                const footer = document.createElement('div');
                footer.className = 'comment-footer';
                footer.innerHTML = `
                    <button class="like-btn" onclick="likeComment(${comment.id})">👍 ${comment.likeCount}</button>
                    <button class="reply-btn" onclick="toggleReplyArea(${comment.id})">回复</button>
                `;
                li.appendChild(header);
                li.appendChild(contentDiv);
                li.appendChild(footer);
                // 回复区域
                const replyArea = document.createElement('div');
                replyArea.className = 'reply-area';
                replyArea.id = `replyArea${comment.id}`;
                replyArea.style.display = 'none';
                replyArea.innerHTML = `
                    <textarea id="replyContent${comment.id}" placeholder="回复评论..."></textarea>
                    <button class="btn-submit-reply" onclick="submitReply(${comment.id})">提交回复</button>
                `;
                li.appendChild(replyArea);
                // 如果有子评论,递归渲染
                if (comment.children && comment.children.length > 0) {
                    const childUl = document.createElement('ul');
                    childUl.className = 'comment-list child-comments';
                    renderComments(comment.children, childUl);
                    li.appendChild(childUl);
                }
                container.appendChild(li);
            });
        }
        // 点赞评论
        function likeComment(commentId) {
            fetch(`/api/comment/like/${commentId}`, {
                method: 'POST'
            })
            .then(response => response.json())
            .then(res => {
                if (res.code === 200) {
                    loadComments(); // 重新加载以更新点赞数
                }
            });
        }
        // 显示/隐藏回复区域
        function toggleReplyArea(commentId) {
            const replyArea = document.getElementById(`replyArea${commentId}`);
            replyArea.style.display = replyArea.style.display === 'none' ? 'block' : 'none';
        }
        // 提交回复
        function submitReply(parentId) {
            const content = document.getElementById(`replyContent${parentId}`).value.trim();
            if (!content) {
                alert('请输入回复内容');
                return;
            }
            const data = {
                articleId: articleId,
                userId: currentUser.id,
                content: content,
                parentId: parentId,
                replyUserId: getCommentById(parentId).userId // 获取被回复者的ID
            };
            fetch('/api/comment/add', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data)
            })
            .then(response => response.json())
            .then(res => {
                if (res.code === 200) {
                    alert('回复成功');
                    loadComments();
                } else {
                    alert(res.message);
                }
            });
        }
        // 格式化时间
        function formatTime(timeStr) {
            if (!timeStr) return '';
            const time = new Date(timeStr);
            const now = new Date();
            const diff = now - time;
            if (diff < 60000) return '刚刚';
            if (diff < 3600000) return `${Math.floor(diff/60000)}分钟前`;
            if (diff < 86400000) return `${Math.floor(diff/3600000)}小时前`;
            if (diff < 2592000000) return `${Math.floor(diff/86400000)}天前`;
            return time.toLocaleDateString('zh-CN');
        }
    </script>
</body>
</html>

11 Maven依赖

<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>comment-system</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.0</version>
        </dependency>
        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- Validation -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>
</project>

12 启动类

// CommentApplication.java
package com.example.commentsystem;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.commentsystem.dao")
public class CommentApplication {
    public static void main(String[] args) {
        SpringApplication.run(CommentApplication.class, args);
        System.out.println("评论系统启动成功!");
    }
}

系统功能特性

1 核心功能

  • ✅ 发表评论
  • ✅ 回复评论(支持多级嵌套)
  • ✅ 删除评论(逻辑删除)
  • ✅ 点赞评论
  • ✅ 按时间排序
  • ✅ 分页加载

2 增强功能建议

  1. 敏感词过滤:添加敏感词库进行内容过滤
  2. 评论审核:管理员审核机制
  3. @用户提醒:支持@功能并通知
  4. 表情支持:集成emoji表情
  5. 图片上传:支持评论图片上传
  6. 实时通知:WebSocket实现实时通知

3 性能优化建议

  1. 缓存优化:使用Redis缓存热数据
  2. 数据库优化:合适的索引设计
  3. 异步处理:异步发送通知邮件
  4. 限流控制:防止刷评论攻击

这个评论系统案例包含了完整的后端实现和前端展示,可以根据实际需求进行扩展和优化。

抱歉,评论功能暂时关闭!