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
1.2.3 可视化工具
studio3t 是 mongodb 优秀的客户端工具。官方地址在 https://studio3t.com/
下载 studio3t
同学不用下载,可以使用资料文件夹中提供好的软件安装即可。
安装并启动
创建连接
注意:以上的链接的 ip 地址以及端口以自己实际的服务器的 ip 地址和端口为准
连接成功:
2 app 端评论 - 发表评论
2.1 需求分析
- 文章详情页下方可以查看评论信息,按照点赞数量倒序排列,展示评论内容、评论的作者、点数数、回复数、时间,默认查看 10 条评论,如果想查看更多,可以点击加载更多进行分页
- 可以针对当前文章发布评论
- 可以针对于某一条评论进行点赞操作
2.2 思路分析
(1)需要将数据存储到 mongodb 中,所以先创建两个 pojo ,他们之间关系如下
思路分析
根据文章 id 发表评论,输入内容发表评论,评论内容不能超过 140 字,评论内容需要做文本垃圾检测(暂时不做),将数据存储到 mongodb 中。
需要搭建一个评论微服务,实现相关的功能。
2.3 搭建评论微服务
(1)创建项目 itheima-leadnews-service-comment
(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"><<span class="hljs-name">artifactId</span>></span>itheima-leadnews-service-comment<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">dependencies</span>></span>
<span class="hljs-tag"><<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.itheima<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>itheima-leadnews-comment-api<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">version</span>></span>1.0-SNAPSHOT<span class="hljs-tag"></<span class="hljs-name">version</span>></span>
<span class="hljs-tag"><<span class="hljs-name">exclusions</span>></span>
<span class="hljs-tag"><<span class="hljs-name">exclusion</span>></span>
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.baomidou<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>mybatis-plus-boot-starter<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"></<span class="hljs-name">exclusion</span>></span>
<span class="hljs-tag"></<span class="hljs-name">exclusions</span>></span>
<span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.itheima<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>itheima-leadnews-common<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">version</span>></span>1.0-SNAPSHOT<span class="hljs-tag"></<span class="hljs-name">version</span>></span>
<span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.springframework.boot<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>spring-boot-starter-data-mongodb<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"></<span class="hljs-name">dependencies</span>></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
数据库其实可以暂时不用。我们先放到这。链接上去。
(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(已经配置好了)
(6) 创建 POJO 映射到 mongdb 中:
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<Comment> <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);
}
}
}
2.4 功能实现
2.4.1 需求分析
实现发表评论 APP端 点击按钮 --》输入文字 点击提交即可
后台接收之后,进行保存到mongodb即可
发表评论:CommentSaveDto
@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
// 保存文章评论 注意该评论保存到 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 网关进行配置
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 需求分析
用户点赞,可以增加点赞数量,点赞后不仅仅要增加点赞数,需要记录当前用户对于当前评论的数据记录
点赞评论 就添加一条数据 ,如果取消点赞 就删除一条数据即可
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;
}
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<CommentLike> commentLikes = mongoTemplate.find(query1, CommentLike.class);
<span class="hljs-keyword">if</span> (commentLikes != <span class="hljs-literal">null</span> && commentLikes.size() > <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 需求分析
查询评论列表,根据当前文章 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;
}
4.2.2 controller
// 展示评论的列表 返回值 参数
<span class="hljs-meta">@PostMapping("/loadPage")</span>
<span class="hljs-keyword">public</span> Result<List<CommentVo>> <span class="hljs-title function_">loadPage</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> CommentDto commentDto)</span> {
List<CommentVo> 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 < 你传递过来的时间 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<Comment> comments = mongoTemplate.find(query, Comment.class);
List<CommentVo> 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<String> ids = comments.stream().map(p -> 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 (?) ?从上面的评论列表中来 查询出来的值(一定是点赞过的) 永远 <=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<CommentLike> 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 需求分析
-
当用户点击了评论中的回复就可以查看所有评论回复内容
-
可以针对当前评论进行回复,需要更新评论的回复数量
-
可以对当前评论回复列表进行点赞操作,同时记录当前回复评论点赞信息
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;*/
}
(2)思路分析:
1,用户点击回复,根据当前评论 id 查询对应的所有回复进行展示
2,用户针对于当前的评论进行了回复,需要保存数据,同时需要更新当前评论的回复数
3,可以对回复列表进行点赞操作
5.3 功能实现
(1)dto 创建
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<ReplyLike> replyLikes = mongoTemplate.find(query1, ReplyLike.class);
<span class="hljs-keyword">if</span> (replyLikes != <span class="hljs-literal">null</span> && replyLikes.size() > <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<Reply> replies = mongoTemplate.find(query, Reply.class);
List<ReplyVo> 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<String> ids = replies.stream().map(p -> 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的值 查询到的一定是点赞了的 而且<=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<ReplyLike> 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> {
}