day09-MongoDB

news2024/10/7 20:27:13

文章目录

  • day09-MongoDB
  • 一、回顾
    • 1.1. 行为实战核心要点说明
  • 二、评论系统
    • 2.1 MongoDB
      • 2.1.1 MongoDB简介
        • ①简介
        • ②体系结构与术语
      • 2.1.2 安装与连接
      • 2.1.3 Springboot整合MongoDB
        • ①引入依赖
        • ②添加服务端配置
        • ③准备实体类
        • ④测试-新增
        • ⑤测试-查询
        • ⑥测试-更新
        • 测试-删除
    • 2.2 app端评论-发表评论
      • 2.2.1 需求分析
        • ①需求分析
        • ②对应数据存储结果-集合
      • 2.2.2 接口定义
        • ①实现步骤
        • ②用户远程接口-查询用户-接口定义
        • ③长整型数据精度丢失问题
    • 2.3 app端评论-点赞评论
      • 2.3.1 需求分析
      • 2.3.2 思路分析
      • 2.3.3 接口定义
      • 2.3.4 接口实现
    • 2.4 app端评论-评论列表
      • 2.4.1 需求分析
      • 2.4.2 接口定义
      • 2.4.3 需求分析
      • 2.4.4 接口实现
    • 2.5 app端评论回复-发表回复、点赞回复、回复列表
    • 2.6 热点评论
      • 2.6.1 需求分析
      • 实现思路-计算热点评论


day09-MongoDB

一、回顾

1.1. 行为实战核心要点说明

  • 技术方案
    Redis+MySQL
    Redis:负责对外提供读与写,因为行为对读写的性能很高,不能直接去操作MySQL
    MySQL:基于MQ实现异步数据同步,(不使用线程池的原因是因为Threadpool是基于本地内存的,不能把大量的数据放在线程池里,数据量过多),Redis操作完数据,把更改的数据同步到MySQL的行为表中
  • 各行为接口
    • user服务
      • 关注与取消关注接口
      • Redis设计:
        • ZSET——关注列表
          • key:behavior:follow:list:当前用户ID
          • score:关注的时间
          • value:作者的用户ID
        • ZSET——粉丝列表
          • key:behavior:follow:list:当前用户ID
          • score:被关注的时间
          • value:粉丝的用户ID
    • article服务
      • 收藏与取消收藏接口
      • Redis设计-HASH类型
        • key:behavior:coll:当前用户ID
        • value:
          • key:文章ID
          • value:文章详情
      • 文章行为关系数据查询接口
    • behavior服务
      • 点赞与取消点赞接口
      • Redis设计-HASH类型
        • key:behavior:likes:文章ID
        • value:
          • key:用户ID
          • value:操作的详情
      • 阅读接口
      • 不喜欢与取消不喜欢接口

二、评论系统

2.1 MongoDB

2.1.1 MongoDB简介

①简介

端口号:27017
默认不支持事务
MongoDB是一个开源、高性能、无模式的文档型数据库
是NoSQL数据库产品中的一种,是最像关系型数据库(MySQL)的非关系性数据库

  • 数据存储量较大,甚至巨大
  • 对数据读写的响应速度要求非常高
  • 某些数据安全性要求不高,可以接收一定范围内的误差
  • 数据具有结构型(BSON)
    应用场景:
    评论、弹幕、观众列表中的一条数据
②体系结构与术语

在这里插入图片描述
在这里插入图片描述

2.1.2 安装与连接

启动MongoDB

docker start mongo-service

mongoDB连接工具——studio3t安装
studio3t是MongoDB优秀的客户端工具。官方地址在https://studio3t.com/

2.1.3 Springboot整合MongoDB

①引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
②添加服务端配置
server:
  port: 9998
spring:
  data:
    mongodb:
      host: 192.168.200.130
      port: 27017
      database: leadnews-comment
③准备实体类
/**
 * APP评论信息
 */
@Data
// 使用这个注解来映射实体类和集合的关系
@Document("ap_comment")
public class ApComment {

    /**
     * id
     */
    private String id;

    /**
     * 用户ID
     */
    private Integer userId;

    /**
     * 用户昵称
     */
    private String userName;

    /**
     * 文章id或动态id
     */
    private Long objectId;

    /**
     * 频道ID
     */
    private Integer channelId;

