88-day11-app端评论系统开发(选项,表设计)

目录

 


回到顶部

第十一章 app 端评论系统开发

目标

  • 能够完成对 mongodb 的环境搭建
  • 能够掌握 mongodb 的基本使用
  • 能够完成 app 端评论的查询、发表、点赞等功能
  • 能够完成 app 端评论回复的查询,发表、点赞功能

1 Mongodb

1.1Mongodb 简介

MongoDB 是一个开源、高性能、无模式的文档型数据库

应用场景:

  • 支持文本查询

  • 不需要支持事务,不存在复杂的多表查询

  • 存储数据可持久化

  • 需要 TB 甚至 PB 级别数据存储

  • 需求变化较快,数据模型无法确认,预计使用快速迭代开发形式

  • 需要至少 2000 以上的读写 QPS【高性能】

  • 能支持快速水平扩展【高扩展】

  • 99.999% 高可用【高可用】

1.2 Mongodb 安装

1.2.1 拉取镜像

docker pull mongo

1.2.2 创建容器

docker run -di --name mongo-service -p 27017:27017 -v ~/data/mongodata:/data  mongo

1587308221361

1.2.3 可视化工具

studio3t 是 mongodb 优秀的客户端工具。官方地址在 https://studio3t.com/

下载 studio3t

1587308417511

同学不用下载,可以使用资料文件夹中提供好的软件安装即可。

1617292175943

安装并启动

1587308580032

创建连接

1587308626866

1587308663776

1587308692439

注意:以上的链接的 ip 地址以及端口以自己实际的服务器的 ip 地址和端口为准

连接成功:

1587308807056

2 app 端评论 - 发表评论

2.1 需求分析

1587310483409

  • 文章详情页下方可以查看评论信息,按照点赞数量倒序排列,展示评论内容、评论的作者、点数数、回复数、时间,默认查看 10 条评论,如果想查看更多,可以点击加载更多进行分页
  • 可以针对当前文章发布评论
  • 可以针对于某一条评论进行点赞操作

2.2 思路分析

(1)需要将数据存储到 mongodb 中,所以先创建两个 pojo ,他们之间关系如下

1601173225423

思路分析

​ 根据文章 id 发表评论,输入内容发表评论,评论内容不能超过 140 字,评论内容需要做文本垃圾检测(暂时不做),将数据存储到 mongodb 中。

需要搭建一个评论微服务,实现相关的功能。

2.3 搭建评论微服务

(1)创建项目 itheima-leadnews-service-comment

1615546024145

(2)微服务中 pom 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>itheima-leadnews</artifactId>
        <groupId>com.itheima</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
<span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>itheima-leadnews-service-comment<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.itheima<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>itheima-leadnews-comment-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">exclusions</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">exclusion</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.baomidou<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mybatis-plus-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">exclusion</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">exclusions</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.itheima<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>itheima-leadnews-common<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>

</project>

(3)application.yml

spring:
  profiles:
    active: dev
---
server:
  port: 9007
spring:
  application:
    name: leadnews-comment
  profiles: dev
  cloud:
    nacos:
      server-addr: 192.168.211.136:8848
      discovery:
        server-addr: ${spring.cloud.nacos.server-addr}
  data:
    mongodb:
      host: 192.168.211.136
      port: 27017
      database: leadnews-comment
---
server:
  port: 9007
spring:
  application:
    name: leadnews-user
  profiles: pro
  cloud:
    nacos:
      server-addr: 192.168.211.136:8848
      discovery:
        server-addr: ${spring.cloud.nacos.server-addr}
  data:
    mongodb:
      host: 192.168.211.136
      port: 27017
      database: leadnews-comment
---
server:
  port: 9007
spring:
  application:
    name: leadnews-user
  profiles: test
  cloud:
    nacos:
      server-addr: 192.168.211.136:8848
      discovery:
        server-addr: ${spring.cloud.nacos.server-addr}
  data:
    mongodb:
      host: 192.168.211.136
      port: 27017
      database: leadnews-comment

数据库其实可以暂时不用。我们先放到这。链接上去。

1615546110343

(4)启动类

package com.itheima;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class CommentApplication {
public static void main(String[] args) {
SpringApplication.run(CommentApplication.class, args);
}
}

(5)配置 mongodb(已经配置好了)

1615546181181

(6) 创建 POJO 映射到 mongdb 中:

1639012338690

package com.itheima.comment.document;

import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;

import java.time.LocalDateTime;

