Jelajahi Sumber

fix: 修复了置顶评论排序失败和无法删除回复的bug

ChenSiTong 6 tahun lalu
induk
melakukan
b58c1445c2

+ 13 - 2
src/main/java/nju/seec/helper/controller/CommentController.java

@@ -57,12 +57,23 @@ public class CommentController {
      */
     @Auth(roles = UserType.TEACHER, message = "置顶评论")
     @PostMapping("/{commentId}/top")
-    public EmptyResponse topComments(LoginUser user,
-                                     @PathVariable Integer commentId) {
+    public EmptyResponse topComment(LoginUser user,
+                                    @PathVariable Integer commentId) {
         commentService.topComment(user, commentId);
         return EmptyResponse.getInstance();
     }
 
+    /**
+     * 教师取消置顶评论
+     */
+    @Auth(roles = UserType.TEACHER, message = "取消置顶评论")
+    @PostMapping("/{commentId}/unTop")
+    public EmptyResponse unTopComment(LoginUser user,
+                                      @PathVariable Integer commentId) {
+        commentService.unTopComment(user, commentId);
+        return EmptyResponse.getInstance();
+    }
+
     /**
      * 取得某一页的评论信息
      */

+ 8 - 5
src/main/java/nju/seec/helper/controller/ReplyController.java

@@ -2,10 +2,12 @@ package nju.seec.helper.controller;
 
 import nju.seec.helper.aspect.auth.Auth;
 import nju.seec.helper.controller.response.EmptyResponse;
+import nju.seec.helper.controller.response.ResourceResponse;
 import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.dto.ReplyDTO;
 import nju.seec.helper.service.ReplyService;
 import nju.seec.helper.util.enums.UserType;
+import nju.seec.helper.vo.ReplyVO;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
@@ -13,7 +15,8 @@ import javax.validation.Valid;
 /**
  * @author cst
  */
-@RestController("/api/reply")
+@RestController
+@RequestMapping("/api/reply")
 public class ReplyController {
     private final ReplyService replyService;
 
@@ -26,10 +29,10 @@ public class ReplyController {
      */
     @Auth(roles = UserType.TEACHER, message = "回复")
     @PostMapping
-    public EmptyResponse createReply(LoginUser user,
-                                     @Valid @RequestBody ReplyDTO replyDTO) {
-        replyService.createReply(user, replyDTO);
-        return EmptyResponse.getInstance();
+    public ResourceResponse<ReplyVO> createReply(LoginUser user,
+                                                 @Valid @RequestBody ReplyDTO replyDTO) {
+        ReplyVO replyVO = replyService.createReply(user, replyDTO);
+        return ResourceResponse.of(replyVO);
     }
 
     /**

+ 23 - 4
src/main/java/nju/seec/helper/dao/CommentDAO.java

@@ -5,8 +5,10 @@ import nju.seec.helper.util.exception.HelperException;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * @author cst
@@ -31,11 +33,11 @@ public interface CommentDAO extends JpaRepository<Comment, Integer> {
      * @param pageNumber
      * @return
      */
-    @Query("select max(c.topNumber) from Comment c " +
+    @Query("select count(distinct c.topNumber) from Comment c " +
             "where c.slideId=?1 " +
-            "and c.pageNumber=?2" +
+            "and c.pageNumber=?2 " +
             "and c.topNumber is not null")
-    Integer countTopComments(Integer slideId, Integer pageNumber);
+    int countTopComments(Integer slideId, Integer pageNumber);
 
     /**
      * 获取评论
@@ -47,7 +49,24 @@ public interface CommentDAO extends JpaRepository<Comment, Integer> {
      */
     @Query("select c from Comment c " +
             "where c.slideId=?1 " +
-            "and c.pageNumber=?2" +
+            "and c.pageNumber=?2 " +
             "order by nullif(c.topNumber, 0) desc")
     Page<Comment> findComments(Integer slideId, Integer pageNumber, Pageable pageable);
+
+    /**
+     * 置顶减一
+     *
+     * @param slideId
+     * @param pageNumber
+     * @param topNumber
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Modifying
+    @Query("update Comment c " +
+            "set c.topNumber=c.topNumber-1 " +
+            "where c.slideId=?1 " +
+            "and c.pageNumber=?2 " +
+            "and c.topNumber is not null " +
+            "and c.topNumber>?3")
+    void decTopNumber(Integer slideId, Integer pageNumber, Integer topNumber);
 }

+ 2 - 0
src/main/java/nju/seec/helper/dto/CommentDTO.java

@@ -15,5 +15,7 @@ public class CommentDTO {
     @NotNull
     private Integer pageNumber;
     @NotBlank
+    private String title;
+    @NotBlank
     private String content;
 }

+ 3 - 1
src/main/java/nju/seec/helper/dto/TopCommentDTO.java

@@ -12,7 +12,9 @@ import java.util.List;
 @Data
 public class TopCommentDTO {
     @NotNull
-    private Integer pageId;
+    private Integer slideId;
+    @NotNull
+    private Integer pageNumber;
     @NotEmpty
     private List<Integer> commentIds;
 }

+ 5 - 5
src/main/java/nju/seec/helper/entity/Comment.java

@@ -7,8 +7,6 @@ import org.hibernate.annotations.CreationTimestamp;
 
 import javax.persistence.*;
 import java.time.LocalDateTime;
-import java.util.Collections;
-import java.util.List;
 
 /**
  * @author cst
@@ -31,6 +29,9 @@ public class Comment {
     @Column(name = "top_number")
     private Integer topNumber;
 
+    @Column(nullable = false)
+    private String title;
+
     @Column(nullable = false)
     private String content;
 
@@ -48,7 +49,6 @@ public class Comment {
     @CreationTimestamp
     private LocalDateTime createAt;
 
-    @OneToMany(mappedBy = "comment", cascade = CascadeType.ALL)
-    @OrderBy("createAt asc")
-    private List<Reply> replies = Collections.emptyList();
+    @OneToOne(mappedBy = "comment", cascade = CascadeType.ALL)
+    private Reply reply;
 }

+ 1 - 1
src/main/java/nju/seec/helper/entity/Reply.java

@@ -19,7 +19,7 @@ public class Reply {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
-    @ManyToOne
+    @OneToOne
     @JoinColumn(name = "comment_id", nullable = false)
     private Comment comment;
 

+ 8 - 1
src/main/java/nju/seec/helper/service/CommentService.java

@@ -2,7 +2,6 @@ package nju.seec.helper.service;
 
 import nju.seec.helper.dto.CommentDTO;
 import nju.seec.helper.dto.LoginUser;
-import nju.seec.helper.dto.ReplyDTO;
 import nju.seec.helper.vo.CommentVO;
 import org.springframework.data.domain.Pageable;
 
@@ -37,6 +36,14 @@ public interface CommentService {
      */
     void topComment(LoginUser user, Integer commentId);
 
+    /**
+     * 取消置顶
+     *
+     * @param user
+     * @param commentId
+     */
+    void unTopComment(LoginUser user, Integer commentId);
+
     /**
      * 基于幻灯片和页码数获取评论
      *

+ 4 - 3
src/main/java/nju/seec/helper/service/ReplyService.java

@@ -2,6 +2,7 @@ package nju.seec.helper.service;
 
 import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.dto.ReplyDTO;
+import nju.seec.helper.vo.ReplyVO;
 
 /**
  * @author cst
@@ -9,11 +10,11 @@ import nju.seec.helper.dto.ReplyDTO;
 public interface ReplyService {
     /**
      * 创建回复
-     *
-     * @param user
+     *  @param user
      * @param replyDTO
+     * @return
      */
-    void createReply(LoginUser user, ReplyDTO replyDTO);
+    ReplyVO createReply(LoginUser user, ReplyDTO replyDTO);
 
     /**
      * 删除回复

+ 28 - 6
src/main/java/nju/seec/helper/service/impl/CommentServiceImpl.java

@@ -37,6 +37,7 @@ public class CommentServiceImpl implements CommentService {
                 .setUserId(user.getId())
                 .setUserName(user.getName())
                 .setUserType(user.getType())
+                .setTitle(commentDTO.getTitle())
                 .setContent(commentDTO.getContent());
         comment = commentDAO.save(comment);
         return new CommentVO(comment);
@@ -49,24 +50,45 @@ public class CommentServiceImpl implements CommentService {
         if (!comment.getUserId().equals(user.getId())) {
             throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权删除该评论");
         }
-        commentDAO.deleteById(commentId);
+        unTopComment(comment);
+        commentDAO.delete(comment);
     }
 
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void topComment(LoginUser user, Integer commentId) {
         Comment comment = commentDAO.findCommentById(commentId);
+
         if (!slideDAO.findSlideById(comment.getSlideId()).getTeacherId().equals(user.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权进行置顶操作");
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权在该评论区置顶评论");
         }
-        Integer topCommentNum = commentDAO.countTopComments(comment.getSlideId(), comment.getPageNumber());
-        if (topCommentNum == null) {
-            topCommentNum = 0;
+
+        unTopComment(comment);
+        comment.setTopNumber(commentDAO.countTopComments(comment.getSlideId(), comment.getPageNumber()) + 1);
+        commentDAO.save(comment);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void unTopComment(LoginUser user, Integer commentId) {
+        Comment comment = commentDAO.findCommentById(commentId);
+
+        if (!slideDAO.findSlideById(comment.getSlideId()).getTeacherId().equals(user.getId())) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权在该评论区取消置顶评论");
         }
-        comment.setTopNumber(topCommentNum + 1);
+
+        unTopComment(comment);
         commentDAO.save(comment);
     }
 
+    private void unTopComment(Comment comment) {
+        Integer topNumber = comment.getTopNumber();
+        if (topNumber != null) {
+            comment.setTopNumber(null);
+            commentDAO.decTopNumber(comment.getSlideId(), comment.getPageNumber(), topNumber);
+        }
+    }
+
     @Transactional(readOnly = true)
     @Override
     public List<CommentVO> getCommentsBySlideIdAndPageNumber(Integer slideId, Integer pageNumber, Pageable pageable) {

+ 13 - 4
src/main/java/nju/seec/helper/service/impl/ReplyServiceImpl.java

@@ -1,5 +1,6 @@
 package nju.seec.helper.service.impl;
 
+import lombok.extern.slf4j.Slf4j;
 import nju.seec.helper.dao.CommentDAO;
 import nju.seec.helper.dao.ReplyDAO;
 import nju.seec.helper.dao.SlideDAO;
@@ -9,12 +10,14 @@ import nju.seec.helper.entity.Comment;
 import nju.seec.helper.entity.Reply;
 import nju.seec.helper.service.ReplyService;
 import nju.seec.helper.util.exception.HelperException;
+import nju.seec.helper.vo.ReplyVO;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
  * @author cst
  */
+@Slf4j
 @Service
 public class ReplyServiceImpl implements ReplyService {
     private final SlideDAO slideDAO;
@@ -29,18 +32,22 @@ public class ReplyServiceImpl implements ReplyService {
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public void createReply(LoginUser user, ReplyDTO replyDTO) {
+    public ReplyVO createReply(LoginUser user, ReplyDTO replyDTO) {
         Comment comment = commentDAO.findCommentById(replyDTO.getCommentId());
         if (!slideDAO.findSlideById(comment.getSlideId()).getTeacherId().equals(user.getId())) {
             throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权回复该评论");
         }
 
+        if (comment.getReply() != null) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您已回复该评论");
+        }
         Reply reply = new Reply()
                 .setComment(comment)
                 .setTeacherId(user.getId())
                 .setContent(replyDTO.getContent());
-        comment.getReplies().add(reply);
-        commentDAO.save(comment);
+        reply.setComment(comment);
+        reply = replyDAO.save(reply);
+        return new ReplyVO(reply);
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -51,6 +58,8 @@ public class ReplyServiceImpl implements ReplyService {
             throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权删除该回复");
         }
 
-        replyDAO.deleteById(replyId);
+        Comment comment = reply.getComment();
+        comment.setReply(null);
+        replyDAO.delete(reply);
     }
 }

+ 7 - 8
src/main/java/nju/seec/helper/vo/CommentVO.java

@@ -6,8 +6,6 @@ import nju.seec.helper.entity.Comment;
 import nju.seec.helper.util.enums.UserType;
 
 import java.time.LocalDateTime;
-import java.util.List;
-import java.util.stream.Collectors;
 
 /**
  * @author cst
@@ -22,30 +20,31 @@ public class CommentVO {
     /**
      * 所属页码
      */
-    private Integer number;
+    private Integer pageNumber;
     /**
      * 置顶优先级(越大说明越高,为null说明不是置顶评论)
      */
     private Integer topNumber;
+    private String title;
     private String content;
     private Integer userId;
     private String userName;
     private UserType userType;
     private LocalDateTime createAt;
 
-    private List<ReplyVO> replies;
+    private ReplyVO reply;
 
     public CommentVO(@NonNull Comment comment) {
         this.id = comment.getId();
+        this.slideId = comment.getSlideId();
+        this.pageNumber = comment.getPageNumber();
         this.topNumber = comment.getTopNumber();
+        this.title = comment.getTitle();
         this.content = comment.getContent();
         this.userId = comment.getUserId();
         this.userName = comment.getUserName();
         this.userType = comment.getUserType();
         this.createAt = comment.getCreateAt();
-        this.replies = comment.getReplies()
-                .stream()
-                .map(ReplyVO::new)
-                .collect(Collectors.toList());
+        this.reply = comment.getReply() == null ? null : new ReplyVO(comment.getReply());
     }
 }

+ 1 - 0
src/main/resources/application-dev.yml

@@ -10,6 +10,7 @@ spring:
       ddl-auto: update
     database: mysql
     database-platform: org.hibernate.dialect.MySQL8Dialect
+    show-sql: true
   http:
     encoding:
       force: true