微服务项目 -- day03 文档型数据库 MongoDB、吐槽微服务、文章评论功能

一、MongoDB简介


1、什么是MongoDB


        MongoDB 是一个跨平台的,面向文档的数据库,是当前 NoSQL 数据库产品中最热门的一种。它介于关系数据库和非关系数据库之间,是非关系数据库当中功能最丰富,最像关系数据库的产品。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。


2、MongoDB特点


        MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。具体特点总结如下:


(1)、面向集合存储,易于存储对象类型的数据


(2)、模式自由


(3)、支持动态查询


(4)、支持完全索引,包含内部对象


(5)、支持复制和故障恢复


(6)、使用高效的二进制数据存储,包括大型对象(如视频等)


(7)、自动处理碎片,以支持云计算层次的扩展性


(8)、支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl 及 C++语言的驱动程序,社区中也提供了对 Erlang 及.NET 等平台的驱动程序


(9)、 文件存储格式为 BSON(一种 JSON 的扩展)


3、MongoDB的体系结构


        MongoDB 的逻辑结构是一种层次结构。主要由:文档(document)集合(collection)数据库(database) 这三部分组成的。逻辑结构是面向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。


        (1)MongoDB 的文档(document),相当于关系数据库中的一行记录。


        (2)多个文档组成一个集合(collection),相当于关系数据库的表。


        (3)多个集合(collection),逻辑上组织在一起,就是数据库(database)。


        (4)一个 MongoDB 实例支持多个数据库(database)。


文档(document)、集合(collection)、数据库(database)的层次结构如下图:




MongoDB与MySQL数据库逻辑结构概念对比如下:




4、MongoDB的数据类型


null:用于表示空值或者不存在的字段,{“x”:null}


布尔型:布尔类型有两个值true和false,{“x”:true}


数值:shell默认使用64为浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用NumberInt(4字节符号整数)或NumberLong(8字节符号整数),{“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}


字符串:UTF-8字符串都可以表示为字符串类型的数据,{“x”:“呵呵”}


日期:日期被存储为自新纪元依赖经过的毫秒数,不存储时区,{“x”:new Date()}


正则表达式:查询时,使用正则表达式作为限定条件,语法与JavaScript的正则表达式相同,{“x”:/[abc]/}


数组:数据列表或数据集可以表示为数组,{“x”: [“a“,“b”,”c”]}


内嵌文档:文档可以嵌套其他文档,被嵌套的文档作为值来处理,{“x”:{“y”:3 }}


对象Id:对象id是一个12字节的字符串,是文档的唯一标识,{“x”: objectId() }


二进制数据:二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要将非utf-字符保存到数据库中,二进制数据是唯一的方式。


代码:查询和文档中可以包括任何JavaScript代码,{“x”:function(){/…/}}


二、MongoDB的安装与使用


1、Windows下MongoDB的安装及配置


MongoDB下载路径:https://download.csdn.net/download/wingzhezhe/10534774


(1)、配置环境变量




(2)、启动MongoDB服务


注意:启动之前需要创建数据目录




(3)、连接MongoDB




2、Docker中安装MongoDB


(1)、拉取镜像


docker pull mongo


(2)、启动守护式容器


docker run -di --name=tensquare_mongo -p 27017:27017 mongo




(3)、远程连接MongoDB数据库




3、MongoDB常用命令


(1)、选择和创建数据库


语法: use 数据库名称


说明:如果数据库不存在,会默认创建数据库




(2)、插入与查询文档


插入文档的语法


db.集合名称.insert(数据);


查询集合的语法


-- 查询所有
db.集合名称.find()

-- 带条件查询
db.集合名称.find({字段名:条件值})

-- 查询符合条件的第一条数据
db.集合名称.findOne({字段名:条件值})

-- 指定返回结果的数量
db.集合名称.find().limit(3)




注意:每条文档会有一个叫_id的字段,这个相当于我们原来关系数据库中表的主键,当你在插入文档记录时没有指定该字段,MongoDB会自动创建,其类型是ObjectID类型。如果我们在插入文档记录时指定该字段也可以,其类型可以是ObjectID类型,也可以是MongoDB支持的任意类型。


(3)、修改与删除文档


修改文档的语法


-- 修改文档,此种方式修改后,没有修改的字段都会删除
db.集合名称.update({条件字段:条件值}, {要修改的字段:修改后的数据值})

-- 使用 $set 修改器来修改,保证只修改要指定的字段,其它字段保持原值
db.集合名称.update({条件字段:条件值}, {$set:{要修改的字段:修改后的数据值}})

删除文档的语法


-- 删除指定文档
db.集合名称.remove({条件字段:条件值})

-- 删除所有文档
db.集合名称.remove({})