@Data
@Document("ap_comment")// 定义集合(表)的名称
public class Comment {

<span class="hljs-comment">/**
 * id 主键
 */</span>
<span class="hljs-keyword">private</span> String id;

<span class="hljs-comment">/**
 * 评论人的ID
 */</span>
<span class="hljs-keyword">private</span> Integer userId;

<span class="hljs-comment">/**
 * 评论人的昵称
 */</span>
<span class="hljs-keyword">private</span> String nickName;

<span class="hljs-comment">/**
 * 评论人的头像
 */</span>
<span class="hljs-keyword">private</span> String headImage;

<span class="hljs-comment">/**
 * 文章id
 */</span>
<span class="hljs-keyword">private</span> Long articleId;

<span class="hljs-comment">/**
 * 文章所属的频道ID
 */</span>
<span class="hljs-comment">//private Integer channelId;</span>

<span class="hljs-comment">/**
 * 评论人写的内容
 */</span>
<span class="hljs-keyword">private</span> String content;


<span class="hljs-comment">/**
 * 总的点赞数
 */</span>
<span class="hljs-keyword">private</span> Integer likes;

<span class="hljs-comment">/**
 * 总的回复数
 */</span>
<span class="hljs-keyword">private</span> Integer replys;

<span class="hljs-comment">/*  */</span><span class="hljs-comment">/**
 * 经度
 */</span><span class="hljs-comment">/*
private BigDecimal longitude;

*/</span><span class="hljs-comment">/**
 * 维度
 */</span><span class="hljs-comment">/*
private BigDecimal latitude;

*/

<span class="hljs-comment">/**
 * 评论时间
 */</span>
<span class="hljs-keyword">private</span> LocalDateTime createdTime;

<span class="hljs-comment">/**
 * 更新时间
 */</span>
<span class="hljs-keyword">private</span> LocalDateTime updatedTime;

}

@Data
@Document("comment_like")
public class CommentLike {

    /**
     * id
     */
    private String id;

    /**
     * 点赞人的 ID
     */
    private Integer userId;

    /**
     * 被点赞的评论 id
     */
    private String commentId;


    // 取消点赞就是 删除评论点赞记录

}

基本的 CURD 操作 mongodb 回顾:

新版本的 springboot 不需要写 RunWith

package com.itheima;

import com.itheima.comment.document.Comment;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.List;

/**

  • @author ljh

  • @version 1.0

  • @date 2021/12/9 09:06

  • @description 标题

  • @package com.itheima
    */
    @SpringBootTest
    public class MongoTest {

    @Autowired
    private MongoTemplate mongoTemplate;

    // 相同的 CRUD 的操作
    @Test
    public void insert(){
    Comment comment = new Comment();
    comment.setUserId(2);
    comment.setLikes(20);
    mongoTemplate.insert(comment);

    }

    @Test
    public void testFindOne() {
    Comment apComment = mongoTemplate.findById("5f7012e03ea2da5788227a6f", Comment.class);
    System.out.println(apComment);
    }

    @Test
    public void testQuery() {
    //Query query = Query.query(Criteria.where("_id").is("5f7012e03ea2da5788227a6f"));
    Query query = Query.query(Criteria.where("likes").gt(8)); // select *from xxx where likes >20
    // query.with(Sort.by(Sort.Direction.DESC, "likes"));
    List<Comment> apComments = mongoTemplate.find(query, Comment.class);
    System.out.println(apComments);
    }

    @Test
    public void testDelete() {
    //delete from xxx where id=?
    mongoTemplate.remove(Query.query(Criteria.where("_id").is("5f7012e03ea2da5788227a6f")), Comment.class);
    }

    @Test
    public void testUpdate() {
    // update xxx set yy=? where id=?

     <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"_id"</span>).is(<span class="hljs-string">"5f7015e63ea2da1618d173eb"</span>));
     <span class="hljs-type">Update</span> <span class="hljs-variable">update</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Update</span>().set(<span class="hljs-string">"content"</span>, <span class="hljs-string">"itcast"</span>);
     mongoTemplate.updateMulti(query, update, Comment.class);
    

    }
    }

方式二:创建 Repository

/**
 * @Repository @service @controller
 *
 * <Comment,String>  comment 用于指定 要操作的 POJO 对应的 collection; String 指定 主键的数据类型
 * @author ljh
 * @version 1.0
 * @date 2021/12/9 09:19
 * @description 标题
 * @package com.itheima.comment.repository
 */
public interface CommentRepository extends MongoRepository<Comment,String> {
    // 我要根据 userId=2 的值进行查询 select * from xx where userId=2 order by likes desc
<span class="hljs-keyword">public</span> List&lt;Comment&gt; <span class="hljs-title function_">findByUserIdOrderByLikesDesc</span><span class="hljs-params">(Integer userId)</span>;

}

test2:

package com.itheima;

import com.itheima.comment.document.Comment;
import com.itheima.comment.repository.CommentRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.util.List;

