文件生成补充
This commit is contained in:
+91
@@ -0,0 +1,91 @@
|
||||
package fun.nojava.module.comment.controller;
|
||||
|
||||
import fun.nojava.common.model.ApiResult;
|
||||
import fun.nojava.common.model.PageResult;
|
||||
import fun.nojava.module.comment.dto.CommentVO;
|
||||
import fun.nojava.module.comment.dto.CreateCommentDTO;
|
||||
import fun.nojava.module.comment.service.CommentService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "评论接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/comment")
|
||||
@RequiredArgsConstructor
|
||||
public class CommentController {
|
||||
|
||||
private final CommentService commentService;
|
||||
|
||||
@Operation(summary = "发表评论")
|
||||
@PostMapping
|
||||
public ApiResult<Long> createComment(
|
||||
@AuthenticationPrincipal Long userId,
|
||||
@Valid @RequestBody CreateCommentDTO dto) {
|
||||
return ApiResult.success(commentService.createComment(userId, dto));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除评论")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResult<Void> deleteComment(
|
||||
@AuthenticationPrincipal Long userId,
|
||||
@PathVariable Long id) {
|
||||
commentService.deleteComment(userId, id);
|
||||
return ApiResult.success();
|
||||
}
|
||||
|
||||
@Operation(summary = "文章评论列表")
|
||||
@GetMapping("/article/{articleId}")
|
||||
public ApiResult<List<CommentVO>> listArticleComments(
|
||||
@PathVariable Long articleId,
|
||||
@AuthenticationPrincipal Long userId) {
|
||||
return ApiResult.success(commentService.listArticleComments(articleId, userId));
|
||||
}
|
||||
|
||||
@Operation(summary = "点赞评论")
|
||||
@PostMapping("/{id}/like")
|
||||
public ApiResult<Boolean> toggleLike(
|
||||
@PathVariable Long id,
|
||||
@AuthenticationPrincipal Long userId) {
|
||||
return ApiResult.success(commentService.toggleLike(userId, id));
|
||||
}
|
||||
}
|
||||
|
||||
@Tag(name = "管理员-评论管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/comment")
|
||||
@RequiredArgsConstructor
|
||||
class AdminCommentController {
|
||||
|
||||
private final CommentService commentService;
|
||||
|
||||
@Operation(summary = "评论列表")
|
||||
@GetMapping("/list")
|
||||
public ApiResult<PageResult<CommentVO>> listComments(
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "15") int pageSize,
|
||||
@RequestParam(required = false) Integer status) {
|
||||
return ApiResult.success(commentService.listAdminComments(page, pageSize, status));
|
||||
}
|
||||
|
||||
@Operation(summary = "审核评论")
|
||||
@PostMapping("/{id}/audit")
|
||||
public ApiResult<Void> auditComment(
|
||||
@PathVariable Long id,
|
||||
@RequestParam Integer status) {
|
||||
commentService.auditComment(id, status);
|
||||
return ApiResult.success();
|
||||
}
|
||||
|
||||
@Operation(summary = "删除评论")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResult<Void> deleteComment(@PathVariable Long id) {
|
||||
commentService.auditComment(id, 3);
|
||||
return ApiResult.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package fun.nojava.module.comment.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommentVO {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long articleId;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String nickname;
|
||||
|
||||
private String avatar;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private Long replyToId;
|
||||
|
||||
private String replyToNickname;
|
||||
|
||||
private String content;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Integer likeCount;
|
||||
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
private Boolean liked;
|
||||
|
||||
private List<CommentVO> replies;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package fun.nojava.module.comment.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CreateCommentDTO {
|
||||
|
||||
@NotNull(message = "文章ID不能为空")
|
||||
private Long articleId;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private Long replyToId;
|
||||
|
||||
@NotBlank(message = "评论内容不能为空")
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package fun.nojava.module.comment.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("comment")
|
||||
public class Comment {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private Long articleId;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private Long replyToId;
|
||||
|
||||
private String content;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Integer likeCount;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package fun.nojava.module.comment.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("comment_like")
|
||||
public class CommentLike {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private Long commentId;
|
||||
|
||||
private Long userId;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package fun.nojava.module.comment.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.nojava.module.comment.entity.CommentLike;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CommentLikeMapper extends BaseMapper<CommentLike> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package fun.nojava.module.comment.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.nojava.module.comment.entity.Comment;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CommentMapper extends BaseMapper<Comment> {
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package fun.nojava.module.comment.service;
|
||||
|
||||
import fun.nojava.common.model.PageResult;
|
||||
import fun.nojava.module.comment.dto.CommentVO;
|
||||
import fun.nojava.module.comment.dto.CreateCommentDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CommentService {
|
||||
|
||||
Long createComment(Long userId, CreateCommentDTO dto);
|
||||
|
||||
void deleteComment(Long userId, Long commentId);
|
||||
|
||||
List<CommentVO> listArticleComments(Long articleId, Long currentUserId);
|
||||
|
||||
PageResult<CommentVO> listAdminComments(int page, int pageSize, Integer status);
|
||||
|
||||
void auditComment(Long commentId, Integer status);
|
||||
|
||||
boolean toggleLike(Long userId, Long commentId);
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package fun.nojava.module.comment.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import fun.nojava.common.enums.CommentStatus;
|
||||
import fun.nojava.common.exception.BusinessException;
|
||||
import fun.nojava.common.exception.ErrorCode;
|
||||
import fun.nojava.common.model.PageResult;
|
||||
import fun.nojava.module.comment.dto.CommentVO;
|
||||
import fun.nojava.module.comment.dto.CreateCommentDTO;
|
||||
import fun.nojava.module.comment.entity.Comment;
|
||||
import fun.nojava.module.comment.entity.CommentLike;
|
||||
import fun.nojava.module.comment.mapper.CommentLikeMapper;
|
||||
import fun.nojava.module.comment.mapper.CommentMapper;
|
||||
import fun.nojava.module.comment.service.CommentService;
|
||||
import fun.nojava.module.system.entity.User;
|
||||
import fun.nojava.module.system.mapper.UserMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CommentServiceImpl implements CommentService {
|
||||
|
||||
private final CommentMapper commentMapper;
|
||||
private final CommentLikeMapper commentLikeMapper;
|
||||
private final UserMapper userMapper;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createComment(Long userId, CreateCommentDTO dto) {
|
||||
if (dto.getParentId() != null) {
|
||||
Comment parent = commentMapper.selectById(dto.getParentId());
|
||||
if (parent == null) {
|
||||
throw new BusinessException(ErrorCode.COMMENT_NOT_FOUND);
|
||||
}
|
||||
if (parent.getParentId() != null) {
|
||||
throw new BusinessException(ErrorCode.COMMENT_LEVEL_LIMIT);
|
||||
}
|
||||
}
|
||||
|
||||
Comment comment = new Comment();
|
||||
comment.setArticleId(dto.getArticleId());
|
||||
comment.setUserId(userId);
|
||||
comment.setParentId(dto.getParentId());
|
||||
comment.setReplyToId(dto.getReplyToId());
|
||||
comment.setContent(dto.getContent());
|
||||
comment.setStatus(CommentStatus.APPROVED.getCode());
|
||||
comment.setLikeCount(0);
|
||||
comment.setDeleted(0);
|
||||
commentMapper.insert(comment);
|
||||
|
||||
return comment.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteComment(Long userId, Long commentId) {
|
||||
Comment comment = commentMapper.selectById(commentId);
|
||||
if (comment == null) {
|
||||
throw new BusinessException(ErrorCode.COMMENT_NOT_FOUND);
|
||||
}
|
||||
if (!comment.getUserId().equals(userId)) {
|
||||
throw new BusinessException(ErrorCode.PERMISSION_DENIED);
|
||||
}
|
||||
commentMapper.deleteById(commentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommentVO> listArticleComments(Long articleId, Long currentUserId) {
|
||||
List<Comment> rootComments = commentMapper.selectList(
|
||||
new LambdaQueryWrapper<Comment>()
|
||||
.eq(Comment::getArticleId, articleId)
|
||||
.eq(Comment::getParentId, null)
|
||||
.eq(Comment::getStatus, CommentStatus.APPROVED.getCode())
|
||||
.orderByDesc(Comment::getCreatedAt)
|
||||
);
|
||||
|
||||
List<CommentVO> result = new ArrayList<>();
|
||||
for (Comment root : rootComments) {
|
||||
CommentVO vo = buildCommentVO(root, currentUserId);
|
||||
List<Comment> replies = commentMapper.selectList(
|
||||
new LambdaQueryWrapper<Comment>()
|
||||
.eq(Comment::getParentId, root.getId())
|
||||
.eq(Comment::getStatus, CommentStatus.APPROVED.getCode())
|
||||
.orderByAsc(Comment::getCreatedAt)
|
||||
);
|
||||
vo.setReplies(replies.stream().map(r -> buildCommentVO(r, currentUserId)).toList());
|
||||
result.add(vo);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<CommentVO> listAdminComments(int page, int pageSize, Integer status) {
|
||||
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
|
||||
if (status != null) {
|
||||
wrapper.eq(Comment::getStatus, status);
|
||||
}
|
||||
wrapper.orderByDesc(Comment::getCreatedAt);
|
||||
|
||||
Page<Comment> commentPage = commentMapper.selectPage(new Page<>(page, pageSize), wrapper);
|
||||
List<CommentVO> records = commentPage.getRecords().stream()
|
||||
.map(c -> buildCommentVO(c, null))
|
||||
.toList();
|
||||
|
||||
return new PageResult<>(records, commentPage.getTotal(), page, pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void auditComment(Long commentId, Integer status) {
|
||||
Comment comment = commentMapper.selectById(commentId);
|
||||
if (comment == null) {
|
||||
throw new BusinessException(ErrorCode.COMMENT_NOT_FOUND);
|
||||
}
|
||||
comment.setStatus(status);
|
||||
commentMapper.updateById(comment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean toggleLike(Long userId, Long commentId) {
|
||||
CommentLike existing = commentLikeMapper.selectOne(
|
||||
new LambdaQueryWrapper<CommentLike>()
|
||||
.eq(CommentLike::getCommentId, commentId)
|
||||
.eq(CommentLike::getUserId, userId)
|
||||
);
|
||||
|
||||
Comment comment = commentMapper.selectById(commentId);
|
||||
if (comment == null) {
|
||||
throw new BusinessException(ErrorCode.COMMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (existing != null) {
|
||||
commentLikeMapper.deleteById(existing.getId());
|
||||
comment.setLikeCount(comment.getLikeCount() - 1);
|
||||
commentMapper.updateById(comment);
|
||||
return false;
|
||||
} else {
|
||||
CommentLike like = new CommentLike();
|
||||
like.setCommentId(commentId);
|
||||
like.setUserId(userId);
|
||||
commentLikeMapper.insert(like);
|
||||
comment.setLikeCount(comment.getLikeCount() + 1);
|
||||
commentMapper.updateById(comment);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private CommentVO buildCommentVO(Comment comment, Long currentUserId) {
|
||||
User user = userMapper.selectById(comment.getUserId());
|
||||
User replyToUser = comment.getReplyToId() != null ? userMapper.selectById(comment.getReplyToId()) : null;
|
||||
|
||||
boolean liked = false;
|
||||
if (currentUserId != null) {
|
||||
liked = commentLikeMapper.selectCount(
|
||||
new LambdaQueryWrapper<CommentLike>()
|
||||
.eq(CommentLike::getCommentId, comment.getId())
|
||||
.eq(CommentLike::getUserId, currentUserId)
|
||||
) > 0;
|
||||
}
|
||||
|
||||
return CommentVO.builder()
|
||||
.id(comment.getId())
|
||||
.articleId(comment.getArticleId())
|
||||
.userId(comment.getUserId())
|
||||
.nickname(user != null ? user.getNickname() : null)
|
||||
.avatar(user != null ? user.getAvatar() : null)
|
||||
.parentId(comment.getParentId())
|
||||
.replyToId(comment.getReplyToId())
|
||||
.replyToNickname(replyToUser != null ? replyToUser.getNickname() : null)
|
||||
.content(comment.getContent())
|
||||
.status(comment.getStatus())
|
||||
.likeCount(comment.getLikeCount())
|
||||
.createdAt(comment.getCreatedAt())
|
||||
.liked(liked)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user