(4)、统计条数


统计条数语法


db.spit.count()




(5)、模糊查询


MongoDB中的模糊查询是通过正则表达式来实现的,格式为:


-- 模糊查询,条件是正则表达式
db.spit.find({条件字段:/内容/})




(6)、大于 小于 不等于


-- 大于: field > value
db.集合名称.find({ "field" : { $gt: value }}) 

-- 小于: field < value
db.集合名称.find({ "field" : { $lt: value }}) 

-- 大于等于: field >= value
db.集合名称.find({ "field" : { $gte: value }}) 

-- 小于等于: field <= value
db.集合名称.find({ "field" : { $lte: value }})

-- 不等于: field != value
db.集合名称.find({ "field" : { $ne: value }}) 


(7)、包含于不包含


包含使用$in操作符,不包含使用$nin操作符。




(8)、条件连接


需要查询同时满足两个以上条件,需要使用$and操作符将条件进行关联。(相当于SQL的and),如果两个以上条件之间是或者的关系,我们使用 $or 操作符进行关联,与前面 and的使用方式相同,条件连接的格式如下


-- 并列关系
$and:[条件1, 条件2]

-- 与关系
$or:[条件1, 条件2]




(9)、列值增长


实现对某列值在原有值的基础上进行增加或减少,可以使用 $inc 运算符来实现:


db.spit.update({_id:"2"},{$inc:{visits:NumberInt(1)}} )


三、Java操作MongoDB


1、创建maven project,引入MongoDB驱动jar包坐标


<dependencies>
        <!-- 引入MongoDB驱动依赖 -->
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver</artifactId>
            <version>3.6.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>


2、创建测试类


package com.mongodb.test;

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

public class MongoDBTest {

    /**
     * 查询所有
     */
    @Test
    public void testFindAll() {
        //创建连接对象
        MongoClient client = new MongoClient("192.168.37.133");
        //打开数据库
        MongoDatabase spitdb = client.getDatabase("spitdb");
        //获取集合
        MongoCollection<Document> collection = spitdb.getCollection("spit");
        //获取文档集合
        FindIterable<Document> documents = collection.find();
        //遍历文档集合,获取内容
        for (Document doc : documents) {
            System.out.println("吐槽内容" + doc.getString("content"));
            System.out.println("用户id" + doc.getString("userid"));
            System.out.println("用户昵称" + doc.getString("nickname"));
            System.out.println("浏览量" + doc.getInteger("visits"));
            System.out.println("-----------------------------------------------");
        }
        //释放连接
        client.close();
    }

    /**
     * 带条件查询
     */
    @Test
    public void testFindBySpec() {
        //创建连接对象
        MongoClient client = new MongoClient("192.168.37.133");
        //打开数据库
        MongoDatabase spitdb = client.getDatabase("spitdb");
        //获取集合
        MongoCollection<Document> collection = spitdb.getCollection("spit");
        //封装查询条件
        BasicDBObject bson = new BasicDBObject("visits", new BasicDBObject("$gte", 903));
        //获取文档集合
        FindIterable<Document> documents = collection.find(bson);
        //遍历文档集合,获取内容
        for (Document doc : documents) {
            System.out.println("吐槽内容" + doc.getString("content"));
            System.out.println("用户id" + doc.getString("userid"));
            System.out.println("用户昵称" + doc.getString("nickname"));
            System.out.println("浏览量" + doc.getInteger("visits"));
            System.out.println("-----------------------------------------------");
        }
        //释放连接
        client.close();
    }

    /**
     * 插入一条记录
     */
    @Test
    public void testInsert(){
        //创建连接对象
        MongoClient client = new MongoClient("192.168.37.133");
        //打开数据库
        MongoDatabase spitdb = client.getDatabase("spitdb");
        //获取集合
        MongoCollection<Document> collection = spitdb.getCollection("spit");

        //封装文档对象
        Map map = new HashMap();
        map.put("content", "我要吐槽");
        map.put("userid", "1044");
        map.put("nickname", "李子明");
        map.put("visits", 1580);

        Document doc = new Document(map);

        //插入数据
        collection.insertOne(doc);
        //释放连接
        client.close();
    }
}


3、spirngboot操作MongoDB的jar包


SpringDataMongoDB是spirngdata家族成员之一,用于操作MongoDb的持久层框架,封装了底层的mongodb-driver。


四、吐槽微服务功能


1、搭建吐槽微服务环境




(1)、创建Maven Module




(2)、pom.xml加入jar包坐标


    <dependencies>
        <!-- 加入MongoDB依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <!-- 加入common基础功能依赖 -->
        <dependency>
            <groupId>com.scf</groupId>
            <artifactId>scf_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- 加入springdataRedis坐标 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>