/**

  • @author ljh

  • @version 1.0

  • @date 2021/12/9 09:06

  • @description 标题

  • @package com.itheima
    */
    @SpringBootTest
    public class Mongo2Test {

    @Autowired
    private CommentRepository commentRepository;

    // 相同的 CRUD 的操作
    @Test
    public void save(){
    Comment entity = new Comment();
    entity.setUserId(46);
    entity.setLikes(89);
    commentRepository.save(entity);
    }

    // 查询
    @Test
    public void findAll(){
    List<Comment> all = commentRepository.findAll();
    for (Comment comment : all) {
    System.out.println(comment.getLikes());
    }
    }

    // 删除
    @Test
    public void delete(){
    Comment contition = new Comment();
    contition.setId("61b158bc38dd626fbad93e48");
    contition.setUserId(2);

     <span class="hljs-comment">// delete from xxx where id=? and userId=?</span>
     commentRepository.delete(contition);
    

    }
    // 条件查询
    @Test
    public void find(){
    List<Comment> byUserIdOrderByLikesDesc = commentRepository.findByUserIdOrderByLikesDesc(2);
    for (Comment comment : byUserIdOrderByLikesDesc) {
    System.out.println(comment);
    }
    }

}

1615546743719

2.4 功能实现

2.4.1 需求分析

实现发表评论
APP端 点击按钮 --》输入文字 点击提交即可

后台接收之后,进行保存到mongodb即可

发表评论:CommentSaveDto

1615546892049

@Data
public class CommentSaveDto {
    /**
     * 文章 id
     */
    private Long articleId;
<span class="hljs-comment">/**
 * 评论内容
 */</span>
<span class="hljs-keyword">private</span> String content;

}

2.4.2 controller

1639033971437

// 保存文章评论 注意该评论保存到 mongodb 中。
 @Autowired
    private CommentService commentService;
<span class="hljs-comment">/**
 * 发表评论
 */</span>
<span class="hljs-meta">@PostMapping("/saveToMongo")</span>
<span class="hljs-keyword">public</span> Result <span class="hljs-title function_">saveToMongo</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> CommentSaveDto commentSaveDto)</span> <span class="hljs-keyword">throws</span> LeadNewsException {
    commentService.saveToMongo(commentSaveDto);
    <span class="hljs-keyword">return</span> Result.ok();
}

2.4.3 service 层

@Autowired
    private MongoTemplate mongoTemplate;
<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> CommentRepository commentRepository; 

// 发表评论
@Override
public void saveToMongo(CommentSaveDto commentSaveDto) throws LeadNewsException {
//1. 获取当前用户判断是否为匿名用户
if (RequestContextUtil.isAnonymous()) {
//2. 如果是抛出异常
throw new LeadNewsException("不能发表评论");
}
UserTokenInfoExp userInfo = RequestContextUtil.getRequestUserTokenInfo();
//3. 添加数据到 mongo 即可
Comment entity = new Comment();
entity.setUserId(userInfo.getUserId().intValue());
entity.setLikes(0);// 点赞数为 0
entity.setNickName(userInfo.getNickName());
entity.setHeadImage(userInfo.getHeadImage());
entity.setCreatedTime(LocalDateTime.now());
entity.setContent(commentSaveDto.getContent());
entity.setArticleId(commentSaveDto.getArticleId());
entity.setReplys(0);// 发表评论 的是默认是 0 回复
entity.setUpdatedTime(LocalDateTime.now());
commentRepository.save(entity);
}

2.4.4 网关进行配置

1615547177958

spring:
  profiles:
    active: dev
---
server:
  port: 6003
spring:
  application:
    name: leadnews-app-gateway
  profiles: dev
  cloud:
    nacos:
      server-addr: 192.168.211.136:8848
      discovery:
        server-addr: ${spring.cloud.nacos.server-addr}
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': # 匹配所有请求
            allowedOrigins: "*" #跨域处理 允许所有的域
            allowedHeaders: "*"
            allowedMethods: # 支持的方法
              - GET
              - POST
              - PUT
              - DELETE
      routes:
        # 文章微服务
        - id: article
          uri: lb://leadnews-article
          predicates:
            - Path=/article/**
          filters:
            - StripPrefix= 1
        # app 用户微服务
        - id: user
          uri: lb://leadnews-user
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix= 1
        - id: behaviour
          uri: lb://leadnews-behaviour
          predicates:
            - Path=/behaviour/**
          filters:
            - StripPrefix= 1
        - id: comment
          uri: lb://leadnews-comment
          predicates:
            - Path=/comment/**
          filters:
            - StripPrefix= 1

---
server:
port: 6003
spring:
application:
name: leadnews-app-gateway
profiles: test
cloud:
nacos:
server-addr: 192.168.211.136:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "" #跨域处理 允许所有的域
allowedHeaders: "
"
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
# 文章微服务
- id: article
uri: lb://leadnews-article
predicates:
- Path=/article/
filters:
- StripPrefix= 1
# app 用户微服务
- id: user
uri: lb://leadnews-user
predicates:
- Path=/user/

filters:
- StripPrefix= 1
- id: behaviour
uri: lb://leadnews-behaviour
predicates:
- Path=/behaviour/
filters:
- StripPrefix= 1
- id: comment
uri: lb://leadnews-comment
predicates:
- Path=/comment/

filters:
- StripPrefix= 1
---
server:
port: 6003
spring:
application:
name: leadnews-app-gateway
profiles: pro
cloud:
nacos:
server-addr: 192.168.211.136:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "" #跨域处理 允许所有的域
allowedHeaders: "
"
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
# 文章微服务
- id: article
uri: lb://leadnews-article
predicates:
- Path=/article/
filters:
- StripPrefix= 1
# app 用户微服务
- id: user
uri: lb://leadnews-user
predicates:
- Path=/user/

filters:
- StripPrefix= 1
- id: behaviour
uri: lb://leadnews-behaviour
predicates:
- Path=/behaviour/
filters:
- StripPrefix= 1
- id: comment
uri: lb://leadnews-comment
predicates:
- Path=/comment/

filters:
- StripPrefix= 1


3 app 端评论 - 点赞评论

3.1 需求分析

用户点赞,可以增加点赞数量,点赞后不仅仅要增加点赞数,需要记录当前用户对于当前评论的数据记录

1601173225423

点赞评论 就添加一条数据 ,如果取消点赞 就删除一条数据即可

3.2 功能实现

3.2.1 dto 创建

用户点赞:CommentLikeDto

@Data
public class CommentLikeDto {
    /**
     * 评论 id
     */
    private String commentId;