    /**
     * 评论内容类型
     * 0 文章
     * 1 动态
     */
    private Integer type;

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

    /**
     * 作者头像
     */
    private String image;

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

    /**
     * 回复数
     */
    private Integer reply;

    /**
     * 文章标记
     * 0 普通评论
     * 1 热点评论
     * 2 推荐评论
     * 3 置顶评论
     * 4 精品评论
     * 5 大V 评论
     */
    private Integer flag;

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

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

    /**
     * 地理位置
     */
    private String address;

    /**
     * 评论排列序号
     */
    private Integer ord;

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

    /**
     * 更新时间
     */
    private Date updatedTime;

}
④测试-新增
package com.itheima.mongo.test;

import com.itheima.mongo.pojo.ApComment;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;

/**
 * @author tp
 * @since 2024/2/19 13:24
 */

@SpringBootTest
@RunWith(SpringRunner.class)
public class MongoTest {

	@Autowired
	private MongoTemplate mongoTemplate;

	/**
	 * 测试新文档
	 */
	@Test
	public void testAddDocument() {
		for (int i = 1; i <= 10; i++) {
			ApComment apComment = new ApComment();
			apComment.setId(String.valueOf(i));// 评论id
			apComment.setUserId(i);// 评论用户id
			apComment.setUserName("测试用户"+i);// 评论用户名
			apComment.setType(0);// 内容类型,0表示文章类型
			apComment.setObjectId(Long.valueOf(10+i));//文章ID
			if (i % 2 == 0) {
				apComment.setFlag(1);// 热点评论
			} else {
				apComment.setFlag(0);// 普通评论
			}
			apComment.setContent("测试内容"+i);// 评论内容
			apComment.setLikes(100+i);// 点赞数
			apComment.setReply(0);// 回复数
			apComment.setCreatedTime(new Date());// 创建时间
			apComment.setUpdatedTime(new Date());// 创建时间
			// mongoTemplate.insert(apComment);// 仅表示新增文档
			mongoTemplate.save(apComment);// 表示新增文档或跟新文档
		}

	}
}

在测试的时候发现,MongoDB可以不创建数据库,可以不创建表,因为在运行的时候,会先读取配置的里database: leadnews-comment的值,发现数据库里没有这个数据库创建,同样的,读取@Document("ap_comment")里的值,发现没有这个集合就创建了这个集合。

⑤测试-查询
/**
	 * 测试查询
	 */
	@Test
	public void testQueryDocument() {
		System.out.println(mongoTemplate.findById("7", ApComment.class));
		Query query = Query.query(Criteria.where("userName").is("测试用户7"));
		System.out.println("----------------------------------------------");
		// 查询一条数据
		ApComment one = mongoTemplate.findOne(query, ApComment.class);
		System.out.println(one);

		System.out.println("-----------------------------------------------");

		// 查询的多条
		List<ApComment> all = mongoTemplate.findAll(ApComment.class);
		all.forEach(x-> System.out.println(x));
		System.out.println("-----------------------------------------------");

		// 查询列表数据:单条件条件查询
		List<ApComment> flag = mongoTemplate.find(Query.query(Criteria.where("flag").is(1)), ApComment.class);
		flag.forEach(x-> System.out.println(x));
		System.out.println("-----------------------------------------------");


		// 查询列表数据:多条件条件查询
		List<ApComment> flag1 = mongoTemplate.find(Query.query(Criteria.where("flag").is(1).and("likes").gt(102)), ApComment.class);
		flag1.forEach(x-> System.out.println(x));

		System.out.println("-----------------------------------------------");

		//查询列表数据:根据域进行排序和限制查询条数
		List<ApComment> apComments = mongoTemplate.find(Query.query(Criteria.where("flag").is(1).and("likes").gt(102)).with(Sort.by(Sort.Direction.DESC, "likes")).limit(3), ApComment.class);
		apComments.forEach(x-> System.out.println(x));

	}
⑥测试-更新

前两种常用,后一种有数字增减,可用