(3)、加入配置文件和启动类


application.yml


server:
  port: 9006
spring:
  application:
    name: scf-spit
  data:
    mongodb:
      host: 192.168.37.133
      database: spitdb
    redis:
      host: 192.168.37.133
      port: 6379


SpitApplication.java


package com.scf.spit;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import util.IdWorker;

@SpringBootApplication
public class SpitApplication {

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

    }

    @Bean
    public IdWorker idWorker() {
        return new IdWorker(1, 1);
    }
}


(4)、编写吐槽实体类和数据访问层架构


Spit.java


package com.scf.spit.pojo;

import java.util.Date;

/**
 * 吐槽实体类
 */
public class Spit {
    private String _id;//主键
    private String content;//吐槽内容
    private Date publishtime;//发布日期
    private String userid;//发布人ID
    private String nickname;//昵称
    private Integer visits;//浏览量
    private Integer thumbup;//点赞数
    private Integer share;//分享数
    private Integer comment;//回复数
    private String state;//状态
    private String parentid;//上级ID

    public Spit() {
    }


SpitDao.java


package com.scf.spit.dao;

import com.scf.spit.pojo.Spit;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 * 吐槽功能的数据访问层接口
 */
public interface SpitDao extends MongoRepository<Spit, String> {
}


2、吐槽微服务基础CRUD功能实现


SpitService.java


package com.scf.spit.service;

import com.scf.spit.dao.SpitDao;
import com.scf.spit.pojo.Spit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import util.IdWorker;

import java.util.List;

/**
 * 吐槽服务的业务路基层
 */
@Service
public class SpitService {

    @Autowired
    private SpitDao spitDao;

    @Autowired
    private IdWorker idWorker;

    /***
     * 查询全部数据
     * @return
     */
    public List<Spit> findAll(){
        return spitDao.findAll();
    }

    /**
     * 根据ID查询数据
     * @param id
     * @return
     */
    public Spit findById(String id){
        return spitDao.findById(id).get();
    }

    /**
     * 增加吐槽
     * @param spit
     */
    public void add(Spit spit){
        spit.set_id(idWorker.nextId()+"");
        spitDao.save(spit);
    }

    /**
     * 修改吐槽
     * @param spit
     */
    public void update(Spit spit){
        spitDao.save(spit);
    }

    /**
     *  删除吐槽
     * @param id
     */
    public void deleteById(String id){
        spitDao.deleteById(id);
    }
}


SpitController.java


package com.scf.spit.controller;

import com.scf.spit.pojo.Spit;
import com.scf.spit.service.SpitService;
import entity.Result;
import entity.StatusCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@CrossOrigin //跨域注解
@RequestMapping("/spit")
public class SpitController {

    @Autowired
    private SpitService spitService;

    /**
     * 查询全部记录
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public Result findAll(){
        List<Spit> list = spitService.findAll();
        return new Result(true, StatusCode.OK,"查询成功",list);
    }

    /**
     *  根据ID查询吐槽
     * @param id
     * @return
     */
    @RequestMapping( value="/{id}" ,method = RequestMethod.GET)
    public Result findById(@PathVariable String id){
        Spit spit = spitService.findById(id);
        return new Result(true, StatusCode.OK,"查询成功",spit);
    }

    /**
     * 增加吐槽
     * @param spit
     * @return
     */
    @RequestMapping( method = RequestMethod.POST)
    public  Result add( @RequestBody Spit spit ){
        spitService.add(spit);
        return new Result(true,StatusCode.OK,"增加成功");
    }

    /**
     * 修改吐槽
     * @param spit
     * @param id
     * @return
     */
    @RequestMapping( value ="/{id}" ,method = RequestMethod.PUT)
    public  Result update( @RequestBody Spit spit ,@PathVariable String id){
        spit.set_id(id);
        spitService.update(spit);
        return new Result(true,StatusCode.OK,"修改成功");
    }

    /**
     *  删除吐槽
     * @param id
     * @return
     */
    @RequestMapping( value ="/{id}" ,method = RequestMethod.DELETE)
    public  Result deleteById(@PathVariable  String id){
        spitService.deleteById(id);
        return new Result(true,StatusCode.OK,"删除成功");
    }
}


3、根据父类id查询吐槽列表,吐槽点赞,发布吐槽功能的实现


SpitDao.java


    /**
     * 根据上级id查询吐槽列表
     * @param parentid
     * @param pageable
     * @return
     */
    public Page<Spit> findByParentid(String parentid, Pageable pageable);


SpitService.java