<span class="hljs-comment">/**
 * 1:点赞
 * 0:取消点赞
 */</span>
<span class="hljs-keyword">private</span> Integer operation;

}

1615547293733

3.2.2 controller

 // 点赞评论或者取消点赞
    @PostMapping("/like")
    public Result like(@RequestBody CommentLikeDto commentLikeDto) throws LeadNewsException{
    commentService.like(commentLikeDto);
    <span class="hljs-keyword">return</span> Result.ok();
}

3.2.3 service

 @Override
    public void like(CommentLikeDto commentLikeDto) throws LeadNewsException {
        if (RequestContextUtil.isAnonymous()) {
            //2. 如果是抛出异常
            throw new LeadNewsException("不能发表评论");
        }
        UserTokenInfoExp userTokenInfo = RequestContextUtil.getRequestUserTokenInfo();
        // 点赞  需要向点赞记录表中添加一条记录
    <span class="hljs-comment">//如果是点赞 就insert</span>
    <span class="hljs-keyword">if</span> (commentLikeDto.getOperation() == <span class="hljs-number">1</span>) {

        <span class="hljs-comment">//先查询 如果有点赞记录 不用点赞了  select * from commentLIke where commentId=? and userId=?</span>
        <span class="hljs-type">Query</span> <span class="hljs-variable">query1</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"userId"</span>)
                .is(userTokenInfo.getUserId().intValue())
                .and(<span class="hljs-string">"commentId"</span>).is(commentLikeDto.getCommentId()));
        List&lt;CommentLike&gt; commentLikes = mongoTemplate.find(query1, CommentLike.class);
        <span class="hljs-keyword">if</span> (commentLikes != <span class="hljs-literal">null</span> &amp;&amp; commentLikes.size() &gt; <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">LeadNewsException</span>(<span class="hljs-string">"不能发表评论"</span>);
        }

        <span class="hljs-type">CommentLike</span> <span class="hljs-variable">commentLike</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">CommentLike</span>();
        commentLike.setCommentId(commentLikeDto.getCommentId());
        commentLike.setUserId(userTokenInfo.getUserId().intValue());
        mongoTemplate.insert(commentLike);

        <span class="hljs-comment">//点赞数量 需要+ 1  找到这个评论 将其数量+1</span>
        <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"_id"</span>).is(commentLikeDto.getCommentId()));
        <span class="hljs-type">Update</span> <span class="hljs-variable">update</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Update</span>();
        update.inc(<span class="hljs-string">"likes"</span>);<span class="hljs-comment">//+1</span>
        mongoTemplate.findAndModify(query, update, Comment.class);

    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">//如果是取消点赞 就delete from xx where userId=? and commentId=?</span>
        <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"userId"</span>)
                .is(userTokenInfo.getUserId().intValue())
                .and(<span class="hljs-string">"commentId"</span>).is(commentLikeDto.getCommentId()));
        mongoTemplate.remove(query, CommentLike.class);

        <span class="hljs-comment">//点赞数 -1</span>
        <span class="hljs-type">Query</span> <span class="hljs-variable">query2</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"_id"</span>).is(commentLikeDto.getCommentId()));
        <span class="hljs-type">Update</span> <span class="hljs-variable">update</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Update</span>();
        update.inc(<span class="hljs-string">"likes"</span>, -<span class="hljs-number">1</span>);<span class="hljs-comment">//-1</span>
        mongoTemplate.findAndModify(query2, update, Comment.class);

    }
}

3.2.4 测试

使用 postmen 来测试

4 app 端评论 - 评论列表

4.1 需求分析

1587310483409

查询评论列表,根据当前文章 id 进行检索,按照发布评论的时间进行倒序排列,分页查询(默认 10 条数据)

