[Project] Imitation Niuke.com Community Development Chapter 3 Spring Boot Practice Development Community Core Function 5 Show Comments

[Project] Imitation Niuke community development

insert image description here

Chapter 3 Spring Boot Practice Development Community Core Functions

5 show comments

insert image description here

  • data layer
    • Query a page of review data by entity.
    • Query the number of reviews by entity.
  • Business Layer
    • Handle the business of querying reviews. Handle the business of querying the number of comments.
  • presentation layer
    • When displaying post detail data, all comment data of this post will be displayed at the same time.

The comment form looks like this:

insert image description here

  • id: the unique identification of the primary key of the comment

  • user_id: who posted the comment

  • entity: [Among the functions we want to implement, you can comment on a post or a comment on a post] [One table is used for all comment functions]

    • entity_type : The target or category of the comment, e.g. 1 for post, 2 for comment, 3 for...
    • entity_id : the id of the specific target
  • target_id: a directional comment, such as a comment of a comment of a comment

    insert image description here

  • content: comment content

  • status: status

    0 means normal, 1 means removed or disabled

  • Comment creation time

Create a new entity class:

package com.nowcoder.community.entity;

import java.util.Date;

/**
 * @Projectname: community
 * @Classname: Comment
 * @Author: Ding Jiaxiong
 * @Date:2023/4/19 12:55
 */


public class Comment {
    
    

    private int id;
    private int userId;
    private int entityType;
    private int entityId;
    private int targetId;
    private String content;
    private int status;
    private Date createTime;

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public int getUserId() {
    
    
        return userId;
    }

    public void setUserId(int userId) {
    
    
        this.userId = userId;
    }

    public int getEntityType() {
    
    
        return entityType;
    }

    public void setEntityType(int entityType) {
    
    
        this.entityType = entityType;
    }

    public int getEntityId() {
    
    
        return entityId;
    }

    public void setEntityId(int entityId) {
    
    
        this.entityId = entityId;
    }

    public int getTargetId() {
    
    
        return targetId;
    }

    public void setTargetId(int targetId) {
    
    
        this.targetId = targetId;
    }

    public String getContent() {
    
    
        return content;
    }

    public void setContent(String content) {
    
    
        this.content = content;
    }

    public int getStatus() {
    
    
        return status;
    }

    public void setStatus(int status) {
    
    
        this.status = status;
    }

    public Date getCreateTime() {
    
    
        return createTime;
    }

    public void setCreateTime(Date createTime) {
    
    
        this.createTime = createTime;
    }

    @Override
    public String toString() {
    
    
        return "Comment{" +
                "id=" + id +
                ", userId=" + userId +
                ", entityType=" + entityType +
                ", entityId=" + entityId +
                ", targetId=" + targetId +
                ", content='" + content + '\'' +
                ", status=" + status +
                ", createTime=" + createTime +
                '}';
    }
}

insert image description here

New data layer mapper

package com.nowcoder.community.dao;

import com.nowcoder.community.entity.Comment;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * @Projectname: community
 * @Classname: CommentMapper
 * @Author: Ding Jiaxiong
 * @Date:2023/4/19 12:57
 */


@Mapper
public interface CommentMapper {
    
    

    List<Comment> selectCommentsByEntity(int entityType, int entityId, int offset, int limit);

    int selectCountByEntity(int entityType, int entityId);

}

Write an XML mapping file

<?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="com.nowcoder.community.dao.CommentMapper">

    <sql id="selectFields">
        id
        , user_id, entity_type, entity_id, target_id, content, status, create_time
    </sql>

    <select id="selectCommentsByEntity" resultType="Comment">
        select
        <include refid="selectFields"></include>
        from comment
        where status = 0
        and entity_type = #{entityType}
        and entity_id = #{entityId}
        order by create_time asc
        limit #{offset}, #{limit}
    </select>

    <select id="selectCountByEntity" resultType="int">
        select count(id)
        from comment
        where status = 0
          and entity_type = #{entityType}
          and entity_id = #{entityId}
    </select>