/**
	 * 测试更新文档
	 */
	@Test
	public void testUpdateDocument() {

		ApComment byId = mongoTemplate.findById("7", ApComment.class);
		byId.setContent("测试内容007");
		// 1. save
		mongoTemplate.save(byId);
		// 2. updateFirst(非线程安全的方法)
		mongoTemplate.updateFirst(Query.query(Criteria.where("userId").is(7)), Update.update("content", "修改的测试内容007"), ApComment.class);
		// 3. findAndModify(线程安全的方法)
		mongoTemplate.findAndModify(Query.query(Criteria.where("userId").is(7)), Update.update("content", "修改的测试内容007"), ApComment.class);
	}
测试-删除
/**
	 * 测试删除文档
	 */
	@Test
	public void testDeleteDocument() {
		// 1. 查询并删除
		// ApComment apComment = mongoTemplate.findById("7", ApComment.class);
		// mongoTemplate.remove(apComment);

		// 2. 根据条件删除
		mongoTemplate.remove(Query.query(Criteria.where("flag").is(1)), ApComment.class);
	}

2.2 app端评论-发表评论

2.2.1 需求分析

①需求分析

在这里插入图片描述

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

APP评论信息
在这里插入图片描述
APP评论信息点赞
在这里插入图片描述
这两个集合是一对多的关系,表示一条评论可以让多个app用户点赞

2.2.2 接口定义

在这里插入图片描述

①实现步骤

1、搭建评论微服务
(1)创建项目heima-leadnews-comment
在这里插入图片描述
(2)bootstrap.yml
其中自动配置项去除了关于数据源的配置,因为这个项目不需要查询数据库,查询的mongodb
(3)nacos中添加comment的配置

spring:
  data:
    mongodb:
      host: 192.168.200.130
      port: 27017
      database: leadnews-comment

(4)启动类

@SpringBootApplication
@EnableDiscoveryClient
public class CommentApplication {

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

(5)添加WebMvcConfig

package com.heima.comment.config;

import com.heima.common.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
         registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**")
                 //放行swagger和knife4j
                 .excludePathPatterns( "/v2/api-docs",
                         "/doc.html",
                         "/swagger-resources/configuration/ui",
                         "/swagger-resources",
                         "/swagger-resources/configuration/security",
                         "/swagger-ui.html",
                         "/webjars/**",
                         "/actuator/**");
    }
}

(6)接口定义
controller

@RestController
@RequestMapping("/api/v1/comment")
public class ApCommentController {

	/**
	 * 新增评论
	 * @return
	 */
	@PostMapping("/save")
	public ResponseResult save(@RequestBody CommentSaveDto dto) {
		return null;
	}
}

service

public interface ApCommentService{

	/**
	 * 新增评论
	 * @param dto
	 * @return
	 */
	ResponseResult save(CommentSaveDto dto);
}

2、实现思路
判断用户是否存在
判断文章是否存在
判断评论内容是否大于140字
安全过滤
保存评论

serviceImpl

@Service
public class ApCommentServiceImpl implements ApCommentService {
	@Autowired
	private IUserClient userClient;

	@Autowired
	private IArticleClient articleClient;

	@Autowired
	private MongoTemplate mongoTemplate;

	@Override
	public ResponseResult save(CommentSaveDto dto) {
		// 1. 判断参数是否为空
		if (dto.getArticleId()==null || StringUtils.isBlank(dto.getContent())){
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}
		// 2. 判断用户是否存在——调用user的feign接口(此feign接口一定要在user服务的webMvcConfig中放行)
		Integer userId = ThreadLocalUtil.getUserId();
		ApUser apUser = userClient.findOne(userId);
		if (apUser == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"APP用户不存在");
		}

		// 3. 判断文章是否存在
		ApArticle apArticle = articleClient.findOne(dto.getArticleId());
		if (apArticle == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"文章不存在");
		}

		// 4. 判断评论内容是否大于140字
		if (dto.getContent().length() > 140) {
			return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"内容长度超过140字");
		}
		// 5. 安全过滤(DFA审核和百度云文本审核)

		// 6. 保存评论到MongoDB中
		ApComment apComment = new ApComment();
		apComment.setUserId(userId);
		apComment.setUserName(apUser.getName());
		apComment.setImage(apUser.getImage());
		apComment.setType(0);	//评论的内容类型,0表示文章
		apComment.setObjectId(dto.getArticleId());
		apComment.setContent(dto.getContent());
		apComment.setLikes(0);
		apComment.setReply(0);
		apComment.setFlag(0);
		apComment.setCreatedTime(new Date());
		apComment.setUpdatedTime(new Date());

		mongoTemplate.save(apComment);
		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
	}
}