可以参考这个:https://www.cnblogs.com/linhan/p/4248679.html
1. 每次查询 10 条数据 限制
2. 下一页的时候,传递最后一个评论数据的 【时间】 根据时间查询数据 并限制 10 条 即可

4.2 功能实现

4.2.1 VO 定义

由于返回列表数据需要标记该评论是否被点赞过,之前的 POJO 没有该标记,所以现在添加一个字段进行展示

@Data
public class CommentVo extends Comment {
<span class="hljs-comment">//1标识被当前用户点赞了    0 标识 该评论没有被当前用点赞</span>
<span class="hljs-keyword">private</span> Integer operation=<span class="hljs-number">0</span>;

}

查询评论列表:CommentDto

@Data
public class CommentDto {
<span class="hljs-comment">/**
 * 文章id
 */</span>
<span class="hljs-keyword">private</span> Long articleId;


<span class="hljs-comment">// 最小时间</span>
<span class="hljs-keyword">private</span> LocalDateTime minDate;

}

1615547525029

4.2.2 controller

 // 展示评论的列表 返回值  参数
<span class="hljs-meta">@PostMapping("/loadPage")</span>
<span class="hljs-keyword">public</span> Result&lt;List&lt;CommentVo&gt;&gt;  <span class="hljs-title function_">loadPage</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> CommentDto commentDto)</span> {
    List&lt;CommentVo&gt; voList =  commentService.loadPage(commentDto);
    <span class="hljs-keyword">return</span> Result.ok(voList);
}

4.2.3 service 层

@Override
    public List<CommentVo> loadPage(CommentDto commentDto) {
    <span class="hljs-comment">//select * from comment where creatitme &lt; 你传递过来的时间  and articleId=? order by creattime desc limit 10;</span>
    <span class="hljs-comment">//匿名用户 可以看  但是 不能点赞 也就是点赞的状态为非点赞的状态</span>

    <span class="hljs-comment">//如果是以第一次过来查询 那么传递一个null时间即可</span>
    <span class="hljs-keyword">if</span> (commentDto.getMinDate() == <span class="hljs-literal">null</span>) {
        commentDto.setMinDate(LocalDateTime.now());
    }

    <span class="hljs-comment">//查询条件1</span>
    <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> Query.query(
            Criteria.where(<span class="hljs-string">"articleId"</span>).is(commentDto.getArticleId())
                    .and(<span class="hljs-string">"createdTime"</span>).lt(commentDto.getMinDate())
    );
    <span class="hljs-comment">//排序条件2</span>
    <span class="hljs-type">Sort</span> <span class="hljs-variable">sort</span> <span class="hljs-operator">=</span> Sort.by(Sort.Direction.DESC, <span class="hljs-string">"createdTime"</span>);
    query.with(sort);
    <span class="hljs-comment">//限制条件3</span>
    query.limit(<span class="hljs-number">10</span>);

    List&lt;Comment&gt; comments = mongoTemplate.find(query, Comment.class);

    List&lt;CommentVo&gt; commentVos = JSON.parseArray(JSON.toJSONString(comments), CommentVo.class);

    <span class="hljs-comment">//判断 如果是匿名用户 直接返回</span>
    <span class="hljs-keyword">if</span> (RequestContextUtil.isAnonymous()) {
        <span class="hljs-keyword">return</span> commentVos;
    }
    List&lt;String&gt; ids = comments.stream().map(p -&gt; p.getId()).collect(Collectors.toList());
    <span class="hljs-type">Integer</span> <span class="hljs-variable">userId</span> <span class="hljs-operator">=</span> RequestContextUtil.getUserId();
    <span class="hljs-comment">//查询  select * from commentLike where userId=? and commentId in (?)   ?从上面的评论列表中来 查询出来的值(一定是点赞过的) 永远 &lt;=10</span>
    <span class="hljs-type">Query</span> <span class="hljs-variable">query2</span> <span class="hljs-operator">=</span> Query.query(
            Criteria.where(<span class="hljs-string">"userId"</span>).is(userId)
                    .and(<span class="hljs-string">"commentId"</span>).in(ids)
    );
    List&lt;CommentLike&gt; commentLikes = mongoTemplate.find(query2, CommentLike.class);
    <span class="hljs-comment">//查询到之后 进行循环遍历 执行判断 并修改状态值即可</span>


    <span class="hljs-keyword">for</span> (CommentVo commentVo : commentVos) {
        <span class="hljs-keyword">for</span> (CommentLike commentLike : commentLikes) {
            <span class="hljs-keyword">if</span> (commentLike.getCommentId().equals(commentVo.getId())) {
                commentVo.setOperation(<span class="hljs-number">1</span>);
            }
        }
    }
    <span class="hljs-keyword">return</span> commentVos;
}

4.2.4 测试

5 app 端评论回复 - 发表回复、点赞回复、回复列表

5.1 需求分析

1587348514673

  • 当用户点击了评论中的回复就可以查看所有评论回复内容

  • 可以针对当前评论进行回复,需要更新评论的回复数量

  • 可以对当前评论回复列表进行点赞操作,同时记录当前回复评论点赞信息

