基于MongoDB文章评论实现与设计

基于MongoDB文章评论实现与设计

前提:本文旨在学习mongoDB对系统评论功能的实现思路,并不是完整的实现系统的评论功能。

设计

评论集合的结构

_idmongoDB文档默认编号
cid文章id,有雪花算法生成
content评论内容
publishdate评论发布时间
userId评论人
articleId评论所属文章ID
thumbup评论被点赞数
parentId0表示评论文章;若是评论的是评论则为被评论的评论c_id

思路

​ 用户能对文章进行评论也能对评论进行评论,类似于树形结构。所以存在评论父级ID:parentId,当用户评论的是文章时,parentId=0;当用户评论的是别人的评论是,parentId = 被评论数据的ID

文章的评论是一次性查出来好,还是单个查出来的好?

​ 单个查询好一些。在文章页面中,先只查询属于文章的评论,也就是parentId=0的评论数据。因为,评论的评论并不是所有的人都想看,若想看,想看的点开单独查询即可(使用异步加载),且全部查出来的方式递归效率低,可能导致系统性能差。

​ 从系统性能与用户体验考虑,单个查询较好。

操作mongoDB的技术

使用Spring-Data-MongoDB

实现

导入依赖

<!--spring data mongodb-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

本人将mongodb部署在docker容器中

ip:192.168.200.135

端口为默认端口:27017

配置文件配置

spring:
  data:
    mongodb:
      host: 192.168.200.135  #连接ip
      port: 27017 #端口号
      database: commentDB #数据库

创建文章评论pojo实体类

package cn.jankin.pojo;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import java.io.Serializable;
import java.util.Date;

/**
 * 评论实体
 */
@Document("comment")
public class Comment implements Serializable {
    @Id
    private String _id;  //mongodb默认主键,加快数据的插入
    private String cid;  //雪花生成器生成评论标识,mongoDB建立索引
    private String articleid;
    private String content;
    private String userid;
    private String parentid;
    private Date publishdate;
    private Integer thumbup;
}

注意:在这里我并没有将mongodb默认的 _id 作为评论的标识,而是分配另一个属性 cid作为标识。

原因:优化mongodb的性能,解决可能发生的数据不一致问题。

意义:系统内每一分每一秒都有可能有用户发布评论,若系统采用默认的 _id作为评论标识,我们知道,mongodb默认的 _id的类型为ObjectId,这是一个12byte组成的数据,分别由时间戳、机器标识码、mongoDB实例进程号以及随机序列组成。若是搭建了mongoDB的集群环境,在大量用户发布评论的情况下,生成的ObjectId是有可能相同的,这就导致了评论的唯一性被打破。

那么,我们也可以不使用mongodb默认的ObjectId,系统程序生成一个唯一标识设置为 _id ,例如雪花算法生成的id,不是吗?

是的,但是mongodb中集合是存在 _id 索引的,通过索引mongodb才能够快速的查询出指定的文档,在插入使,若使用自定义值的 _id, 那么将极大的影响mongodb文档的插入效率,特别是在集合中现存文档的数量极其庞大时尤为明显,所以上述做法会影响系统后期时的性能,也不建议使用。

退而求其次,不使用mongoDB默认的唯一标识不就好了,故cid诞生了。cid是由雪花算法生成的id,保证了评论的唯一性,而评论的_id 仍然使用默认类型,保证插入的高效性。而我们只需要另外建一个mongodb中cid索引就也能保证通过cid查询时的性能问题,这就是典型的以空间换时间的概念。

搭建项目的过程就不再赘述了。直接开始敲代码吧。

分析评论所需要的功能

1、通过评论cid查询评论

2、通过文章id查询评论,顶级评论(评论文章的评论),按发布时间排序

3、通过文章id查询某一评论下的评论

3、通过用户id查询评论,按发布时间排序

4、根据id删除评论

5、评论点赞与取消点赞

6、发布评论

注意,评论我设置为没有修改评论功能,如果想改,就只能删除后进行重新发布评论。
对于遗漏的功能,通过上述的功能实现,基本也就能依葫芦画瓢了。

对于数据的参数校验问题,我使用的是hibernate validator,你们可以采用别的方法,这不属于本文内容。

采用restful来实现前后端分离。

我们只进行后端实现。

操作mongoDB的方式我采用了两种:

一种是使用MongoDBTemplate实现类似于需要用到列值增长等函数的操作;

一种是创建持久化接口CommentRepository 继承松日那个 data mongodb 提供的MongoDBRepository接口,进行方法拼接实现简单的条件查询。

这里我只给出操作mongoDB获取数据的方法,对于三层架构和spring boot的操作在代码中不体现。

开始敲代码

直接从service层开始吧,表现层就不体现了。

创建Service接口

