Spring Boot项目学习13之帖子评论模块

1.评论模块

评论模块主要包括评论的列表展示和评论提交。首先是详情页中的评论展示功能,一般评论信息是在某一篇帖子下评论,因此需要关联帖子的主键 id, 同时还存在用户体系,还需要关联评论人的 userId,用户评论时需要填写一些信息和验证,评论提交就是普通字符串信息提交,包括一些基础的字段填写。评论表中重要的字段如下:

  • 关联的帖子主键 postId
  • 评论者的 userId
  • 评论人的邮箱
  • 评论内容

2.评论表设计

DROP TABLE IF EXISTS `tb_post_comment`;

CREATE TABLE `tb_post_comment` (
  `comment_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `post_id` bigint NOT NULL DEFAULT '0' COMMENT '关联的帖子主键',
  `comment_user_id` bigint NOT NULL DEFAULT '0' COMMENT '评论者id',
  `comment_body` varchar(200) NOT NULL DEFAULT '' COMMENT '评论内容',
  `parent_comment_user_id` bigint NOT NULL DEFAULT '0' COMMENT '所回复的上一级评论的userId',
  `comment_create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '评论时间',
  `is_deleted` tinyint DEFAULT '0' COMMENT '是否删除 0-未删除 1-已删除',
  PRIMARY KEY (`comment_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;

3.评论提交接口设计

用户在看完一篇帖子后想要留下一些感想或者建议都是通过这个模块来处理的,该接口主要负责接收前端的 POST 请求并处理其中的参数,接收的参数依次为:

  • postId 字段(当前帖子的主键)
  • verifyCode 字段(验证码,防止恶意提交)
  • parentCommentUserId 字段(所回复的上一层评论的 userId)
  • commentBody 字段(评论内容)

3.1 评论实体类

BBSPostComment

/**
 * 评论-实体类
 */
public class BBSPostComment {
    private Long commentId;

    private Long postId;

    private Long commentUserId;

    private String commentBody;

    private Long parentCommentUserId;

    private Date commentCreateTime;

    private Byte isDeleted;

    public Long getCommentId() {
        return commentId;
    }

    public void setCommentId(Long commentId) {
        this.commentId = commentId;
    }

    public Long getPostId() {
        return postId;
    }

    public void setPostId(Long postId) {
        this.postId = postId;
    }

    public Long getCommentUserId() {
        return commentUserId;
    }

    public void setCommentUserId(Long commentUserId) {
        this.commentUserId = commentUserId;
    }

    public String getCommentBody() {
        return commentBody;
    }

    public void setCommentBody(String commentBody) {
        this.commentBody = commentBody == null ? null : commentBody.trim();
    }

    public Long getParentCommentUserId() {
        return parentCommentUserId;
    }

    public void setParentCommentUserId(Long parentCommentUserId) {
        this.parentCommentUserId = parentCommentUserId;
    }

    public Date getCommentCreateTime() {
        return commentCreateTime;
    }

    public void setCommentCreateTime(Date commentCreateTime) {
        this.commentCreateTime = commentCreateTime;
    }

    public Byte getIsDeleted() {
        return isDeleted;
    }

    public void setIsDeleted(Byte isDeleted) {
        this.isDeleted = isDeleted;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", commentId=").append(commentId);
        sb.append(", postId=").append(postId);
        sb.append(", commentUserId=").append(commentUserId);
        sb.append(", commentBody=").append(commentBody);
        sb.append(", parentCommentUserId=").append(parentCommentUserId);
        sb.append(", commentCreateTime=").append(commentCreateTime);
        sb.append(", isDeleted=").append(isDeleted);
        sb.append("]");
        return sb.toString();
    }
}

3.2 BBSPostCommentController控制层

BBSPostCommentController

@Controller
public class BBSPostCommentController {

    @Resource
    private BBSPostCommentService bbsPostCommentService;

    @PostMapping("/replyPost")
    @ResponseBody
    public Result replyPost(@RequestParam("postId") Long postId,
                            @RequestParam(value = "parentCommentUserId", required = false) Long parentCommentUserId,
                            @RequestParam("commentBody") String commentBody,
                            @RequestParam("verifyCode") String verifyCode,
                            HttpSession httpSession) {
        if (null == postId || postId < 0) {
            return ResultGenerator.genFailResult("postId参数错误");
        }
        if (!StringUtils.hasLength(commentBody)) {
            return ResultGenerator.genFailResult("commentBody参数错误");
        }
        if (commentBody.trim().length() > 200) {
            return ResultGenerator.genFailResult("评论内容过长");
        }
        String kaptchaCode = httpSession.getAttribute(Constants.VERIFY_CODE_KEY) + "";
        if (!StringUtils.hasLength(kaptchaCode) || !verifyCode.equals(kaptchaCode)) {
            return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_VERIFY_CODE_ERROR.getResult());
        }
        BBSUser bbsUser = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);

        BBSPostComment bbsPostComment = new BBSPostComment();
        bbsPostComment.setCommentBody(commentBody);
        bbsPostComment.setCommentUserId(bbsUser.getUserId());
        bbsPostComment.setParentCommentUserId(parentCommentUserId);
        bbsPostComment.setPostId(postId);

        if (bbsPostCommentService.addPostComment(bbsPostComment)) {
            httpSession.removeAttribute(Constants.VERIFY_CODE_KEY);
            return ResultGenerator.genSuccessResult();
        } else {
            return ResultGenerator.genFailResult("请求失败,请检查参数及账号是否有操作权限");
        }
    }
}

3.3 业务层

BBSPostCommentService

public interface BBSPostCommentService {

    /**
     * 增加一条回复
     *
     * @param postComment
     * @return
     */
    Boolean addPostComment(BBSPostComment postComment);
}
@Service
public class BBSPostCommentServiceImpl implements BBSPostCommentService {

    @Autowired
    private BBSPostCommentMapper bbsPostCommentMapper;

    @Autowired
    private BBSPostMapper bbsPostMapper;

    @Autowired
    private BBSUserMapper bbsUserMapper;

    @Override
    @Transactional
    public Boolean addPostComment(BBSPostComment postComment) {
        BBSPost bbsPost = bbsPostMapper.selectByPrimaryKey(postComment.getPostId());
        if (bbsPost == null) {
            return false;
        }
        BBSUser bbsUser = bbsUserMapper.selectByPrimaryKey(postComment.getCommentUserId());

        if (bbsUser == null || bbsUser.getUserStatus().intValue() == 1) {
            //账号已被封禁
            return false;
        }
        bbsPost.setPostComments(bbsPost.getPostComments() + 1);

        return bbsPostCommentMapper.insertSelective(postComment) > 0 && bbsPostMapper.updateByPrimaryKeySelective(bbsPost) > 0;
    }
}

3.4 bbsPostCommentMapper数据持久层

bbsPostCommentMapper

public interface BBSPostCommentMapper {

    int insertSelective(BBSPostComment record);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.picacho.bbs.dao.BBSPostCommentMapper">
    <resultMap id="BaseResultMap" type="top.picacho.bbs.entity.BBSPostComment">
        <id column="comment_id" jdbcType="BIGINT" property="commentId" />
        <result column="post_id" jdbcType="BIGINT" property="postId" />
        <result column="comment_user_id" jdbcType="BIGINT" property="commentUserId" />
        <result column="comment_body" jdbcType="VARCHAR" property="commentBody" />
        <result column="parent_comment_user_id" jdbcType="BIGINT" property="parentCommentUserId" />
        <result column="comment_create_time" jdbcType="TIMESTAMP" property="commentCreateTime" />
        <result column="is_deleted" jdbcType="TINYINT" property="isDeleted" />
    </resultMap>
    <sql id="Base_Column_List">
        comment_id, post_id, comment_user_id, comment_body, parent_comment_user_id, comment_create_time, 
    is_deleted
    </sql>
    
    <insert id="insertSelective" parameterType="top.picacho.bbs.entity.BBSPostComment">
        insert into tb_post_comment
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="commentId != null">
                comment_id,
            </if>
            <if test="postId != null">
                post_id,
            </if>
            <if test="commentUserId != null">
                comment_user_id,
            </if>
            <if test="commentBody != null">
                comment_body,
            </if>
            <if test="parentCommentUserId != null">
                parent_comment_user_id,
            </if>
            <if test="commentCreateTime != null">
                comment_create_time,
            </if>
            <if test="isDeleted != null">
                is_deleted,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="commentId != null">
                #{commentId,jdbcType=BIGINT},
            </if>
            <if test="postId != null">
                #{postId,jdbcType=BIGINT},
            </if>
            <if test="commentUserId != null">
                #{commentUserId,jdbcType=BIGINT},
            </if>
            <if test="commentBody != null">
                #{commentBody,jdbcType=VARCHAR},
            </if>
            <if test="parentCommentUserId != null">
                #{parentCommentUserId,jdbcType=BIGINT},
            </if>
            <if test="commentCreateTime != null">
                #{commentCreateTime,jdbcType=TIMESTAMP},
            </if>
            <if test="isDeleted != null">
                #{isDeleted,jdbcType=TINYINT},
            </if>
        </trim>
    </insert>
</mapper>

4.评论提交功能

首先是在帖子详情页 detail.html 添加评论提交的 DOM 元素。包括输入评论的 textarea 框和验证码输入框,以及“提交回复”的按钮。

<div class="layui-form layui-form-pane" id="replyTextarea">
  <form method="post" id="replyForm" onsubmit="return false;" action="##">
    <input
      type="hidden"
      id="postId"
      name="postId"
      th:value="${bbsPost.postId}"
    />
    <input
      type="hidden"
      id="parentCommentUserId"
      name="parentCommentUserId"
      value="0"
    />
    <div class="layui-form-item layui-form-text">
      <div class="layui-input-block">
        <textarea
          id="commentBody"
          name="commentBody"
          required
          lay-verify="required"
          placeholder="请输入内容"
          class="layui-textarea fly-editor"
          style="height: 150px;"
        ></textarea>
      </div>
    </div>
    <div class="layui-form-item">
      <label for="verifyCode" class="layui-form-label">验证码</label>
      <div class="layui-input-inline">
        <input
          type="text"
          id="verifyCode"
          name="verifyCode"
          required
          lay-verify="required"
          placeholder="请输入验证码"
          autocomplete="off"
          class="layui-input"
        />
      </div>
      <div class="layui-form-mid">
        <span
          ><img
            data-tooltip="看不清楚?换一张"
            th:src="@{/common/captcha}"
            onclick="this.src='/common/captcha?d='+new Date()*1"
            alt="单击图片刷新!"
        /></span>
      </div>
    </div>
    <div class="layui-form-item">
      <input type="hidden" name="jid" value="123" />
      <button class="layui-btn" lay-filter="*" lay-submit onclick="reply()">
        提交回复
      </button>
    </div>
  </form>
</div>

处理“提交回复”按钮 onclick() 触发事件的是 reply() 方法,在 detail.html 页面中添加该事件的 js 代码:

//评论
window.reply = function (postId) {
  var $ = layui.$;
  var verifyCode = $("#verifyCode").val();
  if (!validLength(verifyCode, 5)) {
    layer.alert("请输入正确的验证码!", {
      title: "提醒",
      skin: "layui-layer-molv",
      icon: 2,
    });
    return false;
  }
  var commentBody = $("#commentBody").val();
  if (isNull(commentBody)) {
    layer.alert("请输入评论!", {
      title: "提醒",
      skin: "layui-layer-molv",
      icon: 2,
    });
    return false;
  }
  var params = $("#replyForm").serialize();
  var url = "/replyPost";
  $.ajax({
    type: "POST", //方法类型
    url: url,
    data: params,
    success: function (result) {
      if (result.resultCode == 200) {
        layer.confirm(
          "评论成功!将刷新本页面...",
          {
            icon: 3,
            skin: "layui-layer-molv",
            title: "提示",
          },
          function (index) {
            layer.close(index);
            window.location.reload();
          }
        );
      } else {
        layer.msg(result.message);
      }
    },
    error: function () {
      layer.alert("操作失败!", {
        title: "提醒",
        skin: "layui-layer-molv",
        icon: 2,
      });
    },
  });
};

5.测试效果

在这里插入图片描述
在这里插入图片描述

6.展示评论

评论列表区域渲染的数据应该是一个 List 对象,同时下方又有分页按钮则说明后端需要返回的数据是一个 PageResult 对象。因为评论数据是在帖子详情页中,所以对请求详情详情数据的方法进行修改,添加分页传参,同时返回的数据中增加评论数据。

6.1 BBSPostController

BBSPostController 类中的 postDetail() 方法进行修改:

        // todo 评论数据
        PageResult commentsPage = bbsPostCommentService.getCommentsByPostId(postId, commentPage);
        request.setAttribute("commentsPage", commentsPage);

6.2 BBSPostCommentService

getCommentsByPostId() 方法用于查询当前帖子下的评论分页数据,传参为 postId 和 commentPage。

    /**
     * 详情页评论列表
     *
     * @param postId
     * @param commentPage
     * @return
     */
    PageResult getCommentsByPostId(Long postId, int commentPage);
    public PageResult getCommentsByPostId(Long postId, int commentPage) {
        Map params = new HashMap();
        params.put("postId", postId);
        params.put("page", commentPage);
        params.put("limit", 6);//每页展示6条评论
        PageQueryUtil pageUtil = new PageQueryUtil(params);
        //查询评论数据
        int total = bbsPostCommentMapper.getTotalComments(pageUtil);
        List<BBSPostComment> commentList = bbsPostCommentMapper.findCommentList(pageUtil);
        List<BBSCommentListEntity> bbsCommentListEntities = new ArrayList<>();
        //数据格式转换
        if (!CollectionUtils.isEmpty(commentList)) {
            bbsCommentListEntities = BeanUtil.copyList(commentList, BBSCommentListEntity.class);
            //当前评论者的userId
            List<Long> userIds = bbsCommentListEntities.stream().map(BBSCommentListEntity::getCommentUserId).collect(Collectors.toList());
            //被回复评论的评论者userId
            List<Long> parentUserIds = bbsCommentListEntities.stream().map(BBSCommentListEntity::getParentCommentUserId).collect(Collectors.toList());
            //分别查询user数据
            List<BBSUser> bbsUsers = bbsUserMapper.selectByPrimaryKeys(userIds);
            List<BBSUser> parentUsers = bbsUserMapper.selectByPrimaryKeys(parentUserIds);
            if (!CollectionUtils.isEmpty(bbsUsers)) {
                //封装user数据
                Map<Long, BBSUser> bbsUserMap = bbsUsers.stream().collect(Collectors.toMap(BBSUser::getUserId, Function.identity(), (entity1, entity2) -> entity1));
                for (BBSCommentListEntity bbsCommentListEntity : bbsCommentListEntities) {
                    if (bbsUserMap.containsKey(bbsCommentListEntity.getCommentUserId())) {
                        //设置头像字段和昵称字段
                        BBSUser tempUser = bbsUserMap.get(bbsCommentListEntity.getCommentUserId());
                        bbsCommentListEntity.setHeadImgUrl(tempUser.getHeadImgUrl());
                        bbsCommentListEntity.setNickName(tempUser.getNickName());
                    }
                }
            }
            if (!CollectionUtils.isEmpty(parentUsers)) {
                //添加被回复者的信息
                Map<Long, BBSUser> parentUserMap = parentUsers.stream().collect(Collectors.toMap(BBSUser::getUserId, Function.identity(), (entity1, entity2) -> entity1));
                for (BBSCommentListEntity bbsCommentListEntity : bbsCommentListEntities) {
                    if (parentUserMap.containsKey(bbsCommentListEntity.getParentCommentUserId())) {
                        //在评论内容前加上"@xxx "
                        BBSUser tempUser = parentUserMap.get(bbsCommentListEntity.getParentCommentUserId());
                        bbsCommentListEntity.setCommentBody("@" + tempUser.getNickName() + ":" + bbsCommentListEntity.getCommentBody());
                    }
                }
            }


        }
        PageResult pageResult = new PageResult(bbsCommentListEntities, total, pageUtil.getLimit(), pageUtil.getPage());
        return pageResult;
    }

6.3 bbsPostCommentMapper

    int getTotalComments(PageQueryUtil pageUtil);

    List<BBSPostComment> findCommentList(PageQueryUtil pageUtil);
    <select id="getTotalComments" parameterType="Map" resultType="int">
        select count(*)
        from tb_post_comment where is_deleted = 0
        <if test="postId!=null and postId!=''">
            and post_id = #{postId}
        </if>
    </select>

    <select id="findCommentList" parameterType="Map" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from tb_post_comment where is_deleted = 0
        <if test="postId!=null and postId!=''">
            and post_id = #{postId}
        </if>
        order by comment_id desc
        <if test="start!=null and limit!=null">
            limit #{start},#{limit}
        </if>
    </select>

6.4 BBSCommentListEntity

/**
 * 评论列表-实体类
 * 页面展示时需要的字段与评论实体类不同,因此新增了这个类
 */
public class BBSCommentListEntity {

    private Long commentId;

    private Long postId;

    private Long commentUserId;

    private String commentBody;

    private Long parentCommentUserId;

    private Date commentCreateTime;

    private String nickName;

    private String headImgUrl;

    public Long getPostId() {
        return postId;
    }

    public void setPostId(Long postId) {
        this.postId = postId;
    }

    public Long getCommentId() {
        return commentId;
    }

    public void setCommentId(Long commentId) {
        this.commentId = commentId;
    }

    public Long getCommentUserId() {
        return commentUserId;
    }

    public void setCommentUserId(Long commentUserId) {
        this.commentUserId = commentUserId;
    }

    public String getCommentBody() {
        return commentBody;
    }

    public void setCommentBody(String commentBody) {
        this.commentBody = commentBody;
    }

    public Long getParentCommentUserId() {
        return parentCommentUserId;
    }

    public void setParentCommentUserId(Long parentCommentUserId) {
        this.parentCommentUserId = parentCommentUserId;
    }

    public Date getCommentCreateTime() {
        return commentCreateTime;
    }

    public void setCommentCreateTime(Date commentCreateTime) {
        this.commentCreateTime = commentCreateTime;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getHeadImgUrl() {
        return headImgUrl;
    }

    public void setHeadImgUrl(String headImgUrl) {
        this.headImgUrl = headImgUrl;
    }
}

6.5 渲染数据

最后是帖子详情页中评论列表的渲染,在 detail.html 新增DOM。在评论列表区域和分页功能区域对应的位置读取 commentsPage 对象中的 list 数据和分页数据,list 数据为评论列表数据,使用 th:each 循环语法将评论内容、评论时间、评论者信息等字段渲染出来,之后根据分页字段 currPage(当前页码)、 totalPage(总页码)将下方的分页按钮渲染出来,分页按钮生成的逻辑与首页帖子列表中的逻辑类似,区别在于跳转链接的最后加上了 #comments。

       <ul class="jieda" id="jieda">
                    <th:block th:if="${#lists.isEmpty(commentsPage.list)}">
                        <!-- 无数据时 -->
                        <li class="fly-none">消灭零回复</li>
                    </th:block>
                    <th:block th:unless="${#lists.isEmpty(commentsPage.list)}">
                        <th:block th:each="bbsCommentListEntity : ${commentsPage.list}">
                            <li data-id="111">
                                <a name="item-1111111111"></a>
                                <div class="detail-about detail-about-reply">
                                    <a class="fly-avatar"
                                       th:href="@{${'/userCenter/'+bbsCommentListEntity.commentUserId}}">
                                        <img th:src="@{${bbsCommentListEntity.headImgUrl}}"
                                             th:alt="${bbsCommentListEntity.nickName}">
                                    </a>
                                    <div class="fly-detail-user">
                                        <a th:href="@{${'/userCenter/'+bbsCommentListEntity.commentUserId}}"
                                           class="fly-link">
                                            <cite th:text="${bbsCommentListEntity.nickName}">picacho</cite>
                                        </a>
                                    </div>
                                    <div class="detail-hits">
                                        <span th:text="${#dates.format(bbsCommentListEntity.commentCreateTime, 'yyyy-MM-dd HH:mm:ss')}">2021-08-01</span>
                                    </div>
                                </div>
                                <div class="detail-body jieda-body photos">
                                    <p th:text="${bbsCommentListEntity.commentBody}">回复内容</p>
                                </div>
                                <div class="jieda-reply">
                                    <a href="#replyTextarea"
                                       th:onclick="'preReply('+${bbsCommentListEntity.commentUserId}+')'">
                                    <span type="reply">
                                    <i class="iconfont icon-svgmoban53"></i>
                                    回复
                                    </span>
                                    </a>
                                    <div class="jieda-admin">
                                        <span type="del" th:onclick="'delReply('+${bbsCommentListEntity.commentId}+')'">删除</span>
                                    </div>
                                </div>
                            </li>
                        </th:block>
                    </th:block>
                </ul>

                <th:block th:unless="${#lists.isEmpty(commentsPage.list)}">
                    <!-- 有数据时才会显示分页按钮 -->
                    <div style="text-align: center">
                        <div class="laypage-main">
                            <th:block th:if="${commentsPage.currPage>1}">
                                <a class="laypage-prev"
                                   th:href="@{'/detail/'+${bbsPost.postId}+'?commentPage=' + ${commentsPage.currPage-1}+'#comments'}">
                                    &lt;&lt;</a>
                            </th:block>
                            <th:block th:if="${commentsPage.currPage==1}">
                                <a class="laypage-prev"
                                   href="##">
                                    &lt;&lt;</a>
                            </th:block>
                            <th:block th:if="${commentsPage.currPage-2 >=1}">
                                <a class="laypage-prev"
                                   th:href="@{'/detail/'+${bbsPost.postId}+'?commentPage=' + ${commentsPage.currPage-2}+'#comments'}"
                                   th:text="${commentsPage.currPage - 2}">1</a>
                            </th:block>
                            <th:block th:if="${commentsPage.currPage-1 >=1}">
                                <a class="laypage-prev"
                                   th:href="@{'/detail/'+${bbsPost.postId}+'?commentPage=' + ${commentsPage.currPage-1}+'#comments'}"
                                   th:text="${commentsPage.currPage - 1}">1</a>
                            </th:block>
                            <a href="##" class="laypage-curr" th:text="${commentsPage.currPage}">1</a>
                            <th:block th:if="${commentsPage.currPage+1<=commentsPage.totalPage}">
                                <a class="laypage-next"
                                   th:href="@{'/detail/'+${bbsPost.postId}+'?commentPage=' + ${commentsPage.currPage+1}+'#comments'}"
                                   th:text="${commentsPage.currPage + 1}">1</a>
                            </th:block>
                            <th:block th:if="${commentsPage.currPage+2<=commentsPage.totalPage}">
                                <a class="laypage-next"
                                   th:href="@{'/detail/'+${bbsPost.postId}+'?commentPage=' + ${commentsPage.currPage+2}+'#comments'}"
                                   th:text="${commentsPage.currPage + 2}">1</a>
                            </th:block>
                            <th:block th:if="${commentsPage.currPage<commentsPage.totalPage}">
                                <a class="laypage-next"
                                   th:href="@{'/detail/'+${bbsPost.postId}+'?commentPage=' + ${commentsPage.currPage+1}+'#comments'}">
                                    &gt;&gt;</a>
                            </th:block>
                            <th:block th:if="${commentsPage.currPage==commentsPage.totalPage}">
                                <a class="laypage-next"
                                   href="##">
                                    &gt;&gt;</a>
                            </th:block>
                        </div>
                    </div>
                </th:block>

7.测试效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.删除评论

8.1 前端逻辑

在这里插入图片描述

        //删除评论
        window.delReply = function (commentId) {
            var $ = layui.$;
            $.ajax({
                type: 'POST',//方法类型
                url: '/delReply/' + commentId,
                success: function (result) {
                    if (result.resultCode == 200) {
                        layer.confirm('删除成功!将刷新本页面...', {
                            icon: 3,
                            skin: 'layui-layer-molv',
                            title: '提示'
                        }, function (index) {
                            layer.close(index);
                            window.location.reload();
                        });
                    } else {
                        layer.msg(result.message);
                    }
                    ;
                },
                error: function () {
                    layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                }
            });
        }

8.2 BBSPostCommentController 控制层

BBSPostCommentController

    @PostMapping("/delReply/{commentId}")
    @ResponseBody
    public Result delReply(@PathVariable("commentId") Long commentId,
                           HttpSession httpSession) {

        if (null == commentId || commentId < 0) {
            return ResultGenerator.genFailResult("commentId参数错误");
        }

        BBSUser bbsUser = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);

        if (bbsPostCommentService.delPostComment(commentId,bbsUser.getUserId())) {
            return ResultGenerator.genSuccessResult();
        } else {
            return ResultGenerator.genFailResult("请求失败,请检查参数及账号是否有操作权限");
        }
    }

BBSPostCommentService

    /**
     * 删除一条回复
     *
     * @param commentId
     * @param userId
     * @return
     */
    Boolean delPostComment(Long commentId, Long userId);
    @Override
    @Transactional
    public Boolean delPostComment(Long commentId, Long userId) {

        BBSPostComment bbsPostComment = bbsPostCommentMapper.selectByPrimaryKey(commentId);
        //评论不存在,不能删除
        if (bbsPostComment == null) {
            return false;
        }

        BBSUser bbsUser = bbsUserMapper.selectByPrimaryKey(userId);

        if (bbsUser == null || bbsUser.getUserStatus().intValue() == 1) {
            //账号已被封禁
            return false;
        }

        BBSPost bbsPost = bbsPostMapper.selectByPrimaryKey(bbsPostComment.getPostId());

        //评论所关联的帖子不存在,不能删除
        if (bbsPost == null) {
            return false;
        }

        Long commentCount = bbsPost.getPostComments() - 1;
        if (commentCount >= 0) {
            bbsPost.setPostComments(commentCount);
        }

        if (userId.equals(bbsPostComment.getCommentUserId()) || userId.equals(bbsPost.getPublishUserId())) {
            //这条评论所关联的user或者这条评论所关联帖子的user都可以删除该评论
            //即评论者和发帖者都可以删帖
            return bbsPostCommentMapper.deleteByPrimaryKey(commentId) > 0 && bbsPostMapper.updateByPrimaryKeySelective(bbsPost) > 0;
        }

        return false;
    }

BBSPostCommentMapper

    BBSPostComment selectByPrimaryKey(Long commentId);
    
    int deleteByPrimaryKey(Long commentId);
    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List" />
        from tb_post_comment
        where comment_id = #{commentId,jdbcType=BIGINT} and is_deleted =0
    </select>
    <update id="deleteByPrimaryKey" parameterType="java.lang.Long">
        update tb_post_comment
        set is_deleted = 1
        where comment_id = #{commentId,jdbcType=BIGINT}
    </update>

8.3 测试效果

在这里插入图片描述
在这里插入图片描述
项目源码下载地址:源码下载

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
对于学习 Spring Boot项目学习路线,可以按照以下步骤进行: 1. 第一阶段:了解基础知识和概念。在此阶段,你可以开始学习 Spring Boot 的基础知识和核心概念,包括 Spring Framework、Spring Boot 的特点和优势等。可以参考中提供的学习路线,掌握基础知识和概念是深入学习 Spring Boot 的基础。 2. 第二阶段:学习 Spring Boot Starter。Spring Boot Starter 是 Spring Boot 的一个重要特性,它提供了一种快速集成常用框架和库的方式。在此阶段,你可以学习如何使用已有的 Starter,例如 Spring Data JPA、Thymeleaf 等,来快速集成这些常用框架和库。这将有助于你在实际项目中更快地构建应用程序。可以参考中提供的学习内容,深入理解 Spring Boot Starter 的概念和作用。 3. 第三阶段:深入学习 Spring Boot 特性和功能。在这个阶段,你可以进一步深入学习 Spring Boot 的各种特性和功能,例如自动配置、Actuator、Spring Boot DevTools、Spring Security 等。通过学习和实践,你将能够更好地理解和应用这些功能,进一步提升你的开发能力。可以参考中提供的学习路线,逐步掌握 Spring Boot 的核心概念和功能。 通过以上学习路线,你可以系统地学习和掌握 Spring Boot 的核心概念和功能。随着实践项目的进行和不断学习,你将能够应对更复杂的需求和场景,深入理解和运用 Spring Boot 的各种特性和功能。希望这个学习路线对你的学习有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

picacho_pkq

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

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

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

打赏作者

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

抵扣说明:

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

余额充值