本文目录导读:

我来为您提供一个完整的Java评论功能案例,包含前后端实现。
数据库设计
CREATE TABLE `comment` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `content` text NOT NULL COMMENT '评论内容', `user_id` bigint(20) NOT NULL COMMENT '用户ID', `user_name` varchar(50) NOT NULL COMMENT '用户名称', `article_id` bigint(20) NOT NULL COMMENT '文章ID', `parent_id` bigint(20) DEFAULT NULL COMMENT '父评论ID', `reply_user_id` bigint(20) DEFAULT NULL COMMENT '回复用户ID', `reply_user_name` varchar(50) DEFAULT NULL COMMENT '回复用户名称', `likes` int(11) DEFAULT '0' COMMENT '点赞数', `status` tinyint(4) DEFAULT '1' COMMENT '状态:1正常 0删除', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), KEY `idx_article_id` (`article_id`), KEY `idx_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论表';
实体类
// Comment.java
package com.example.entity;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class Comment {
private Long id;
private String content;
private Long userId;
private String userName;
private Long articleId;
private Long parentId;
private Long replyUserId;
private String replyUserName;
private Integer likes;
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
// 用于展示的子评论列表
private List<Comment> children;
}
DAO层
// CommentMapper.java
package com.example.mapper;
import com.example.entity.Comment;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface CommentMapper {
// 添加评论
@Insert("INSERT INTO comment(content, user_id, user_name, article_id, parent_id, " +
"reply_user_id, reply_user_name, likes, status, create_time, update_time) " +
"VALUES(#{content}, #{userId}, #{userName}, #{articleId}, #{parentId}, " +
"#{replyUserId}, #{replyUserName}, 0, 1, NOW(), NOW())")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(Comment comment);
// 根据文章ID查询父评论(顶级评论)
@Select("SELECT * FROM comment WHERE article_id = #{articleId} AND parent_id IS NULL AND status = 1 " +
"ORDER BY create_time DESC")
List<Comment> findParentComments(Long articleId);
// 根据父评论ID查询子评论
@Select("SELECT * FROM comment WHERE parent_id = #{parentId} AND status = 1 " +
"ORDER BY create_time ASC")
List<Comment> findChildComments(Long parentId);
// 删除评论(逻辑删除)
@Update("UPDATE comment SET status = 0 WHERE id = #{id}")
int delete(Long id);
// 点赞
@Update("UPDATE comment SET likes = likes + 1 WHERE id = #{id}")
int likeComment(Long id);
}
Service层
// CommentService.java
package com.example.service;
import com.example.entity.Comment;
import com.example.mapper.CommentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
public class CommentService {
@Autowired
private CommentMapper commentMapper;
// 添加评论
@Transactional
public Comment addComment(Comment comment) {
commentMapper.insert(comment);
return comment;
}
// 获取文章的评论列表(树形结构)
public List<Comment> getCommentsByArticleId(Long articleId) {
// 获取所有父评论
List<Comment> parentComments = commentMapper.findParentComments(articleId);
// 为每个父评论添加子评论
for (Comment parent : parentComments) {
List<Comment> children = commentMapper.findChildComments(parent.getId());
parent.setChildren(children);
}
return parentComments;
}
// 删除评论
@Transactional
public boolean deleteComment(Long id) {
// 逻辑删除评论
commentMapper.delete(id);
// 如果有子评论,也一并删除
List<Comment> children = commentMapper.findChildComments(id);
for (Comment child : children) {
commentMapper.delete(child.getId());
}
return true;
}
// 点赞评论
public boolean likeComment(Long id) {
commentMapper.likeComment(id);
return true;
}
}
Controller层
// CommentController.java
package com.example.controller;
import com.example.common.Result;
import com.example.entity.Comment;
import com.example.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/comment")
public class CommentController {
@Autowired
private CommentService commentService;
// 添加评论
@PostMapping("/add")
public Result addComment(@RequestBody Comment comment) {
// 模拟用户信息(实际应从登录用户获取)
comment.setUserId(1L);
comment.setUserName("测试用户");
Comment result = commentService.addComment(comment);
return Result.success(result);
}
// 获取文章的评论
@GetMapping("/list/{articleId}")
public Result getComments(@PathVariable Long articleId) {
List<Comment> comments = commentService.getCommentsByArticleId(articleId);
return Result.success(comments);
}
// 删除评论
@DeleteMapping("/delete/{id}")
public Result deleteComment(@PathVariable Long id) {
commentService.deleteComment(id);
return Result.success();
}
// 点赞评论
@PostMapping("/like/{id}")
public Result likeComment(@PathVariable Long id) {
commentService.likeComment(id);
return Result.success();
}
}
统一返回结果类
// Result.java
package com.example.common;
import lombok.Data;
@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("success");
result.setData(data);
return result;
}
public static Result success() {
return success(null);
}
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.setCode(500);
result.setMessage(message);
return result;
}
}
前端HTML示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">评论系统</title>
<style>
.comment {
border: 1px solid #ddd;
padding: 15px;
margin-bottom: 10px;
border-radius: 5px;
}
.comment-header {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.comment-user {
font-weight: bold;
color: #333;
}
.comment-time {
color: #999;
font-size: 12px;
}
.comment-content {
margin-bottom: 10px;
}
.comment-actions {
display: flex;
gap: 15px;
}
.comment-actions button {
border: none;
background: none;
cursor: pointer;
color: #666;
}
.comment-actions button:hover {
color: #007bff;
}
.children {
margin-left: 30px;
margin-top: 10px;
}
.reply-form {
margin-top: 10px;
}
.reply-form textarea {
width: 100%;
height: 60px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="container">
<h2>文章评论</h2>
<!-- 评论表单 -->
<div class="comment-form">
<textarea id="commentContent" placeholder="写下你的评论..." style="width:100%;height:80px;"></textarea>
<button onclick="submitComment()">发表评论</button>
</div>
<!-- 评论列表 -->
<div id="commentList" class="comment-list"></div>
</div>
<script>
// 获取评论列表
async function loadComments() {
try {
const response = await fetch('/api/comment/list/1'); // 文章ID为1
const result = await response.json();
if (result.code === 200) {
renderComments(result.data);
}
} catch (error) {
console.error('加载评论失败:', error);
}
}
// 渲染评论
function renderComments(comments) {
const commentList = document.getElementById('commentList');
commentList.innerHTML = comments.map(comment => renderComment(comment)).join('');
}
// 渲染单个评论
function renderComment(comment) {
return `
<div class="comment" id="comment-${comment.id}">
<div class="comment-header">
<span class="comment-user">${comment.userName}</span>
<span class="comment-time">${formatTime(comment.createTime)}</span>
</div>
<div class="comment-content">${comment.content}</div>
<div class="comment-actions">
<button onclick="likeComment(${comment.id})">👍 ${comment.likes || 0}</button>
<button onclick="replyComment(${comment.id}, '${comment.userName}')">回复</button>
<button onclick="deleteComment(${comment.id})">删除</button>
</div>
<!-- 子评论 -->
${comment.children && comment.children.length > 0 ? `
<div class="children">
${comment.children.map(child => renderComment(child)).join('')}
</div>
` : ''}
</div>
`;
}
// 提交评论
async function submitComment(parentId = null, replyUserId = null, replyUserName = null) {
const content = document.getElementById('commentContent').value;
if (!content.trim()) {
alert('请输入评论内容');
return;
}
try {
const response = await fetch('/api/comment/add', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
content: content,
articleId: 1,
parentId: parentId,
replyUserId: replyUserId,
replyUserName: replyUserName
})
});
const result = await response.json();
if (result.code === 200) {
document.getElementById('commentContent').value = '';
loadComments();
}
} catch (error) {
console.error('提交评论失败:', error);
}
}
// 点赞评论
async function likeComment(id) {
try {
const response = await fetch(`/api/comment/like/${id}`, {method: 'POST'});
const result = await response.json();
if (result.code === 200) {
loadComments();
}
} catch (error) {
console.error('点赞失败:', error);
}
}
// 删除评论
async function deleteComment(id) {
if (!confirm('确定删除此评论?')) return;
try {
const response = await fetch(`/api/comment/delete/${id}`, {method: 'DELETE'});
const result = await response.json();
if (result.code === 200) {
loadComments();
}
} catch (error) {
console.error('删除失败:', error);
}
}
// 格式化时间
function formatTime(time) {
const date = new Date(time);
return date.toLocaleString('zh-CN');
}
// 初始化加载评论
loadComments();
</script>
</body>
</html>
配置文件
# application.yml
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/comment_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: your_password
mybatis:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
功能特点
- 支持嵌套评论:实现评论和回复的树形结构
- 评论点赞:支持对评论进行点赞
- 评论删除:逻辑删除,保留数据完整性
- 时间排序:父评论按时间倒序,子评论按时间正序
- 前端交互:完整的HTML+JavaScript实现
这个案例包含了评论功能的核心实现,您可以根据实际需求进行扩展,比如添加用户认证、评论审核、分页加载等功能。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播