</mapper>

insert image description here

Below is the business layer

package com.nowcoder.community.service;

import com.nowcoder.community.dao.CommentMapper;
import com.nowcoder.community.entity.Comment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Projectname: community
 * @Classname: CommentService
 * @Author: Ding Jiaxiong
 * @Date:2023/4/19 13:01
 */

@Service
public class CommentService {
    
    

    @Autowired
    private CommentMapper commentMapper;

    public List<Comment> findCommentsByEntity(int entityType, int entityId, int offset, int limit) {
    
    
        return commentMapper.selectCommentsByEntity(entityType, entityId, offset, limit);
    }

    public int findCommentCount(int entityType, int entityId) {
    
    
        return commentMapper.selectCountByEntity(entityType, entityId);
    }

}

The following is the presentation layer, because the comments are in the post details, so we directly modify the controller of the post

insert image description here

Pre-injection

insert image description here

Add two constants to this interface

    @RequestMapping(path = "/detail/{discussPostId}", method = RequestMethod.GET)
    public String getDiscussPost(@PathVariable("discussPostId") int discussPostId, Model model, Page page) {
    
    
        // 帖子
        DiscussPost post = discussPostService.findDiscussPostById(discussPostId);
        model.addAttribute("post", post);
        // 作者
        User user = userService.findUserById(post.getUserId());
        model.addAttribute("user", user);

        // 评论分页信息
        page.setLimit(5);
        page.setPath("/discuss/detail/" + discussPostId);
        page.setRows(post.getCommentCount());

        // 评论: 给帖子的评论
        // 回复: 给评论的评论
        // 评论列表
        List<Comment> commentList = commentService.findCommentsByEntity(
                ENTITY_TYPE_POST, post.getId(), page.getOffset(), page.getLimit());
        // 评论VO列表
        List<Map<String, Object>> commentVoList = new ArrayList<>();
        if (commentList != null) {
    
    
            for (Comment comment : commentList) {
    
    
                // 评论VO
                Map<String, Object> commentVo = new HashMap<>();
                // 评论
                commentVo.put("comment", comment);
                // 作者
                commentVo.put("user", userService.findUserById(comment.getUserId()));

                // 回复列表
                List<Comment> replyList = commentService.findCommentsByEntity(
                        ENTITY_TYPE_COMMENT, comment.getId(), 0, Integer.MAX_VALUE);
                // 回复VO列表
                List<Map<String, Object>> replyVoList = new ArrayList<>();
                if (replyList != null) {
    
    
                    for (Comment reply : replyList) {
    
    
                        Map<String, Object> replyVo = new HashMap<>();
                        // 回复
                        replyVo.put("reply", reply);
                        // 作者
                        replyVo.put("user", userService.findUserById(reply.getUserId()));
                        // 回复目标
                        User target = reply.getTargetId() == 0 ? null : userService.findUserById(reply.getTargetId());
                        replyVo.put("target", target);

                        replyVoList.add(replyVo);
                    }
                }
                commentVo.put("replys", replyVoList);

                // 回复数量
                int replyCount = commentService.findCommentCount(ENTITY_TYPE_COMMENT, comment.getId());
                commentVo.put("replyCount", replyCount);

                commentVoList.add(commentVo);
            }
        }

        model.addAttribute("comments", commentVoList);

        return "/site/discuss-detail";
    }

insert image description here

Modify the front-end template

There is a place on the homepage where the number of comments will be displayed, you need to change it

insert image description here

And reuse the paging logic of the home page

insert image description here

Then there is the details page

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
          crossorigin="anonymous">
    <link rel="stylesheet" th:href="@{/css/global.css}"/>
    <link rel="stylesheet" th:href="@{/css/discuss-detail.css}"/>
    <title>牛客网-帖子详情</title>