3、配置网关
在这里插入图片描述

②用户远程接口-查询用户-接口定义

在这里插入图片描述

package com.heima.apis.user;

import com.heima.model.user.pojos.ApUser;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @author tp
 * @since 2024/2/19 16:17
 */

@FeignClient("leadnews-user")
public interface IUserClient {

	/**
	 * 根据id查询用户
	 * @param id
	 * @return
	 */
	@GetMapping("/api/v1/user/one/{id}")
	public ApUser findOne(@PathVariable("id") Integer id);
}

ApUserFeign

@FeignClient("leadnews-user")
public interface IUserClient {

	/**
	 * 根据id查询用户
	 * @param id
	 * @return
	 */
	@GetMapping("/api/v1/user/one/{id}")
	public ApUser findOne(@PathVariable("id") Integer id);
}
③长整型数据精度丢失问题

前端的问题
一旦遇到服务端响应的数据是长整型的,永远会把后两位,或者后三位变为0,所以服务端根本就不能返回长整型给前端
解决方法:
方案一:将文章的id的由long类型手动改为String类型,可以解决此问题。(需要修改表结构)pass掉
方案二:可以使用jackson进行序列化和反序列化解决

在这里插入图片描述

2.3 app端评论-点赞评论

2.3.1 需求分析

在这里插入图片描述

  • 用户点赞,可以增加点赞数量,点赞后不仅仅要增加点赞数,需要记录当前用户对于当前评论的数据记录
  • 用户取消点赞,点赞减一,更新点赞数据
    在这里插入图片描述

2.3.2 思路分析

在这里插入图片描述

2.3.3 接口定义

在这里插入图片描述

2.3.4 接口实现

package com.heima.comment.service.impl;

import com.heima.apis.article.IArticleClient;
import com.heima.apis.user.IUserClient;
import com.heima.comment.service.ApCommentService;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.comment.dtos.CommentDto;
import com.heima.model.comment.dtos.CommentLikeDto;
import com.heima.model.comment.dtos.CommentSaveDto;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.common.ThreadLocalUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
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.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author tp
 * @since 2024/2/19 16:06
 */

@Service
public class ApCommentServiceImpl implements ApCommentService {
	@Autowired
	private IUserClient userClient;

	@Autowired
	private IArticleClient articleClient;

	@Autowired
	private MongoTemplate mongoTemplate;

	@Override
	public ResponseResult save(CommentSaveDto dto) {
		// 1. 判断参数是否为空
		if (dto.getArticleId()==null || StringUtils.isBlank(dto.getContent())){
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}
		// 2. 判断用户是否存在——调用user的feign接口(此feign接口一定要在user服务的webMvcConfig中放行)
		Integer userId = ThreadLocalUtil.getUserId();
		ApUser apUser = userClient.findOne(userId);
		if (apUser == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"APP用户不存在");
		}

