springboot整合mongoDB

需求分析

某头条的文章评论业务如下:
需要实现以下功能:
  1. 1)基本增删改查API
  2. 2)根据文章id查询评论
  3. 3)评论点赞

表结构分析

数据库: articledb
专栏文章评论
comment
字段名称
字段含义
字段类型
备注
_id
ID
ObjectId String
Mongo 的主键的字段
articleid
文章 ID
String
content
评论内容
String
userid
评论人 ID
String
nickname
评论人昵称
String
createdatetime
评论的日期时间
Date
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 框架。

文章微服务模块搭建

1)搭建项目工程articlepom.xml引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2 )配置 application.yml
spring:
  #数据源配置
  data:
    mongodb:
      # 主机地址
     host: 192.168.2.4
      # 数据库
     database: articledb
     # 默认端口是27017
     port: 27017
     #也可以使用uri连接
     #uri: mongodb://192.168.2.4:27017/articledb
3 )创建启动类
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        System.out.println("启动成功");
    }


}
4 )启动项目,看是否能正常启动,控制台没有错误。

文章评论实体类的编写 

/**
 * 文章评论实体类
 */
//把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。
//@Document(collection="mongodb 对应 collection 名")
// 若未加 @Document ,该 bean save 到 mongo 的 comment collection
// 若添加 @Document ,则 save 到 comment collection
@Document(collection="comment")//可以省略,如果省略,则默认使用类名小写映射集合
//复合索引
// @CompoundIndex( def = "{'userid': 1, 'nickname': -1}")
public class Comment implements Serializable {
    //主键标识,该属性的值会自动对应mongodb的主键字段"_id",如果该属性名就叫“id”,则该注解可以省略,否则必须写
    @Id
    private String id;//主键
//该属性对应mongodb的字段的名字,如果一致,则无需该注解
    @Field("content")

    private String content;//吐槽内容
    private Date publishtime;//发布日期
    //添加了一个单字段的索引
    @Indexed
    private String userid;//发布人ID
    private String nickname;//昵称
    private LocalDateTime createdatetime;//评论的日期时间
    private Integer likenum;//点赞数
    private Integer replynum;//回复数
    private String state;//状态
    private String parentid;//上级ID
    private String articleid;
    //getter and setter.....
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public Date getPublishtime() {
        return publishtime;
    }
    public void setPublishtime(Date publishtime) {
        this.publishtime = publishtime;
    }
    public String getUserid() {
        return userid;
    }
    public void setUserid(String userid) {
        this.userid = userid;
    }
    public String getNickname() {
        return nickname;
    }
    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
    public LocalDateTime getCreatedatetime() {
        return createdatetime;
    }
    public void setCreatedatetime(LocalDateTime createdatetime) {
        this.createdatetime = createdatetime;
    }
    public Integer getLikenum() {
        return likenum;
    }
    public void setLikenum(Integer likenum) {
        this.likenum = likenum;
    }
    public Integer getReplynum() {
        return replynum;
    }
    public void setReplynum(Integer replynum) {
        this.replynum = replynum;
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    public String getParentid() {

        return parentid;
    }
    public void setParentid(String parentid) {
        this.parentid = parentid;
    }
    public String getArticleid() {
        return articleid;
    }
    public void setArticleid(String articleid) {
        this.articleid = articleid;
    }
    @Override
    public String toString() {
        return "Comment{" +
                "id='" + id + '\'' +
                ", content='" + content + '\'' +
                ", publishtime=" + publishtime +
                ", userid='" + userid + '\'' +
                ", nickname='" + nickname + '\'' +
                ", createdatetime=" + createdatetime +
                ", likenum=" + likenum +
                ", replynum=" + replynum +
                ", state='" + state + '\'' +
                ", parentid='" + parentid + '\'' +
                ", articleid='" + articleid + '\'' +
                '}';
    }
}
说明:
索引可以大大提升查询效率,一般在查询字段上添加索引,索引的添加可以通过 Mongo 的命令来添加,也可以在 Java 的实体类中通过注解添
加。
1 )单字段索引注解 @Indexed
org.springframework.data.mongodb.core.index.Indexed.class
声明该字段需要索引,建索引可以大大的提高查询效率。
Mongo 命令参考:
db.comment.createIndex({"userid":1})
2 )复合索引注解 @CompoundIndex
org.springframework.data.mongodb.core.index.CompoundIndex.class
复合索引的声明,建复合索引可以有效地提高多字段的查询效率。
Mongo 命令参考:
db.comment.createIndex({"userid":1,"nickname":-1})

文章评论的基本增删改查

