SpringBoot 整合 MongoDB
需求分析
某头条的文章评论业务如下:

文章示例参考:早晨空腹喝水,是对还是错?https://www.toutiao.com/a6721476546088927748/
需要实现以下功能:
- 基本增删改查API
- 根据文章id查询评论
- 评论点赞
表结构分析
数据库:articledb
字段名称 |
字段含义 |
字段类型 |
备注 |
_id |
ID |
ObjectId或String |
Mongo的主键字段 |
articleid |
文章ID |
String |
|
content |
评论内容 |
String |
|
userid |
评论人ID |
String |
|
nickname |
评论人昵称 |
String |
|
createdatetime |
评论的日期时间 |
Data |
|
likenum |
点赞数 |
Int32 |
|
replynum |
回复数 |
Int32 |
|
state |
状态 |
String |
0:不可见;1:可见; |
parentid |
上级ID |
String |
如果为0表示文章的顶级评论 |
技术选型
mongodb-driver
mongodb-driver是mongo官方推出的java连接mongoDB的驱动包,相当于JDBC驱动。我们通过一个入门的案例来了解mongodb-driver的基本使用。
官方驱动说明和下载:http://mongodb.github.io/mongo-java-driver/
官方驱动示例文档:http://mongodb.github.io/mongo-java-driver/3.8/driver/getting-started/quick-start/
SpringDataMongoDB
SpringData家族成员之一,用于操作MongoDB的持久层框架,封装了底层的mongodb-driver。
官网主页: https://projects.spring.io/spring-data-mongodb/
我们十次方项目的吐槽微服务就采用SpringDataMongoDB框架。
文章微服务模块搭建
- 搭建项目工程article,pom.xml引入依赖:
spring-boot-starter-data-mongodb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.1</version> <relativePath/> </parent> <groupId>com.frx01</groupId> <artifactId>article</artifactId> <version>0.0.1-SNAPSHOT</version> <name>article</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
|
- 创建application.yml
1 2 3 4 5 6 7 8 9 10 11 12
| spring: data: mongodb: host: 192.168.72.200 database: articledb port: 27017
|
文章评论实体类的编写
创建实体类Comment
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Data
@Document(collection="comment")
public class Comment implements Serializable { @Id private String id; @Field("content") private String content; private Date publishtime; @Indexed private String userid; private String nickname; private LocalDateTime createdatetime; private Integer likenum; private Integer replynum; private String state; private String parentid; private String articleid; }
|
说明:
索引可以大大提升查询效率,一般在查询字段上添加索引,索引的添加可以通过Mongo的命令来添加,也可以在Java的实体类中通过注解添加。
- 单字段索引注解@Indexed
org.springframework.data.mongodb.core.index.Indexed.class
声明该字段需要索引,建索引可以大大的提高查询效率。
Mongo命令参考:
1
| db.comment.createIndex({"userid":1})
|
- 复合索引注解@CompoundIndex
org.springframework.data.mongodb.core.index.CompoundIndex.class
复合索引的声明,建复合索引可以有效地提高多字段的查询效率。
Mongo命令参考:
1
| db.comment.createIndex({"userid":1,"nickname":-1})
|
文章评论的基本增删改查
- 创建数据访问层接口
CommentRepository
:继承MongoRepository
接口,提供了默认的crud方法。
1 2 3
| public interface CommentRepository extends MongoRepository<Comment,String> { }
|
- 创建业务逻辑类
CommentService
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @Service public class CommentService { @Autowired private CommentRepository commentRepository;
public void saveComment(Comment comment) { commentRepository.save(comment); }
public void updateComment(Comment comment) { commentRepository.save(comment); }
public void deleteCommentById(String id) { commentRepository.deleteById(id); }
public List<Comment> findCommentList() { return commentRepository.findAll(); }
public Comment findCommentById(String id) { return commentRepository.findById(id).get(); } }
|
- 新建Junit测试类,测试保存和查询所有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest public class ArticleApplicationTests { @Autowired private CommentService commentService;
@Test public void testFindCommentById(){ Comment commentById = commentService.findCommentById("1"); System.out.println(commentById); }
@Test public void testSaveComment(){ Comment comment = new Comment(); comment.setArticleid("100000"); comment.setContent("测试添加的数据"); comment.setCreatedatetime(LocalDateTime.now()); comment.setUserid("1006"); comment.setNickname("xustudyxu"); comment.setState("1"); comment.setReplynum(0); comment.setReplynum(0); commentService.saveComment(comment); }
@Test public void testFindCommentList(){ List<Comment> commentList = commentService.findCommentList(); commentList.forEach(System.out::println); } }
|
根据上级ID查询文章评论的分页列表
- CommentRepository新增方法定义:
1 2
| Page<Comment> findByParentid(String parentid, Pageable pageable);
|
注意:
方法的命名是有规范的,需要和实体类名字一致。
- CommentService新增方法
1 2 3 4 5 6 7 8 9 10
|
public Page<Comment> findCommentListByParentid(String parentid, int page,int size){ return commentRepository.findByParentid(parentid, PageRequest.of(page-1, size)); }
|
- junit测试用例:
1 2 3 4 5 6 7 8 9
|
@Test public void testFindCommentListByParentid(){ Page<Comment> pageResponse = commentService.findCommentListByParentid("3", 1, 2); System.out.println("---总记录数---:"+pageResponse.getTotalElements()); System.out.println("---当前页数据---:"+pageResponse.getContent()); }
|
- 测试
使用compass快速插入一条测试数据,数据的内容是对3号评论内容进行评论。

执行测试,结果:
1 2 3
| ---总记录数---:1 ---当前页数据---:[Comment(id=62b86e74258c6f1903c71820, content=:不要让惰性毁了你, publishtime=null, userid=1003, nickname=null, createdatetime=null, likenum=null, replynum=null, state=null, parentid=3, articleid=100000)] Process finished with exit code 0
|
MongoTemplate实现评论点赞
我们看一下以下点赞的临时示例代码: CommentService 新增updateThumbup方法
1 2 3 4 5 6 7 8 9
|
public void updateCommentThumbupToIncrementingOld(String id){ Comment comment = commentRepository.findById(id).get(); comment.setLikenum(comment.getReplynum()+1); commentRepository.save(comment); }
|
以上方法虽然实现起来比较简单,但是执行效率并不高,因为我只需要将点赞数加1就可以了,没必要查询出所有字段修改后再更新所有字段。(蝴蝶效应)
我们可以使用MongoTemplate
类来实现对某列的操作,该类SpringBoot已经自动装配,提供高级查询方法。
- 修改CommentService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Autowired private MongoTemplate mongoTemplate;
public void updataCommentLikenum(String id){ Query query = Query.query(Criteria.where("_id").is(id)); Update update = new Update(); update.inc("likenum"); mongoTemplate.updateFirst(query,update,Comment.class); }
|