		// 3. 判断文章是否存在
		ApArticle apArticle = articleClient.findOne(dto.getArticleId());
		if (apArticle == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"文章不存在");
		}

		// 4. 判断评论内容是否大于140字
		if (dto.getContent().length() > 140) {
			return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"内容长度超过140字");
		}
		// 5. 安全过滤(DFA审核和百度云文本审核)

		// 6. 保存评论到MongoDB中
		ApComment apComment = new ApComment();
		apComment.setUserId(userId);
		apComment.setUserName(apUser.getName());
		apComment.setImage(apUser.getImage());
		apComment.setType(0);	//评论的内容类型,0表示文章
		apComment.setObjectId(dto.getArticleId());
		apComment.setContent(dto.getContent());
		apComment.setLikes(0);
		apComment.setReply(0);
		apComment.setFlag(0);
		apComment.setCreatedTime(new Date());
		apComment.setUpdatedTime(new Date());

		mongoTemplate.save(apComment);
		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
	}

	/**
	 * 加载评论
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult load(CommentDto dto) {

		return null;
	}

	/**
	 * 点赞评论或者取消点赞
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult like(CommentLikeDto dto) {
		// 1. 判断参数是否为空
		if (StringUtils.isBlank(dto.getCommentId()) || dto.getOperation() == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}
		// 2. 判断评论是否存在
		ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
		if (apComment == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"评论不存在");
		}
		// 3. 查询评论对应的点赞记录
		// 根据评论id查询点赞记录
		ApCommentLike apCommentLike = mongoTemplate.findOne(Query.query(Criteria.where("userId").is(ThreadLocalUtil.getUserId()).and("commentId").is(dto.getCommentId())), ApCommentLike.class);
		// 3.1 点赞记录不存在如何处理?
		if (apCommentLike == null) {
			// 就是说还没有点过赞
			// 3.1.1 判断是否取消点赞
			if (dto.getOperation() == 1) {
				return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"点赞记录不存在,无法取消点赞");
			}
			// 3.1.2 更新评论的点赞数+1
			ApComment comment = mongoTemplate.findAndModify(Query.query(Criteria.where("id").is(dto.getCommentId())), new Update().inc("likes", 1).set("updateTime", new Date()), ApComment.class);
			// 3.1.3 保存点赞记录
			apCommentLike = new ApCommentLike();
			apCommentLike.setCommentId(dto.getCommentId());
			apCommentLike.setUserId(ThreadLocalUtil.getUserId());
			apCommentLike.setOperation(dto.getOperation());
			apCommentLike.setCreatedTime(new Date());
			apCommentLike.setUpdatedTime(new Date());
			mongoTemplate.save(apCommentLike);
		} else {
			// 3.2 点赞记录存在如何处理?
			// 3.2.1 判断是否重复点赞
			if (dto.getOperation() == 0 && apCommentLike.getOperation() == 0) {
				return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"不能重复点赞");
			}
			// 3.2.2 判断是否重复取消点赞
			if (dto.getOperation() == 1 && apCommentLike.getOperation() == 1) {
				return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"不能重复取消点赞");
			}
			// 3.2.3 如果操作的是点赞,则点赞数+1
			if (dto.getOperation() == 0) {
				mongoTemplate.findAndModify(Query.query(Criteria.where("id").is(dto.getCommentId())), new Update().inc("likes", 1).set("updateTime", new Date()), ApComment.class);
			} else {
				// 3.2.4 如果操作的是取消点赞,则点赞数-1
				mongoTemplate.findAndModify(Query.query(Criteria.where("id").is(dto.getCommentId())), new Update().inc("likes", -1).set("updateTime", new Date()), ApComment.class);
			}
			// 3.2.5 更新点赞记录的操作类型和时间
			apCommentLike.setOperation(dto.getOperation());
			apCommentLike.setUpdatedTime(new Date());
			mongoTemplate.save(apCommentLike);
		}
		// 4.查询最新点赞数并返回
		apComment = mongoTemplate.findById(dto.getCommentId(),ApComment.class);
		Map result = new HashMap();
		result.put("likes", apComment.getLikes());

		return ResponseResult.okResult(result);
	}
}

2.4 app端评论-评论列表

2.4.1 需求分析

查询评论列表,根据当前文章id进行检索,按照创建时间倒序,分页查询(默认10条数据)
在这里插入图片描述

2.4.2 接口定义

在这里插入图片描述

2.4.3 需求分析

在这里插入图片描述

2.4.4 接口实现

public ResponseResult load(CommentDto dto) {
		int size = 10; // 默认查询数
		// 1. 判断参数是否为空
		if (dto.getArticleId() == null || dto.getMinDate() == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}
		// 2. 根据条件查询评论列表(查询条件:type、objectId、createdTime 查询结果:createdTime倒序、限制查询10条)
		Query query = Query.query(Criteria
				.where("type").is(0)
				.and("objectId").is(dto.getArticleId())
				.and("createdTime").lt(dto.getMinDate()))
				.with(Sort.by(Sort.Direction.DESC, "createdTime"))
				.limit(size);
		List<ApComment> apCommentList = mongoTemplate.find(query, ApComment.class);
		// 3. 如果当前用户是游客,直接响应评论列表数据
		Integer userId = ThreadLocalUtil.getUserId();
		if (userId == 0) {
			return ResponseResult.okResult(apCommentList);
		}
		// 4. 如果当前用户是正常用户,需要标识评论列表中被当前用户点赞过的评论,再响应
		// 4.1 获取评论列表对应的评论ID列表
		List<String> commentIdList = apCommentList.stream().map(ApComment::getId).collect(Collectors.toList());
		// 4.2 查询当前用户针对当前评论列表对应的所有点赞记录(查询条件:userId,operation,commentId)
		Query queryCommentLike = query = Query.query(Criteria.where("userId").is(userId).and("operation").is(0).and("commentId").in(commentIdList));
		// 点赞记录列表
		List<ApCommentLike> apCommentLikes = mongoTemplate.find(queryCommentLike, ApCommentLike.class);

		// 4.3 在评论列表中找到被点赞过的评论并添加标识表示点赞过
		List<CommentVo> commentVoList = new ArrayList<>();
		for (ApComment apComment : apCommentList) {
			long count = apCommentLikes.stream().filter(x -> x.getCommentId().equals(apComment.getId())).count();
			CommentVo commentVo = new CommentVo();
			BeanUtils.copyProperties(apComment,commentVo);
			if (count > 0) {
				commentVo.setOperation(0);
			}
			commentVoList.add(commentVo);
		}
		return ResponseResult.okResult(commentVoList);
	}

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

2.6 热点评论

2.6.1 需求分析

  • 一个文章最多有5条热点评论
  • 热点评论需要按照点赞数倒序排序
  • 前5条评论是按照点赞数倒序,其他按照时间倒序查询

实现思路-计算热点评论

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1466246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

选择排序的简单介绍

选择排序是一种简单直观的排序算法&#xff0c;其原理如下&#xff1a; 1. 遍历数组&#xff0c;找到最小&#xff08;或最大&#xff09;的元素&#xff0c;并将其与数组的第一个元素交换位置。 2. 接着在剩下的元素中找到最小&#xff08;或最大&#xff09;的元素&#xff…

Mysql深入学习 基础篇 Ss.01 相关概念及初识SQL语法

事情永远不会变得容易&#xff0c;但我会变得更好 ——24.2.20 一、数据库相关概念 1.数据库 存储数据的仓库&#xff0c;数据是有组织的进行存储 DB 2.数据库管理系统 操纵和管理数据库的大型软件 DBMS 3.SQL 操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据…

三、MQTT的基本原理

1、概述 在MQTT协议通讯中&#xff0c;有两个最为重要的角色。它们分别是服务端和客户端&#xff0c;客户端之间通过发布和订阅通信。 1.1、形象的理解MQTT MQTT通信模型示意图如下&#xff1a; 使用电视台、记者、观众三个角色来类比更容易理解&#xff1a; 电视台&#xf…

图文说明Linux云服务器如何更改实例镜像

一、应用场景举例 在学习Linux的vim时&#xff0c;我们难免要对vim进行一些配置&#xff0c;这里我们提供一个vim插件的安装包&#xff1a; curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o./install.sh && bash ./install.sh 但是此安装包…

Jmeter基础(1) Mac下载安装启动

目录 Jmeter下载安装启动下载启动 Jmeter下载安装启动 注意⚠️&#xff1a;使用jmeter需要有java环境 下载 官网下载地址&#xff1a;https://jmeter.apache.org/ 会看到这里有两个版本&#xff0c;那么有什么区别么&#xff1f; Binaries是可执行版&#xff0c;直接下载解…

Gemma模型论文详解(附源码)

原文链接&#xff1a;Gemma模型论文详解&#xff08;附源码&#xff09; 1. 背景介绍 Gemma模型是在2023.2.21号Google新发布的大语言模型, Gemma复用了Gemini相同的技术(Gemini也是Google发布的多模态模型)&#xff0c;Gemma这次发布了了2B和7B两个版本的参数&#xff0c;不…

文件上传漏洞--Upload-labs--Pass10--双写绕过

一、什么是双写绕过 顾名思义&#xff0c;双写绕过就是双写文件后缀名来进行绕过&#xff0c;如&#xff1a;test.php 双写后为 test.pphphp。通常情况下双写绕过用于绕过源代码中的 str_ireplace()函数。 二、双写绕过原理 1、首先进行代码审计&#xff0c;源代码中有黑名单…

linux---防火墙拓展

目录 一、iptables 1.基本语法 2.四表五链——重点记忆 2.1四表 2.2五链 2.3总结 3.iptables选项示例 3.1 -Z 清空流量计数 3.2 -P 修改默认规则 3.3 -D 删除规则 3.4 -R 指定编号替换规则 4.白名单 5.通用匹配 6.示例 6.1添加回环网卡 6.2可以访问端口 6.3 主…

ERROR: No matching distribution found for json

问题描述 安装 json库 的时候&#xff0c;一直报错&#xff1a; 解决方案&#xff1a; 大多数博文分享是&#xff1a;①网络问题&#xff0c;换国内镜像&#xff1b;②更新pip. 少有人提及在Python 3.10.1中&#xff0c;它叫 simplejson 了 pip install simplejson 参考&am…

力扣日记2.21-【回溯算法篇】46. 全排列

力扣日记&#xff1a;【回溯算法篇】46. 全排列 日期&#xff1a;2023.2.21 参考&#xff1a;代码随想录、力扣 46. 全排列 题目描述 难度&#xff1a;中等 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&…

分布式应用:kylin 部署 zabbix 监控平台

目录 一、实验 1.环境 2. kylin 修改mysql数据库 3. kylin 部署 zabbix 监控平台 4. kylin 修改 zabbix 配置 5. kylin 修改zabbix web 二、问题 1. zabbix_server 查看版本报错 2.zabbix_server 文件如何去掉注释"#"和空行 3. zabbix图表显示异常 4.zabbi…

Docker基础篇(三) 容器数据卷(二) dockerfile

新建dockerfile文件 zenDockerfile from centos volume [“/containVolum-01”, “/containVolum-02”] CMD echo “zen”

YOLO v9 出世!

当今的深度学习方法专注于如何设计最合适的目标函数&#xff0c;以使模型的预测结果能够尽可能地接近真实值。同时&#xff0c;还需要设计一种适当的架构&#xff0c;以便为预测获取足够的信息。现有方法忽略了一个事实&#xff0c;即当输入数据经过逐层特征提取和空间转换时&a…

Java基于SpringBoot+Vue的体育用品库存管理系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

什么品牌的洗地机好用?入门级智能洗地机

对于隔三差五就需要做全屋清洁的家庭&#xff0c;使用传统拖布洗地真的很吃不消&#xff0c;随着科技的不断进步&#xff0c;洗地机成为现代家庭清洁的必备工具之一。洗地机&#xff0c;用最贴合实际省事、省钱的方式去完成家务劳动&#xff0c;可以大大减少体力消耗&#xff0…

信号信号槽

三、信号槽 概念 信号和槽是两种函数&#xff0c;这是Qt在C基础上新增的特性&#xff0c;类似于其他技术中的回调的概念。 信号槽通过程序员提前设定的“约定”&#xff0c;可以实现对象之间的通信&#xff0c;有两个先决条件。 通信的对象都是在QOBject类中派生出来的。 QOBje…

Linux环境非root用户配置SSH免密登录,并解决登录仍提示输入密码

Linux环境非root用户配置SSH免密登录&#xff0c;并解决登录仍提示输入密码 ssh免密登录的简单理解 以A和B进行举例&#xff1a;A免密登录B &#xff08;即在A服务器输入命令&#xff1a;ssh 非root用户名B的IP地址&#xff09;可以直接免密码直接登录 A生成私钥和公钥&#…

​​​​​​​Sora:OpenAI的革命性AI视频模型与其对未来影像创作的影响

随着深度学习技术和计算能力的进步&#xff0c;人工智能不仅在图像识别、自然语言处理等领域取得了卓越成就&#xff0c;同时也在不断突破视频处理和生成的边界。在这一背景下&#xff0c;OpenAI推出了Sora——一种新型的AI视频模型&#xff0c;标志着AI在视频内容创作领域的又…

云呐智能维运技术有哪些?智能运维活动有哪些

智能运维&#xff08;AIOps&#xff09;技术是指利用人工智能、机器学习、大数据分析等先进技术手段&#xff0c;来提高IT运维效率和质量的一系列技术和工具。目前常见的智能运维技术核心功能和应用场景。一些具体的智能运维活动案例&#xff0c;包括但不限于故障预测、自动化修…

[hgame 2024 week3] crypto/pwn

第2周作完了不知道扔哪去了&#xff0c;先记录下第3周&#xff0c;因为官方WP已经出来&#xff0c;顺便把没出的题复现一下。最近的比赛都比较不错&#xff0c;相当于近期知识点的总结&#xff0c;有点心经的意思。 Crypto matrix_equation 题目很短&#xff0c;结了一个式子…