1 )创建数据访问接口 
import com.example.demo.model.Comment;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface CommentRepository extends MongoRepository<Comment,String> {
}
2 )创建业务逻辑类 
//评论的业务层
@Service
public class CommentService {
    //注入dao
    @Autowired
    private CommentRepository commentRepository;
    /**
    * 保存一个评论
    * @param comment
    */
    public void saveComment(Comment comment){
        //如果需要自定义主键,可以在这里指定主键;如果不指定主键,MongoDB会自动生成主键
        //设置一些默认初始值。。。
        //调用dao
        commentRepository.save(comment);
    }
    /**
    * 更新评论
    * @param comment
    */
    public void updateComment(Comment comment){
        //调用dao
        commentRepository.save(comment);
    }
    /**
    * 根据id删除评论
    * @param id
    */
    public void deleteCommentById(String id){
        //调用dao
        commentRepository.deleteById(id);
    }
    /**
    * 查询所有评论
    * @return
    */
    public List<Comment> findCommentList(){
        //调用dao
        return commentRepository.findAll();
    }
    /**
    * 根据id查询评论
    * @param id
    * @return
    */
    public Comment findCommentById(String id){
        //调用dao
        return commentRepository.findById(id).get();
    }
}
3 )新建 Junit 测试类,测试保存和查询所有:

@SpringBootTest
class DemoApplicationTests {

    //注入Service
    @Autowired
    private CommentService commentService;
    /**
     * 保存一个评论
     */
    @Test
    public void testSaveComment(){
        Comment comment=new Comment();
        comment.setArticleid("100000");
        comment.setContent("测试添加的数据");
        comment.setCreatedatetime(LocalDateTime.now());
        comment.setUserid("1003");
        comment.setNickname("凯撒大帝");
        comment.setState("1");
        comment.setLikenum(0);
        comment.setReplynum(0);
        commentService.saveComment(comment);
    }
    /**
     * 查询所有数据
     */
    @Test
    public void testFindAll(){
        List<Comment> list = commentService.findCommentList();
        System.out.println(list);
    }
    /**
     * 测试根据id查询
     */
    @Test
    public void testFindCommentById(){
        Comment comment = commentService.findCommentById("5d6a27b81b8d374798cf0b41");
        System.out.println(comment);
    }
}

根据上级ID查询文章评论的分页列表

1 CommentRepository 新增方法定义
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface CommentRepository extends MongoRepository<Comment,String> {
    //根据父id,查询子评论的分页列表
    Page<Comment> findByParentid(String parentid, Pageable pageable);
}
2 CommentService 新增方法
/**
     * 根据父id查询分页列表
     * @param parentid
     * @param page
     * @param size
     * @return
     */
    public Page<Comment> findCommentListPageByParentid(String parentid, int page , int size){
        return commentRepository.findByParentid(parentid, PageRequest.of(page-1,size));
    }
3 junit 测试用例:
/**
     * 测试根据父id查询子评论的分页列表
     */
    @Test
    public void testFindCommentListPageByParentid(){
        Page<Comment> pageResponse = commentService.findCommentListPageByParentid("3", 1, 2);
        System.out.println("----总记录数:"+pageResponse.getTotalElements());
        System.out.println("----当前页数据:"+pageResponse.getContent());
    }

MongoTemplate实现评论点赞 

我们看一下以下点赞的临时示例代码: CommentService 新增 updateThumbup 方法
/**
     * 点赞-效率低
     * @param id
     */
    public void updateCommentThumbupToIncrementingOld(String id){
        Comment comment = commentRepository.findById(id).get();
        comment.setLikenum(comment.getLikenum()+1);
        commentRepository.save(comment);
    }
以上方法虽然实现起来比较简单,但是执行效率并不高,因为我只需要将点赞数加 1 就可以了,没必要查询出所有字段修改后再更新所有字段。( 蝴蝶效应 )
我们可以使用 MongoTemplate 类来实现对某列的操作。 ( 1 )修改 CommentService
//注入MongoTemplate
    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 点赞数+1
     * @param id
     */
    public void updateCommentLikenum(String id){
        //查询对象
        Query query=Query.query(Criteria.where("_id").is(id));
        //更新对象
        Update update=new Update();
        //局部更新,相当于$set
        // update.set(key,value)
        //递增$inc
        // update.inc("likenum",1);
        update.inc("likenum");
        //参数1:查询对象
        //参数2:更新对象
        //参数3:集合的名字或实体类的类型Comment.class
        mongoTemplate.updateFirst(query,update,"comment");
    }
2 )测试用例:
/**
     * 点赞数+1
     */
    @Test
    public void testUpdateCommentLikenum(){
        //对3号文档的点赞数+1
        commentService.updateCommentLikenum("3");
    }
执行测试用例后,发现点赞数 +1 了:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值