zoukankan      html  css  js  c++  java
  • 如何实现一个评论模块

    前言:

      这篇文章主要介绍了博主在学习过程中的一些思路、以及这个评论模块的大致的实现过程,可能并不是常规的做法(全都是自己YY出来的),希望能提供一些思路。

    一、实现一个什么样的评论模块?

      最开始接触到评论的时候,是在自己做一个个人博客的时候遇到的,当时自己想的很简单,别人评论,然后博主回复。类似于这样:

      这种评论很简单,数据库里只需要把回复作为一个字段存进去就可以了,但是后来看到了 畅言 和 多说 ,两个免费的评论系统,只需要调用他们的API就可以把评论模块托管到第三方平台,比较方便。类似这种比较完善的评论模块,是可以评论别人的评论,然后又可以回复其他的评论,类似于这样:

    二、数据库该怎么设计?

      刚开始是想设计成两个表,一个表是所有的评论,一个表存放所有的评论的子评论,然后子评论中多一个字段,存放父评论的ID,这样把两个表关联起来,但是如果再往下增加子节点,就要判断是往哪个数据表中插入,这就比较复杂了。其实仔细想一下这两张表的结构,使用ID关联起来的,完全可以合成一张表,表结构如下:

      最上层的评论的pid是0,子评论的pid就是父评论的id,好像这样的表结构就可以把所有的评论放到一个表中,但是又有一个问题了,像这样表结构存贮的数据取出来的结果是默认按id排序的:

      这样的表结构取出来的数据默认的排序规则是按照id排序的,在前台数据展示的时候,怎么把一个子评论放到其应有的位置呢? 例如:上表中的id值为105的这条数据,父评论是id为102的这条数据,所以,105的位置应该在102这条数据的后面,而这种默认的排序规则是不满足要求的;刚开始想的是怎么把这个数据表怎么填充到一棵树的节点上,因为这个评论系统的结构可以模拟成一棵树,但是怎么遍历这棵树让数据按照正确的规则显示到前台的页面上呢,数据结构和算法学得不是太好,思考未果。。。于是就想,数据都是正确的,只是顺序不对,只需要将它排序就行了。

    三、进行数据模拟

      数据模拟的思路很简单,就是把数据库中的每一条记录都当成是一个对象实体,把整个表的数据放到一个对象数组里面,然后针对这个对象数组进行排序;首先肯定要遍历这个数组,每次循环只需要找到该条评论的子评论就行了,通过pid作为参数进行判断,每一次循环都是做同样的事,其实就是一种递归的思想,递归的深度就取决于子评论的深度;具体代码如下

    package commet.sort.test;
    import commet.sort.entity.Comment;
    public class Test {
        public static void main(String[] args) {
            Comment[] comments = { 
                    new Comment(1001, 0, "a", "a's comment", 1), 
                    new Comment(1002, 0, "b", "b's comment", 1),
                    new Comment(1003, 0, "c", "c's comment", 1), 
                    new Comment(1004, 0, "d", "d's comment", 1),
                    new Comment(1005, 1002, "e", "e's comment", 2), 
                    new Comment(1006, 1002, "f", "f's comment", 2),
                    new Comment(1007, 1005, "g", "g's comment", 3), 
                    new Comment(1008, 0, "h", "h's comment", 1),
                    new Comment(1009, 0, "i", "i's comment", 1), 
                    new Comment(10010, 1003, "j", "j's comment", 1),
                    new Comment(10011, 1010, "k", "k's comment", 1), 
                    new Comment(10012, 1007, "l", "l's comment", 1),
                    new Comment(10013, 1006, "m", "m's comment", 1), 
                    new Comment(10014, 0, "n", "n's comment", 1), };
            sortByArray(comments, 0);
        }
    
        static int num = 0;
        // 通过对象数组进行排序
        public static void sortByArray(Comment[] comments, int pid) {
            for (int i = 0; i < comments.length; i++) {
                if (comments[i].getPid() == pid) {
                    System.out.println(comments[i]);
                    sortByArray(comments, comments[i].getId());
                }
                num++;
            }
        }
    }

    上述代码中,新建对象数组是按照id的顺序来排列的,把排序的结果打印,相当于模拟前台的数据输出。控制台的输出结果如下:

    Comment [id=1001, pid=0, content=a, userName=a's comment, level=1]
    Comment [id=1002, pid=0, content=b, userName=b's comment, level=1]
    Comment [id=1005, pid=1002, content=e, userName=e's comment, level=2]
    Comment [id=1007, pid=1005, content=g, userName=g's comment, level=3]
    Comment [id=10012, pid=1007, content=l, userName=l's comment, level=1]
    Comment [id=1006, pid=1002, content=f, userName=f's comment, level=2]
    Comment [id=10013, pid=1006, content=m, userName=m's comment, level=1]
    Comment [id=1003, pid=0, content=c, userName=c's comment, level=1]
    Comment [id=10010, pid=1003, content=j, userName=j's comment, level=1]
    Comment [id=1004, pid=0, content=d, userName=d's comment, level=1]
    Comment [id=1008, pid=0, content=h, userName=h's comment, level=1]
    Comment [id=1009, pid=0, content=i, userName=i's comment, level=1]
    Comment [id=10014, pid=0, content=n, userName=n's comment, level=1]

      从控制台输出的结果来看,每条数据的pid都等于上一条数据的id,按照这样的排序规则输出到前台页面就满足需求,但是还有一个问题:如何去控制缩进(从上面的示例图片可以看出,如果一条评论是子评论,该条评论相对于父评论是有一些缩进的),刚刚在讲数据库设计的时候,可以看到表结构中有一个属性:level,这个值就是来控制每一条子评论的缩进的,把level值作为div的类名,通过样式来控制每个div的缩进。

    .level1 {
        margin-left: 0px;
    }
    
    .level2 {
        margin-left: 40px;
        border-left: 3px solid #339BD5;
        padding-left: 10px;
    }
    
    .level3 {
        margin-left: 80px;
        border-left: 3px solid #339BD5;
        padding-left: 10px;
    }

      其实这个level值也是控制递归的深度的限制值,由于后台用了递归的排序,所以当数据量较大、递归的深度较深时,执行效率将会大打折扣,而且这个深度也必须受到控制,不可能无限地递归下去;其实一般的评论都会做分页,这样每次都是取较少量的数据进行排序,这样就不用太去担心递归的效率问题。

    四、简单的实现

      刚刚的排序的算法只是一个并不可能在实际中使用,由于用到了springmvc+mybatis,在后台service层进行排序的时候把存储数据的list作为一个成员变量,由于框架机制的原因,每一个service都是单例的,service中的成员变量会存在线程安全问题;因此放弃了在后台排序的念头,改成在页面加载时,后台将数据转成json,交由前台进行排序:

      前台使用了bootstrap中的媒体对象,这种排版看起来类似于一个评论:http://v3.bootcss.com/components/#media

    以下是前台页面:

    <%@ page language="java" contentType="text/html; charset=utf-8"
        pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Home</title>
    <link href="${pageContext.request.contextPath}/sourceFile/offcanvas.css"
        rel="stylesheet">
    <link rel="stylesheet"
        href="${pageContext.request.contextPath}/sourceFile/bootstrap.min.css">
    <script
        src="${pageContext.request.contextPath}/sourceFile/jquery.2.1.1.js"></script>
    <script
        src="${pageContext.request.contextPath}/sourceFile/bootstrap.min.js"></script>
    </head>
    <style>
    .level1 {
        margin-left: 0px;
    }
    .level2 {
        margin-left: 40px;
        border-left: 3px solid #339BD5;
        padding-left: 10px;
    }
    .level3 {
        margin-left: 80px;
        border-left: 3px solid #339BD5;
        padding-left: 10px;
    }
    </style>
    <script>
        $(function() {
            //alert("${comments}");
            var comments = ${comments};
            getComment(comments, 0);
            var reply="<div><a>回复</a></div>"
            $(".level1").append(reply);
            $(".level2").append(reply);
        })
    
      //对json数组进行排序,并且按照排序结果动态添加dom节点
    function getComment(comments, pid) { $.each(comments, function(n, value) { if (value.pid == pid) { $(".media-list").append("<hr/><li class='media'><div class='level"+value.level+"'> <div class='media-body'> <p class='media-heading'>id和pid:"+value.id +"___"+ value.pid+"</p>内容是:"+value.content+"</div></div></li>");
              //递归
              getComment(comments,value.id);
    } }); } </script> <body> <div class="container"> <footer> <p>© create by YaoQi</p> <ul class="media-list"> <li class="media"> <div class="media-left"> <a href="#"> <img class="media-object" src="${pageContext.request.contextPath}/sourceFile/images/2.ico" alt="..."> </a> </div> <div class="media-body"> <h4 class="media-heading"></h4> </div> </li> </ul> </footer> </div> <!--/.container--> </body> </html>

    测试最终的结果:

  • 相关阅读:
    分布式系统学习一-概念篇
    JAVA多线程学习九-原子性操作类的应用
    JAVA多线程学习八-多个线程之间共享数据的方式
    JAVA多线程学习七-线程池
    vue 工作随笔
    智能云课堂整理
    mysql
    模板引挚 jade ejs
    node实战小例子
    昭山欢node资料学习笔记
  • 原文地址:https://www.cnblogs.com/hello-daocaoren/p/7020514.html
Copyright © 2011-2022 走看看