    /**
     * 根据上级ID查询吐槽列表
     *
     * @param parentId
     * @param page
     * @param size
     * @return
     */
    public Page<Spit> findByParentid(String parentId, int page, int size) {
        PageRequest pageRequest = PageRequest.of(page - 1, size);
        return spitDao.findByParentid(parentId, pageRequest);
    }

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 吐槽点赞功能
     *
     * @param id
     */
    public void updateThumbup(String id) {
        //创建查询对象
        Query query = new Query();
        //封装查询条件
        query.addCriteria(Criteria.where("_id").is(id));
        //创建修改对象
        Update update = new Update();
        //设置修改内容
        update.inc("thumbup", 1);
        //执行修改操作
        mongoTemplate.updateFirst(query, update, "spit");
    }

    /**
     * 发布吐槽
     *
     * @param spit
     */
    public void add(Spit spit) {
        spit.set_id(idWorker.nextId() + "");
        spit.setPublishtime(new Date());
        spit.setVisits(0);  //浏览量
        spit.setShare(0);   //分享数
        spit.setThumbup(0); //点赞数
        spit.setComment(0); //回复数
        spit.setState("1"); //状态
        if(spit.getParentid() != null && !"".equals(spit.getParentid())){
            //如果存在上级,设置上级回复数 +1
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(spit.getParentid()));
            Update update = new Update();
            update.inc("comment", 1);
            mongoTemplate.updateFirst(query, update, "spit");
        }
        spitDao.save(spit);
    }


SpitController.java


    /**
     * 根据上级ID查询吐槽列表
     * @param parentId
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "/comment/{parentId}/{page}/{size}", method = RequestMethod.GET)
    public Result findByParentId(@PathVariable String parentId, @PathVariable int page, @PathVariable int size) {
        Page<Spit> pageList = spitService.findByParentid(parentId, page, size);
        PageResult<Spit> pageResult = new PageResult<>(pageList.getTotalElements(), pageList.getContent());
        return new Result(true, StatusCode.OK, "查询成功", pageResult);
    }

    /**
     * 吐槽点赞
     * @param id
     * @return
     */
    @RequestMapping(value = "/thumbup/{id}", method = RequestMethod.PUT)
    public Result updateThumbup(@PathVariable String id){
        spitService.updateThumbup(id);
        return new Result(true, StatusCode.OK, "点赞成功");
    }


五、文章评论功能


1、表结构分析




2、新增评论功能


(1)、scf_article项目中的pom.xml中加入MongoDB依赖


        <!-- 加入MongoDB依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>


(2)、application.yml中加入MongoDB配置




(3)、创建评论实体类


package com.scf.article.pojo;

import javax.persistence.Id;
import java.util.Date;

public class Comment {
    @Id
    private String id;
    private String articleid;
    private String content;
    private String userid;
    private String parentid;
    private Date publishdate;
    
    getter/setter
}


(4)、数据访问层接口


package com.scf.article.dao;

import com.scf.article.pojo.Comment;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 * 评论的数据访问层接口
 */
public interface CommentDao extends MongoRepository<Comment, String> {
}


(5)、业务逻辑层代码


package com.scf.article.service;

import com.scf.article.dao.CommentDao;
import com.scf.article.pojo.Comment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import util.IdWorker;

@Service
public class CommentService {

    @Autowired
    private CommentDao commentDao;

    @Autowired
    private IdWorker idWorker;

    /**
     * 新增评论
     * @param comment
     */
    public void add(Comment comment){
        comment.setId(idWorker.nextId() + "");
        commentDao.save(comment);
    }
}


(6)、web层代码


package com.scf.article.controller;

import com.scf.article.pojo.Comment;
import com.scf.article.service.CommentService;
import entity.Result;
import entity.StatusCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@CrossOrigin
@RequestMapping(value = "/comment")
public class CommentController {

    @Autowired
    private CommentService commentService;

    @RequestMapping(method = RequestMethod.POST)
    public Result save(@RequestBody Comment comment){
        commentService.add(comment);
        return new Result(true, StatusCode.OK, "提交成功");
    }
}


3、根据文章ID查询评论列表


CommentDao.java


    /**
     * 根据文章ID查询品论列表
     * @param atticleid
     * @return
     */
    public List<Comment> findByArticleid(String atticleid);


CommentService.java


    /**
     * 根据文章ID获取评论列表
     * @param articleid
     * @return
     */
    public List<Comment> findByArticleId(String articleid){
        return commentDao.findByArticleid(articleid);
    }


CommentController.java


    /**
     * 根据文章ID获取评论列表
     * @param articleid
     * @return
     */
    @RequestMapping(value = "/article/{articleid}", method = RequestMethod.GET)
    public Result findByArticleId(@PathVariable String articleid){
        List<Comment> commentList = commentService.findByArticleId(articleid);
        return new Result(true, StatusCode.OK, "查询成功", commentList);
    }

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值