第十一章 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>

    <artifactId>itheima-leadnews-service-comment</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.itheima</groupId>
            <artifactId>itheima-leadnews-comment-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.itheima</groupId>
            <artifactId>itheima-leadnews-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
    </dependencies>

</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 {

    /**
     * id 主键
     */
    private String id;

    /**
     * 评论人的ID
     */
    private Integer userId;

    /**
     * 评论人的昵称
     */
    private String nickName;

    /**
     * 评论人的头像
     */
    private String headImage;

    /**
     * 文章id
     */
    private Long articleId;

    /**
     * 文章所属的频道ID
     */
    //private Integer channelId;

    /**
     * 评论人写的内容
     */
    private String content;


    /**
     * 总的点赞数
     */
    private Integer likes;

    /**
     * 总的回复数
     */
    private Integer replys;

    /*  *//**
     * 经度
     *//*
    private BigDecimal longitude;

    *//**
     * 维度
     *//*
    private BigDecimal latitude;
*/

    /**
     * 评论时间
     */
    private LocalDateTime createdTime;

    /**
     * 更新时间
     */
    private 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=?

        Query query = Query.query(Criteria.where("_id").is("5f7015e63ea2da1618d173eb"));
        Update update = new Update().set("content", "itcast");
        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

    public List<Comment> findByUserIdOrderByLikesDesc(Integer userId);
}

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);

        // delete from xxx where id=? and userId=?
        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;

    /**
     * 评论内容
     */
    private String content;
}

2.4.2 controller

1639033971437

//保存文章评论 注意该评论保存到 mongodb中。
 @Autowired
    private CommentService commentService;

    /**
     * 发表评论
     */
    @PostMapping("/saveToMongo")
    public Result saveToMongo(@RequestBody CommentSaveDto commentSaveDto) throws LeadNewsException {
        commentService.saveToMongo(commentSaveDto);
        return Result.ok();
    }

2.4.3 service层

@Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private 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;

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

1615547293733