5.2 思路分析

(1)数据实体

操作数据实体为 mongodb 中的集合,评论回复集合是 ap_comment_reply

package com.itheima.comment.document;

import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;

import java.math.BigDecimal;
import java.time.LocalDateTime;

@Data
@Document("ap_comment_reply")
public class Reply {
/**
* id
*/

private String id;

<span class="hljs-comment">/**
 * 写下回复的 用户的ID
 */</span>
<span class="hljs-keyword">private</span> Integer userId;

<span class="hljs-comment">/**
 * 写下回复的 用户的昵称
 */</span>
<span class="hljs-keyword">private</span> String nickName;

<span class="hljs-comment">/**
 * 头像
 */</span>
<span class="hljs-keyword">private</span> String headImage;

<span class="hljs-comment">/**
 * 针对的是哪条 评论id 进行回复
 */</span>
<span class="hljs-keyword">private</span> String commentId;

<span class="hljs-comment">/**
 * 回复的内容
 */</span>
<span class="hljs-keyword">private</span> String content;

<span class="hljs-comment">/**
 * 点赞数(回复本身的点赞数量)
 */</span>
<span class="hljs-keyword">private</span> Integer likes;

<span class="hljs-comment">/**
 * 创建时间
 */</span>
<span class="hljs-keyword">private</span> LocalDateTime createdTime;

<span class="hljs-comment">/**
 * 更新时间
 */</span>
<span class="hljs-keyword">private</span> LocalDateTime updatedTime;

}

回复的点赞信息记录

package com.itheima.comment.document;

import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;

@Data
@Document("ap_comment_reply_like")
public class ReplyLike {

<span class="hljs-comment">/**
 * id
 */</span>
<span class="hljs-keyword">private</span> String id;

<span class="hljs-comment">/**
 * 点赞了回复的用户ID
 */</span>
<span class="hljs-keyword">private</span> Integer userId;

<span class="hljs-comment">/**
 * 点赞了哪一条回复
 */</span>
<span class="hljs-keyword">private</span> String replyId;


<span class="hljs-comment">//点赞 就是有记录 取消点赞 就是删除记录即可</span>

/* //*
* 1:点赞
* 0:取消点赞
//
private Integer operation;*/
}

1639034188205

(2)思路分析:

1,用户点击回复,根据当前评论 id 查询对应的所有回复进行展示

2,用户针对于当前的评论进行了回复,需要保存数据,同时需要更新当前评论的回复数

3,可以对回复列表进行点赞操作

5.3 功能实现

(1)dto 创建

1615553590984

CommentReplySaveDto

@Data
public class CommentReplySaveDto {
<span class="hljs-comment">//回复内容</span>
<span class="hljs-keyword">private</span> String content;

<span class="hljs-comment">//针对哪一个评论进行回复</span>

<span class="hljs-keyword">private</span> String commentId;

}

CommentReplyLikeDto:

@Data
public class CommentReplyLikeDto {
<span class="hljs-comment">/**
 * 针对 回复的ID  为该回复进行点赞或者取消点赞
 */</span>
<span class="hljs-keyword">private</span> String commentReplyId;

<span class="hljs-comment">/**
 * 1:点赞
 * 0:取消点赞
 */</span>
<span class="hljs-keyword">private</span> Integer operation;

}

CommentRelyDto

/**
 * 回复列表查询 传递最后一条回复的时间
 */
@Data
public class CommentRelyDto {
<span class="hljs-comment">/**
 * 评论的ID
 */</span>
<span class="hljs-keyword">private</span> String commentId;


<span class="hljs-comment">// 最小时间</span>
<span class="hljs-keyword">private</span> LocalDateTime minDate;

}

(2)controller

package com.itheima.comment.controller;

import com.itheima.comment.dto.CommentRelyDto;
import com.itheima.comment.dto.CommentReplyLikeDto;
import com.itheima.comment.dto.CommentReplySaveDto;
import com.itheima.comment.service.ReplyService;
import com.itheima.comment.vo.ReplyVo;
import com.itheima.common.pojo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**

  • @author ljh

  • @version 1.0

  • @date 2021/12/9 11:59

  • @description 标题

  • @package com.itheima.comment.controller
    */
    @RestController
    @RequestMapping("/reply")
    public class ReplyController {

    @Autowired
    private ReplyService replyService;

    // 发表回复
    @PostMapping("/saveReply")
    public Result saveReply(@RequestBody CommentReplySaveDto commentReplySaveDto) throws Exception{
    replyService.saveReply(commentReplySaveDto);
    return Result.ok();
    }

    // 点赞回复
    @PostMapping("/replyLike")
    public Result replyLike(@RequestBody CommentReplyLikeDto commentReplyLikeDto) throws Exception{
    replyService.replyLike(commentReplyLikeDto);
    return Result.ok();
    }

    // 获取回复列表
    @PostMapping("/loadPage")
    public Result<List<ReplyVo>> loadPage(@RequestBody CommentRelyDto commentRelyDto){
    List<ReplyVo> commentReplyVoList = replyService.loadPage(commentRelyDto);
    return Result.ok(commentReplyVoList);
    }
    }