package cn.jankin.service;

import cn.jankin.pojo.Comment;

import java.util.List;
import java.util.Map;

/**
 * 评论业务接口
 */
public interface CommentService {

    /**
     * 通过评论id获取评论数据
     * @param id 评论id
     * @return
     */
    Comment findById(String id);

    /**
     * 根据用户id查找用户所发布的评论,并按照发布时间排序
     * @param userId
     * @param sortType
     * @return
     */
    List<Comment> findByUserIdOrderByPublishdate(String userId,String sortType);

    /**
     * 查询所属指定文章的评论,不包含评论的评论,并按评论发布时间排序
     * @param articleId
     * @param sortType
     * @return
     */
    List<Comment> findByArticleIdOrderByPublishdate(String articleId,String sortType);

    /**
     * 通过评论id修改评论数据
     * @param comment
     */
    void updateById(Comment comment);

    /**
     * 通过评论id删除评论
     * @param commentId
     */
    void deleteById(String commentId);

    /**
     * 点赞评论功能实现
     * @param commentId 被点赞评论id
     * @param isThumbup true : 点赞 ; false : 取消点赞
     */
    void thumbup(String commentId,Boolean isThumbup);


    /**
     * 发布评论
     * @param comment
     */
    void save(Comment comment);
}

实现功能一:根据评论id查询评论findById。

service

 	/**
     * 通过评论标识c_id查询评论数据
     * @param id 评论id
     * @return
     */
    @Override
    public Comment findById(String id) {
        Comment comment = commentRepositoty.findByCid(id);
        return comment;
    }

repository:采用方法条件拼接实现

  /**
     * 通过评论c_id查询评论数据
     * @param cid
     * @return
     */
    Comment findByCid(String cid);
实现功能二:通过文章id查询评论,顶级评论(评论文章的评论),按发布时间排序

service

/**
     * 根据文章id查询评论,并按时间排序
     * @param articleId
     * @param sortType
     * @return
     */
    @Override
    public List<Comment> findByArticleIdOrderByPublishdate(String articleId, String sortType) {
        List<Comment> list = null;
        //判断排序规则
        if(sortType.equals(SortType.ASC)){
            list = commentRepositoty.findByArticleidOrderByPublishdateAsc(articleId);
        }else{
            list = commentRepositoty.findByArticleidOrderByPublishdateDesc(articleId);
        }
        return list;
    }

在这里有一个sortType参数,是用来标识是升序排序还是降序排序。

package cn.jankin.entity;

/**
 * 排序类型
 */
public class SortType {
    public final static String ASC = "1";  //升序
    public final static String DESC = "-1";  //降序
}

这样在我们需要改变前端排序参数时,直接该这个类就行,而不需要一个类一个类的改。设计原则:对修改封闭,对扩展开放。

repository

/**
     * 根据文章id查询评论,并根据发布时间正序排序
     * @param articleId
     * @return
     */
    List<Comment> findByArticleidOrderByPublishdateAsc(String articleId);

    /**
     * 根据文章id查询评论,并根据发布时间倒叙排序
     * @param articleId
     * @return
     */
    List<Comment> findByArticleidOrderByPublishdateDesc(String articleId);
实现功能三:通过用户id查询评论,按发布时间排序

因为与文章id查询做法相差不多,不再赘述,但是要考虑登录用户的问题,我这只是demo,没有实现用户登录功能。

实现功能四:根据cid删除评论

service

/**
     * 删除指定评论id的评论文档
     * @param commentId
     */
    @Override
    public void deleteById(String commentId) {
        commentRepositoty.deleteByCid(commentId);
    }

repository

 /**
     * 通过用户标识c_id删除评论
     * @param cid
     */
    void deleteByCid(String cid);
实现功能五:评论点赞与取消点赞
/**
     * 用户点赞与取消点赞评论根据评论id
     * @param commentId 被点赞评论id
     * @param isThumbup true : 点赞 ; false : 取消点赞
     */
    @Override
    public void thumbup(String commentId, Boolean isThumbup) {
        Query query = new Query(Criteria.where("cid").is(commentId)); //设置修改条件
        Update update = new Update();
        if(isThumbup){ //点赞操作
            update.inc("thumbup",1);
        }else{  //取消点赞操作
            update.inc("thumbup",-1);
        }
        mongoTemplate.updateFirst(query,update,"comment");
    }
实现功能六:发布评论

service

/**
     * 发布评论
     * @param comment
     */
    @Override
    public void save(Comment comment) {
        //生成id
        String id = idWorker.nextId()+"";
        comment.setCid(id);
        //设置发布时间
        comment.setPublishdate(new Date());
        //设置初始点赞数
        comment.setThumbup(0);
        //保存
        commentRepositoty.save(comment);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值