3.2.2 controller

 //点赞评论或者取消点赞
    @PostMapping("/like")
    public Result like(@RequestBody CommentLikeDto commentLikeDto) throws LeadNewsException{

        commentService.like(commentLikeDto);
        return 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();
        //点赞  需要向点赞记录表中添加一条记录

        //如果是点赞 就insert
        if (commentLikeDto.getOperation() == 1) {

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

            CommentLike commentLike = new CommentLike();
            commentLike.setCommentId(commentLikeDto.getCommentId());
            commentLike.setUserId(userTokenInfo.getUserId().intValue());
            mongoTemplate.insert(commentLike);

            //点赞数量 需要+ 1  找到这个评论 将其数量+1
            Query query = Query.query(Criteria.where("_id").is(commentLikeDto.getCommentId()));
            Update update = new Update();
            update.inc("likes");//+1
            mongoTemplate.findAndModify(query, update, Comment.class);

        } else {
            //如果是取消点赞 就delete from xx where userId=? and commentId=?
            Query query = Query.query(Criteria.where("userId")
                    .is(userTokenInfo.getUserId().intValue())
                    .and("commentId").is(commentLikeDto.getCommentId()));
            mongoTemplate.remove(query, CommentLike.class);

            //点赞数 -1
            Query query2 = Query.query(Criteria.where("_id").is(commentLikeDto.getCommentId()));
            Update update = new Update();
            update.inc("likes", -1);//-1
            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 {

    //1标识被当前用户点赞了    0 标识 该评论没有被当前用点赞
    private Integer operation=0;
}

查询评论列表:CommentDto

@Data
public class CommentDto {

    /**
     * 文章id
     */
    private Long articleId;


    // 最小时间
    private LocalDateTime minDate;

}

1615547525029

4.2.2 controller

 //展示评论的列表 返回值  参数

    @PostMapping("/loadPage")
    public Result<List<CommentVo>>  loadPage(@RequestBody CommentDto commentDto) {
        List<CommentVo> voList =  commentService.loadPage(commentDto);
        return Result.ok(voList);
    }

4.2.3 service层

@Override
    public List<CommentVo> loadPage(CommentDto commentDto) {

        //select * from comment where creatitme < 你传递过来的时间  and articleId=? order by creattime desc limit 10;
        //匿名用户 可以看  但是 不能点赞 也就是点赞的状态为非点赞的状态

        //如果是以第一次过来查询 那么传递一个null时间即可
        if (commentDto.getMinDate() == null) {
            commentDto.setMinDate(LocalDateTime.now());
        }

        //查询条件1
        Query query = Query.query(
                Criteria.where("articleId").is(commentDto.getArticleId())
                        .and("createdTime").lt(commentDto.getMinDate())
        );
        //排序条件2
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        //限制条件3
        query.limit(10);

        List<Comment> comments = mongoTemplate.find(query, Comment.class);

        List<CommentVo> commentVos = JSON.parseArray(JSON.toJSONString(comments), CommentVo.class);

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


        for (CommentVo commentVo : commentVos) {
            for (CommentLike commentLike : commentLikes) {
                if (commentLike.getCommentId().equals(commentVo.getId())) {
                    commentVo.setOperation(1);
                }
            }
        }
        return 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;

    /**
     * 写下回复的 用户的ID
     */
    private Integer userId;

    /**
     * 写下回复的 用户的昵称
     */
    private String nickName;

    /**
     * 头像
     */
    private String headImage;

    /**
     * 针对的是哪条 评论id 进行回复
     */
    private String commentId;

    /**
     * 回复的内容
     */
    private String content;

    /**
     * 点赞数(回复本身的点赞数量)
     */
    private Integer likes;

    /**
     * 创建时间
     */
    private LocalDateTime createdTime;

    /**
     * 更新时间
     */
    private 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 {

    /**
     * id
     */
    private String id;

    /**
     * 点赞了回复的用户ID
     */
    private Integer userId;

    /**
     * 点赞了哪一条回复
     */
    private String replyId;


    //点赞 就是有记录 取消点赞 就是删除记录即可

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

1639034188205

(2)思路分析:

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

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

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

5.3 功能实现

(1)dto创建

1615553590984

CommentReplySaveDto

@Data
public class CommentReplySaveDto {

    //回复内容
    private String content;

    //针对哪一个评论进行回复

    private String commentId;


}

CommentReplyLikeDto:

@Data
public class CommentReplyLikeDto {

    /**
     * 针对 回复的ID  为该回复进行点赞或者取消点赞
     */
    private String commentReplyId;

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

CommentRelyDto

/**
 * 回复列表查询 传递最后一条回复的时间
 */
@Data
public class CommentRelyDto {

    /**
     * 评论的ID
     */
    private String commentId;


    // 最小时间
    private 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 {
        //就是发表回复

        //获取当前用户的信息 判断是否匿名用户 如果是匿名用户 返回错误
        if (RequestContextUtil.isAnonymous()) {
            throw new LeadNewsException("不能点赞");
        }

        UserTokenInfoExp userTokenInfo = RequestContextUtil.getRequestUserTokenInfo();
        Reply entity = new Reply();
        entity.setCommentId(replyDto.getCommentId());
        entity.setContent(replyDto.getContent());
        entity.setCreatedTime(LocalDateTime.now());
        entity.setHeadImage(userTokenInfo.getHeadImage());
        entity.setLikes(0);
        entity.setNickName(userTokenInfo.getNickName());
        entity.setUpdatedTime(LocalDateTime.now());
        entity.setUserId(userTokenInfo.getUserId().intValue());
        replyRepository.save(entity);

        //找到这个评论 将回复数量+1  update xxx set replays=replays+1 where id=?
        Query query = Query.query(Criteria.where("_id").is(replyDto.getCommentId()));
        Update update = new Update();
        update.inc("replys");
        mongoTemplate.findAndModify(query, update, Comment.class);

    }

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

        if (RequestContextUtil.isAnonymous()) {
            //2.如果是抛出异常
            throw new LeadNewsException("不能点赞回复");
        }
        UserTokenInfoExp userTokenInfo = RequestContextUtil.getRequestUserTokenInfo();
        //点赞  需要向点赞记录表中添加一条记录

        //如果是点赞 就insert
        if (ReplyLikeDto.getOperation() == 1) {

            //先查询 如果有点赞记录 不用点赞了  select * from replyLike where replyId=? and userId=?
            Query query1 = Query.query(Criteria.where("userId")
                    .is(userTokenInfo.getUserId().intValue())
                    .and("replyId").is(ReplyLikeDto.getReplyId()));
            List<ReplyLike> replyLikes = mongoTemplate.find(query1, ReplyLike.class);
            if (replyLikes != null && replyLikes.size() > 0) {
                throw new LeadNewsException("不能点赞已经有点赞记录了");
            }

            ReplyLike replyLike = new ReplyLike();
            replyLike.setReplyId(ReplyLikeDto.getReplyId());
            replyLike.setUserId(userTokenInfo.getUserId().intValue());
            mongoTemplate.insert(replyLike);

            //回复中的点赞数量 需要+ 1  找到这个评论 将其数量+1
            Query query = Query.query(Criteria.where("_id").is(ReplyLikeDto.getReplyId()));
            Update update = new Update();
            update.inc("likes");//+1
            mongoTemplate.findAndModify(query, update, Reply.class);

        } else {
            //如果是取消点赞 就delete from xx where userId=? and commentId=?
            Query query = Query.query(Criteria.where("userId")
                    .is(userTokenInfo.getUserId().intValue())
                    .and("replyId").is(ReplyLikeDto.getReplyId()));
            mongoTemplate.remove(query, ReplyLike.class);

            //点赞数 -1
            Query query2 = Query.query(Criteria.where("_id").is(ReplyLikeDto.getReplyId()));
            Update update = new Update();
            update.inc("likes", -1);//-1
            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;

        if(commentRelyDto.getMinDate()==null){
            commentRelyDto.setMinDate(LocalDateTime.now());
        }

        Query query  =Query.query(
                Criteria.where("commentId").is(commentRelyDto.getCommentId())
                .and("createdTime").lt(commentRelyDto.getMinDate())
        );
        Sort sort=Sort.by(Sort.Direction.DESC,"createdTime");
        query.with(sort);

        query.limit(10);

        List<Reply> replies = mongoTemplate.find(query, Reply.class);

        List<ReplyVo> replyVos = JSON.parseArray(JSON.toJSONString(replies), ReplyVo.class);
        //如果是匿名用户 直接返回列表
        if(RequestContextUtil.isAnonymous()){
            return replyVos;
        }

        List<String> ids = replies.stream().map(p -> p.getId()).collect(Collectors.toList());
        //replyVos 数据都是没点赞回复的  回复数据列表

        //select * from reply_like where userId=? and relyId in (?)  ? 就是上边查询到的所有的回复ID的值 查询到的一定是点赞了的 而且<=10

        Query query2 = Query.query(
                Criteria.where("userId").is(RequestContextUtil.getUserId())
                .and("replyId").in(ids)
        );
        List<ReplyLike> replyLikes = mongoTemplate.find(query2, ReplyLike.class);

        for (ReplyVo replyVo : replyVos) {

            for (ReplyLike replyLike : replyLikes) {
                if(replyLike.getReplyId().equals(replyVo.getId())){
                    replyVo.setOperation(1);
                }
            }
        }

        return 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

posted on 2022-04-25 00:50  ofanimon  阅读(214)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css