加载评论回复列表数据封装类

package com.itheima.comment.vo;

import com.itheima.comment.document.Reply;
import lombok.Data;

/**

  • @author ljh
  • @version 1.0
  • @date 2021/12/9 14:35
  • @description 标题
  • @package com.itheima.comment.vo
    */
    @Data
    public class ReplyVo extends Reply {
    private Integer operation=0;
    }

(3)service

package com.itheima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.itheima.comment.document.Comment;
import com.itheima.comment.document.CommentLike;
import com.itheima.comment.document.Reply;
import com.itheima.comment.document.ReplyLike;
import com.itheima.comment.dto.CommentRelyDto;
import com.itheima.comment.dto.CommentReplyLikeDto;
import com.itheima.comment.dto.CommentReplySaveDto;
import com.itheima.comment.repository.ReplyRepository;
import com.itheima.comment.service.ReplyService;
import com.itheima.comment.vo.ReplyVo;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.util.au.UserTokenInfoExp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**

  • @author ljh

  • @version 1.0

  • @date 2021/12/9 12:01

  • @description 标题

  • @package com.itheima.comment.service.impl
    */
    @Service
    public class ReplyServiceImpl implements ReplyService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private ReplyRepository replyRepository;

    @Override
    public void saveReply(CommentReplySaveDto replyDto) throws LeadNewsException {
    // 就是发表回复

     <span class="hljs-comment">//获取当前用户的信息 判断是否匿名用户 如果是匿名用户 返回错误</span>
     <span class="hljs-keyword">if</span> (RequestContextUtil.isAnonymous()) {
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">LeadNewsException</span>(<span class="hljs-string">"不能点赞"</span>);
     }
    
     <span class="hljs-type">UserTokenInfoExp</span> <span class="hljs-variable">userTokenInfo</span> <span class="hljs-operator">=</span> RequestContextUtil.getRequestUserTokenInfo();
     <span class="hljs-type">Reply</span> <span class="hljs-variable">entity</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Reply</span>();
     entity.setCommentId(replyDto.getCommentId());
     entity.setContent(replyDto.getContent());
     entity.setCreatedTime(LocalDateTime.now());
     entity.setHeadImage(userTokenInfo.getHeadImage());
     entity.setLikes(<span class="hljs-number">0</span>);
     entity.setNickName(userTokenInfo.getNickName());
     entity.setUpdatedTime(LocalDateTime.now());
     entity.setUserId(userTokenInfo.getUserId().intValue());
     replyRepository.save(entity);
    
     <span class="hljs-comment">//找到这个评论 将回复数量+1  update xxx set replays=replays+1 where id=?</span>
     <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"_id"</span>).is(replyDto.getCommentId()));
     <span class="hljs-type">Update</span> <span class="hljs-variable">update</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Update</span>();
     update.inc(<span class="hljs-string">"replys"</span>);
     mongoTemplate.findAndModify(query, update, Comment.class);
    

    }

    @Override
    public void replyLike(CommentReplyLikeDto ReplyLikeDto) throws LeadNewsException {

     <span class="hljs-keyword">if</span> (RequestContextUtil.isAnonymous()) {
         <span class="hljs-comment">//2.如果是抛出异常</span>
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">LeadNewsException</span>(<span class="hljs-string">"不能点赞回复"</span>);
     }
     <span class="hljs-type">UserTokenInfoExp</span> <span class="hljs-variable">userTokenInfo</span> <span class="hljs-operator">=</span> RequestContextUtil.getRequestUserTokenInfo();
     <span class="hljs-comment">//点赞  需要向点赞记录表中添加一条记录</span>
    
     <span class="hljs-comment">//如果是点赞 就insert</span>
     <span class="hljs-keyword">if</span> (ReplyLikeDto.getOperation() == <span class="hljs-number">1</span>) {
    
         <span class="hljs-comment">//先查询 如果有点赞记录 不用点赞了  select * from replyLike where replyId=? and userId=?</span>
         <span class="hljs-type">Query</span> <span class="hljs-variable">query1</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"userId"</span>)
                 .is(userTokenInfo.getUserId().intValue())
                 .and(<span class="hljs-string">"replyId"</span>).is(ReplyLikeDto.getReplyId()));
         List&lt;ReplyLike&gt; replyLikes = mongoTemplate.find(query1, ReplyLike.class);
         <span class="hljs-keyword">if</span> (replyLikes != <span class="hljs-literal">null</span> &amp;&amp; replyLikes.size() &gt; <span class="hljs-number">0</span>) {
             <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">LeadNewsException</span>(<span class="hljs-string">"不能点赞已经有点赞记录了"</span>);
         }
    
         <span class="hljs-type">ReplyLike</span> <span class="hljs-variable">replyLike</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ReplyLike</span>();
         replyLike.setReplyId(ReplyLikeDto.getReplyId());
         replyLike.setUserId(userTokenInfo.getUserId().intValue());
         mongoTemplate.insert(replyLike);
    
         <span class="hljs-comment">//回复中的点赞数量 需要+ 1  找到这个评论 将其数量+1</span>
         <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"_id"</span>).is(ReplyLikeDto.getReplyId()));
         <span class="hljs-type">Update</span> <span class="hljs-variable">update</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Update</span>();
         update.inc(<span class="hljs-string">"likes"</span>);<span class="hljs-comment">//+1</span>
         mongoTemplate.findAndModify(query, update, Reply.class);
    
     } <span class="hljs-keyword">else</span> {
         <span class="hljs-comment">//如果是取消点赞 就delete from xx where userId=? and commentId=?</span>
         <span class="hljs-type">Query</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"userId"</span>)
                 .is(userTokenInfo.getUserId().intValue())
                 .and(<span class="hljs-string">"replyId"</span>).is(ReplyLikeDto.getReplyId()));
         mongoTemplate.remove(query, ReplyLike.class);
    
         <span class="hljs-comment">//点赞数 -1</span>
         <span class="hljs-type">Query</span> <span class="hljs-variable">query2</span> <span class="hljs-operator">=</span> Query.query(Criteria.where(<span class="hljs-string">"_id"</span>).is(ReplyLikeDto.getReplyId()));
         <span class="hljs-type">Update</span> <span class="hljs-variable">update</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Update</span>();
         update.inc(<span class="hljs-string">"likes"</span>, -<span class="hljs-number">1</span>);<span class="hljs-comment">//-1</span>
         mongoTemplate.findAndModify(query2, update, Reply.class);
     }
    

    }

    @Override
    public List<ReplyVo> loadPage(CommentRelyDto commentRelyDto) {
    //select * from reply where commentId=? and createdTime<? order by creattime desc limit 10;

     <span class="hljs-keyword">if</span>(commentRelyDto.getMinDate()==<span class="hljs-literal">null</span>){
         commentRelyDto.setMinDate(LocalDateTime.now());
     }
    
     <span class="hljs-type">Query</span> <span class="hljs-variable">query</span>  <span class="hljs-operator">=</span>Query.query(
             Criteria.where(<span class="hljs-string">"commentId"</span>).is(commentRelyDto.getCommentId())
             .and(<span class="hljs-string">"createdTime"</span>).lt(commentRelyDto.getMinDate())
     );
     Sort sort=Sort.by(Sort.Direction.DESC,<span class="hljs-string">"createdTime"</span>);
     query.with(sort);
    
     query.limit(<span class="hljs-number">10</span>);
    
     List&lt;Reply&gt; replies = mongoTemplate.find(query, Reply.class);
    
     List&lt;ReplyVo&gt; replyVos = JSON.parseArray(JSON.toJSONString(replies), ReplyVo.class);
     <span class="hljs-comment">//如果是匿名用户 直接返回列表</span>
     <span class="hljs-keyword">if</span>(RequestContextUtil.isAnonymous()){
         <span class="hljs-keyword">return</span> replyVos;
     }
    
     List&lt;String&gt; ids = replies.stream().map(p -&gt; p.getId()).collect(Collectors.toList());
     <span class="hljs-comment">//replyVos 数据都是没点赞回复的  回复数据列表</span>
    
     <span class="hljs-comment">//select * from reply_like where userId=? and relyId in (?)  ? 就是上边查询到的所有的回复ID的值 查询到的一定是点赞了的 而且&lt;=10</span>
    
     <span class="hljs-type">Query</span> <span class="hljs-variable">query2</span> <span class="hljs-operator">=</span> Query.query(
             Criteria.where(<span class="hljs-string">"userId"</span>).is(RequestContextUtil.getUserId())
             .and(<span class="hljs-string">"replyId"</span>).in(ids)
     );
     List&lt;ReplyLike&gt; replyLikes = mongoTemplate.find(query2, ReplyLike.class);
    
     <span class="hljs-keyword">for</span> (ReplyVo replyVo : replyVos) {
    
         <span class="hljs-keyword">for</span> (ReplyLike replyLike : replyLikes) {
             <span class="hljs-keyword">if</span>(replyLike.getReplyId().equals(replyVo.getId())){
                 replyVo.setOperation(<span class="hljs-number">1</span>);
             }
         }
     }
    
     <span class="hljs-keyword">return</span> replyVos;
    

    }
    }

(3)repository:

package com.itheima.comment.repository;

import com.itheima.comment.document.Reply;
import org.springframework.data.mongodb.repository.MongoRepository;

/**

  • @Repository @service @controller
  • @author ljh
  • @version 1.0
  • @date 2021/12/9 09:19
  • @description 标题
  • @package com.itheima.comment.repository
    */
    public interface ReplyRepository extends MongoRepository<Reply,String> {
    }

1639034305265