</head>
<body>
<div class="nk-container">
    <!-- 头部 -->
    <header class="bg-dark sticky-top" th:replace="index::header">
        <div class="container">
            <!-- 导航 -->
            <nav class="navbar navbar-expand-lg navbar-dark">
                <!-- logo -->
                <a class="navbar-brand" href="#"></a>
                <button class="navbar-toggler" type="button" data-toggle="collapse"
                        data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <!-- 功能 -->
                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav mr-auto">
                        <li class="nav-item ml-3 btn-group-vertical">
                            <a class="nav-link" href="../index.html">首页</a>
                        </li>
                        <li class="nav-item ml-3 btn-group-vertical">
                            <a class="nav-link position-relative" href="letter.html">消息<span
                                    class="badge badge-danger">12</span></a>
                        </li>
                        <li class="nav-item ml-3 btn-group-vertical">
                            <a class="nav-link" href="register.html">注册</a>
                        </li>
                        <li class="nav-item ml-3 btn-group-vertical">
                            <a class="nav-link" href="login.html">登录</a>
                        </li>
                        <li class="nav-item ml-3 btn-group-vertical dropdown">
                            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
                               data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                <img src="http://images.nowcoder.com/head/1t.png" class="rounded-circle"
                                     style="width:30px;"/>
                            </a>
                            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                                <a class="dropdown-item text-center" href="profile.html">个人主页</a>
                                <a class="dropdown-item text-center" href="setting.html">账号设置</a>
                                <a class="dropdown-item text-center" href="login.html">退出登录</a>
                                <div class="dropdown-divider"></div>
                                <span class="dropdown-item text-center text-secondary">nowcoder</span>
                            </div>
                        </li>
                    </ul>
                    <!-- 搜索 -->
                    <form class="form-inline my-2 my-lg-0" action="search.html">
                        <input class="form-control mr-sm-2" type="search" aria-label="Search"/>
                        <button class="btn btn-outline-light my-2 my-sm-0" type="submit">搜索</button>
                    </form>
                </div>
            </nav>
        </div>
    </header>

    <!-- 内容 -->
    <div class="main">
        <!-- 帖子详情 -->
        <div class="container">
            <!-- 标题 -->
            <h6 class="mb-4">
                <img src="http://static.nowcoder.com/images/img/icons/ico-discuss.png"/>
                <span th:utext="${post.title}">备战春招,面试刷题跟他复习,一个月全搞定!</span>
                <div class="float-right">
                    <button type="button" class="btn btn-danger btn-sm">置顶</button>
                    <button type="button" class="btn btn-danger btn-sm">加精</button>
                    <button type="button" class="btn btn-danger btn-sm">删除</button>
                </div>
            </h6>
            <!-- 作者 -->
            <div class="media pb-3 border-bottom">
                <a href="profile.html">
                    <img th:src="${user.headerUrl}" class="align-self-start mr-4 rounded-circle user-header"
                         alt="用户头像">
                </a>
                <div class="media-body">
                    <div class="mt-0 text-warning" th:utext="${user.username}">寒江雪</div>
                    <div class="text-muted mt-3">
                        发布于 <b th:text="${#dates.format(post.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15
                        15:32:18</b>
                        <ul class="d-inline float-right">
                            <li class="d-inline ml-2"><a href="#" class="text-primary">赞 11</a></li>
                            <li class="d-inline ml-2">|</li>
                            <li class="d-inline ml-2"><a href="#replyform" class="text-primary">回帖 <i
                                    th:text="${post.commentCount}">7</i></a></li>
                        </ul>
                    </div>
                </div>
            </div>
            <!-- 正文 -->
            <div class="mt-4 mb-3 content" th:utext="${post.content}">
                金三银四的金三已经到了,你还沉浸在过年的喜悦中吗?
                如果是,那我要让你清醒一下了:目前大部分公司已经开启了内推,正式网申也将在3月份陆续开始,金三银四,春招的求职黄金时期已经来啦!!!
                再不准备,作为19应届生的你可能就找不到工作了。。。作为20届实习生的你可能就找不到实习了。。。
                现阶段时间紧,任务重,能做到短时间内快速提升的也就只有算法了,
                那么算法要怎么复习?重点在哪里?常见笔试面试算法题型和解题思路以及最优代码是怎样的?
                跟左程云老师学算法,不仅能解决以上所有问题,还能在短时间内得到最大程度的提升!!!
            </div>
        </div>
        <!-- 回帖 -->
        <div class="container mt-3">
            <!-- 回帖数量 -->
            <div class="row">
                <div class="col-8">
                    <h6><b class="square"></b> <i th:text="${post.commentCount}">30</i>条回帖</h6>
                </div>
                <div class="col-4 text-right">
                    <a href="#replyform" class="btn btn-primary btn-sm">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</a>
                </div>
            </div>
            <!-- 回帖列表 -->
            <ul class="list-unstyled mt-4">
                <li class="media pb-3 pt-3 mb-3 border-bottom" th:each="cvo:${comments}">
                    <a href="profile.html">
                        <img th:src="${cvo.user.headerUrl}" class="align-self-start mr-4 rounded-circle user-header"
                             alt="用户头像">
                    </a>
                    <div class="media-body">
                        <div class="mt-0">
                            <span class="font-size-12 text-success" th:utext="${cvo.user.username}">掉脑袋切切</span>
                            <span class="badge badge-secondary float-right floor">
									<i th:text="${page.offset + cvoStat.count}">1</i>#
								</span>
                        </div>
                        <div class="mt-2" th:utext="${cvo.comment.content}">
                            这开课时间是不是有点晚啊。。。
                        </div>
                        <div class="mt-4 text-muted font-size-12">
                            <span>发布于 <b th:text="${#dates.format(cvo.comment.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18</b></span>
                            <ul class="d-inline float-right">
                                <li class="d-inline ml-2"><a href="#" class="text-primary">赞(1)</a></li>
                                <li class="d-inline ml-2">|</li>
                                <li class="d-inline ml-2"><a href="#" class="text-primary">回复(<i
                                        th:text="${cvo.replyCount}">2</i>)</a></li>
                            </ul>
                        </div>
                        <!-- 回复列表 -->
                        <ul class="list-unstyled mt-4 bg-gray p-3 font-size-12 text-muted">

                            <li class="pb-3 pt-3 mb-3 border-bottom" th:each="rvo:${cvo.replys}">
                                <div>
										<span th:if="${rvo.target==null}">
											<b class="text-info" th:text="${rvo.user.username}">寒江雪</b>:&nbsp;&nbsp;
										</span>
                                    <span th:if="${rvo.target!=null}">
											<i class="text-info" th:text="${rvo.user.username}">Sissi</i> 回复
											<b class="text-info" th:text="${rvo.target.username}">寒江雪</b>:&nbsp;&nbsp;
										</span>
                                    <span th:utext="${rvo.reply.content}">这个是直播时间哈,觉得晚的话可以直接看之前的完整录播的~</span>
                                </div>
                                <div class="mt-3">
                                    <span th:text="${#dates.format(rvo.reply.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18</span>
                                    <ul class="d-inline float-right">
                                        <li class="d-inline ml-2"><a href="#" class="text-primary">赞(1)</a></li>
                                        <li class="d-inline ml-2">|</li>
                                        <li class="d-inline ml-2"><a th:href="|#huifu-${rvoStat.count}|"
                                                                     data-toggle="collapse"
                                                                     class="text-primary">回复</a></li>
                                    </ul>
                                    <div th:id="|huifu-${rvoStat.count}|" class="mt-4 collapse">
                                        <div>
                                            <input type="text" class="input-size" placeholder="回复寒江雪"/>
                                        </div>
                                        <div class="text-right mt-2">
                                            <button type="button" class="btn btn-primary btn-sm" onclick="#">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
                                        </div>
                                    </div>
                                </div>
                            </li>

                            <!-- 回复输入框 -->
                            <li class="pb-3 pt-3">
                                <div>
                                    <input type="text" class="input-size" placeholder="请输入你的观点"/>
                                </div>
                                <div class="text-right mt-2">
                                    <button type="button" class="btn btn-primary btn-sm" onclick="#">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
                                </div>
                            </li>
                        </ul>
                    </div>
                </li>
            </ul>
            <!-- 分页 -->
            <nav class="mt-5" th:replace="index::pagination">
                <ul class="pagination justify-content-center">
                    <li class="page-item"><a class="page-link" href="#">首页</a></li>
                    <li class="page-item disabled"><a class="page-link" href="#">上一页</a></li>
                    <li class="page-item active"><a class="page-link" href="#">1</a></li>
                    <li class="page-item"><a class="page-link" href="#">2</a></li>
                    <li class="page-item"><a class="page-link" href="#">3</a></li>
                    <li class="page-item"><a class="page-link" href="#">4</a></li>
                    <li class="page-item"><a class="page-link" href="#">5</a></li>
                    <li class="page-item"><a class="page-link" href="#">下一页</a></li>
                    <li class="page-item"><a class="page-link" href="#">末页</a></li>
                </ul>
            </nav>
        </div>
        <!-- 回帖输入 -->
        <div class="container mt-3">
            <form class="replyform">
                <p class="mt-3">
                    <a name="replyform"></a>
                    <textarea placeholder="在这里畅所欲言你的看法吧!"></textarea>
                </p>
                <p class="text-right">
                    <button type="submit" class="btn btn-primary btn-sm">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    </button>
                </p>
            </form>
        </div>
    </div>

    <!-- 尾部 -->
    <footer class="bg-dark">
        <div class="container">
            <div class="row">
                <!-- 二维码 -->
                <div class="col-4 qrcode">
                    <img src="https://uploadfiles.nowcoder.com/app/app_download.png" class="img-thumbnail"
                         style="width:136px;"/>
                </div>
                <!-- 公司信息 -->
                <div class="col-8 detail-info">
                    <div class="row">
                        <div class="col">
                            <ul class="nav">
                                <li class="nav-item">
                                    <a class="nav-link text-light" href="#">关于我们</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link text-light" href="#">加入我们</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link text-light" href="#">意见反馈</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link text-light" href="#">企业服务</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link text-light" href="#">联系我们</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link text-light" href="#">免责声明</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link text-light" href="#">友情链接</a>
                                </li>
                            </ul>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col">
                            <ul class="nav btn-group-vertical company-info">
                                <li class="nav-item text-white-50">
                                    公司地址:北京市朝阳区大屯路东金泉时代3-2708北京牛客科技有限公司
                                </li>
                                <li class="nav-item text-white-50">
                                    联系方式:010-60728802(电话)&nbsp;&nbsp;&nbsp;&nbsp;[email protected]
                                </li>
                                <li class="nav-item text-white-50">
                                    牛客科技©2018 All rights reserved
                                </li>
                                <li class="nav-item text-white-50">
                                    京ICP备14055008号-4 &nbsp;&nbsp;&nbsp;&nbsp;
                                    <img src="http://static.nowcoder.com/company/images/res/ghs.png"
                                         style="width:18px;"/>
                                    京公网安备 11010502036488号
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </footer>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
        crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" crossorigin="anonymous"></script>
<script th:src="@{/js/global.js}"></script>
</body>
</html>

Start the server, visit and see

insert image description here

The current number is not written to death.

insert image description here

insert image description here

Comments on posts and comments on comments are also displayed normally.

Guess you like

Origin blog.csdn.net/weixin_44226181/article/details/130470197