9. 学习MongoDB 并完善租房的通讯系统后端
本章目的为MongoDB快速入门, 并完善上一节编写的通讯系统后台, 将DAO层从HashMap迁移到MongoDB中.
思考如下问题:
MongoDB属于关系型还是非关系型数据库
为什么在我们的通讯系统中选择MongoDB作为数据库?
9.1 mongoDB概念简介
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储
解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库
的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。
MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似
关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
9.2 MongoDB实操相关
接下来我们对mongoDB进行一波命令学习.
9.2.1 通过docker安装MongoDB
#拉取镜像
docker pull mongo:4.0.3
#创建容器
docker create --name mongodb -p 27017:27017 -v /data/mongodb:/data/db mongo:4.0.3
#启动容器
docker start mongodb
#进入容器
docker exec -it mongodb /bin/bash
#使用MongoDB客户端进行操作
mongo
> show dbs #查询所有的数据库
admin 0.000GB
config 0.000GB
local 0.000GB
9.2.2 MongoDB基本命令实操
为了更好的理解,下面与SQL中的概念进行对比:
SQL术语 | 概念MongoDB术语/概念 | 解释/说明 |
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接 | MongoDB不支持 |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
通过上表, 我们能看得出来, MongoDB的基本概念基本上还是能和关系型数据库的概念对上的.
不过存储结构视图就差别很大了, 左侧为数据库的表格结构, 右侧为MongDB的bson格式:
9.2.2.1mongoDB数据库以及表的操作
# 查看所有的数据库
> show dbsadmin 0.000GBsconfig 0.000GBlocal 0.000GB
# 通过use关键字切换数据库, 这一点与mysql一致
> use adminswitched to db admin#创建数据库#说明:在MongoDB中,数据库是自动创建的,通过use切换到新数据库中,进行插入数据即可自动创建数据库
> use testdbswitched to db testdb
> show dbs # 并没有创建数据库admin 0.000GBconfig 0.000GBlocal 0.000GB
> db.user.insert({id:1,name:'zhangsan'}) # 插入数据WriteResult({ "nInserted" : 1 })
> show dbsadmin 0.000GBconfig 0.000GBlocal 0.000GBtestdb 0.000GB #数据库自动创建#查看表
> show tablesuser
> show collections # tables 与 collections 是一个东西.user
># 删除集合(表)
> db.user.drop()true # 如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
# 删除数据库
> use testdb # 先切换到要删除的数据中switched to db testdb
> db.dropDatabase() #删除数据库{ "dropped" : "testdb", "ok" : 1 }
> show dbsadmin 0.000GBconfig 0.000GBlocal 0.000GB
9.2.2.2 新增数据
在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。
#插入数据#语法:db.COLLECTION_NAME.insert(document)
> db.user.insert({id:1,username:'zhangsan',age:20})WriteResult({ "nInserted" : 1 })
> db.user.save({id:2,username:'lisi',age:25})WriteResult({ "nInserted" : 1 })
> db.user.find() #查询数据{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan","age" : 20 }{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi","age" : 25 }
9.2.2.3 更新数据
update() 方法用于更新已存在的文档。实例如下:
> db.user.find(){ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan","age" : 20 }{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi","age" : 25 }
> db.user.update({id:1},{$set:{age:22}}) #更新数据WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find(){ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan","age" : 22 }{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi","age" : 25 }#注意:如果这样写,会删除掉其他的字段
> db.user.update({id:1},{age:25})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find(){ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi","age" : 25 }#更新不存在的字段,会新增字段
> db.user.update({id:2},{$set:{sex:1}}) #更新数据
> db.user.find(){ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi","age" : 25, "sex" : 1 }#更新不存在的数据,默认不会新增数据
> db.user.update({id:3},{$set:{sex:1}})WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
> db.user.find(){ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi","age" : 25, "sex" : 1 }#如果设置第一个参数为true,就是新增数据
> db.user.update({id:3},{$set:{sex:1}},true)WriteResult({"nMatched" : 0,"nUpserted" : 1,"nModified" : 0,"_id" : ObjectId("5c08cb281418d073246bc642")})
> db.user.find(){ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi","age" : 25, "sex" : 1 }{ "_id" : ObjectId("5c08cb281418d073246bc642"), "id" : 3, "sex" : 1 }
9.2.2.4 删除数据
> db.user.remove({age:25})WriteResult({ "nRemoved" : 2 }) #删除了2条数据#插入4条测试数据
> db.user.insert({id:1,username:'zhangsan',age:20})
> db.user.insert({id:2,username:'lisi',age:21})
> db.user.insert({id:3,username:'wangwu',age:22})
> db.user.insert({id:4,username:'zhaoliu',age:22})> db.user.remove({age:22},true)WriteResult({ "nRemoved" : 1 }) #删除了1条数据#删除所有数据
> db.user.remove({})#说明:为了简化操作,官方推荐使用deleteOne()与deleteMany()进行删除数据操作。db.user.deleteOne({id:1})db.user.deleteMany({}) #删除所有数据
9.2.2.5 查询数据
#插入测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})# 常见的几种查询方式.
db.user.find() #查询全部数据
db.user.find({},{id:1,username:1}) #只查询id与username字段
db.user.find().count() #查询数据条数
db.user.find({id:1}) #查询id为1的数据
db.user.find({age:{$lte:21}}) #查询小于等于21的数据
db.user.find({age:{$lte:21}, id:{$gte:2}}) #and查询,age小于等于21并且id大于等于2
db.user.find({$or:[{id:1},{id:2}]}) #查询id=1 or id=2
#分页查询:Skip()跳过几条,limit()查询条数
db.user.find().limit(2).skip(1) #跳过1条数据,查询2条数据
db.user.find().sort({id:-1}) #按照age倒序排序,-1为倒序,1为正序
通过上面的操作的练习, 我们可以基本熟悉他的套路, 本质上就是调用一个表对应的某个方法. 扩展一下, 你可以试试下面这个命令
db.user.find
输出结果如下:
不难看出, 通过这个命令调出的就是对应的C++代码.
9.2.3 索引
索引通常能够极大的提高查询的效率, 这个我相信大多数人在关系型数据库中都有很深的印象, mongoDB底层基本概念延续了关系型数据库那一套, 索引也被其延续下来使用了.
#查看当前user表的索引
> db.user.getIndexes()[{"v" : 2,"key" : {"_id" : 1},"name" : "_id_","ns" : "testdb.user"}]
#说明:1表示升序创建索引,-1表示降序创建索引。
#创建索引
> db.user.createIndex({'age':1}){"createdCollectionAutomatically" : false,"numIndexesBefore" : 1,"numIndexesAfter" : 2,"ok" : 1}#删除索引
> db.user.dropIndex("age_1")
#或者,删除除了_id之外的索引
> db.user.dropIndexes()
#创建联合索引
> db.user.createIndex({'age':1, 'id':-1})
#查看索引大小,单位:字节
db.user.totalIndexSize()
9.2.4 UI客户端工具
Robo 3T是MongoDB的客户端工具,我们可以使用它来操作MongoDB, 有需要的可以自行去官网下载.
9.3 Java 通过api操作MongoDB
新建一个itcast-mongodb项目
9.3.1 搭建项目
引入依赖
<?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"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>itcast-mongodb</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.0.RELEASE</version></parent><dependencies><dependency><groupId>org.mongodb</groupId><artifactId>mongodb-driver-sync</artifactId><version>3.9.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.4</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><!-- java编译插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.2</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build>
</project>
完成构建后的项目结构如图所示:
9.3.2 使用demo测试连接MongoDB
package cn.itcast.mongodb;import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;import java.util.function.Consumer;
/*** 和连接mysql的demo如出一辙*/
public class MongoDBDemo {public static void main(String[] args) {// 建立连接MongoClient mongoClient = MongoClients.create("mongodb://127.0.0.1:27017");// 连接数据库MongoDatabase mongoDatabase = mongoClient.getDatabase("testdb");// 选择表MongoCollection<Document> userCollection = mongoDatabase.getCollection("user");// 查询十条数据userCollection.find().limit(10).forEach((Consumer<? super Document>) document -> {System.out.println(document.toJson());});// 关闭连接mongoClient.close();}
}
9.3.2 使用Junit测试MongoDB的常见操作
新建一个类, 测试增删改查
package cn.itcast.mongodb;import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.Sorts;
import com.mongodb.client.result.DeleteResult;
import org.bson.Document;
import org.junit.Before;
import org.junit.Test;import java.util.function.Consumer;import static com.mongodb.client.model.Filters.*;public class TestCRUD {// mongoDB的表对象, 我们对数据的操作都是通过调用表对象的方法来实现. 这一点与我们输入mongoDB的命令如出一辙private MongoCollection<Document> mongoCollection;@Beforepublic void init() {// 建立连接MongoClient mongoClient = MongoClients.create("mongodb://127.0.0.1:27017");// 连接数据库MongoDatabase mongoDatabase = mongoClient.getDatabase("testdb");// 选择表, 并缓存表对象mongoCollection = mongoDatabase.getCollection("user");}@Testpublic void testQuery() {// 调用表对象的查询方法与排序this.mongoCollection.find( and(lte("age", 50),gt("id", 100))).sort(Sorts.descending("id")).projection(// 这一步相当于我们的 select id, age (不包含_id) from ...Projections.fields(Projections.include("id", "age"),// 不查询 '_id' ,即不查询mongoDB生成的随机 _idProjections.excludeId())).forEach(new Consumer<Document>() {@Overridepublic void accept(Document document) {// 对于遍历出来的结果, 打印即可System.out.println(document.toJson());}});}@Testpublic void testInsert() {Document document = new Document("id", 10001).append("name", "张三").append("age", 30);this.mongoCollection.insertOne(document);System.out.println("插入数据成功");this.mongoCollection.find(eq("id", 10001)).forEach(new Consumer<Document>() {@Overridepublic void accept(Document document) {System.out.println(document.toJson());}});}/****/@Testpublic void testDelete(){DeleteResult deleteResult = this.mongoCollection.deleteOne(eq("id",10001));System.out.println(deleteResult);}}
9.3.3 Java的面向对象接入MongoDB
我们知道MySQL可以很好的对接面向对象, MongoDB用的是类json格式, 那么也应该效果不差.
首先我们构建两个对象Person和Address
package cn.itcast.mongodb.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {private ObjectId id;private String name;private int age;private Address address;
}
package cn.itcast.mongodb.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {private String street;private String city;private String zip;
}
我们写一下单元测试
package cn.itcast.mongodb;import cn.itcast.mongodb.pojo.Address;
import cn.itcast.mongodb.pojo.Person;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.bson.types.ObjectId;
import org.junit.Before;
import org.junit.Test;import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;/*** mongoDB上了面向对象, 就好像我们在使用mybatis-plus的效果一致*/
public class TestPerson {private MongoCollection<Person> personCollection;/*** 连接, 得到mongoDB的表对象*/@Beforepublic void init() {CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build()));// 建立连接MongoClient mongoClient = MongoClients.create("mongodb://127.0.0.1:27017");// 连接数据库MongoDatabase mongoDatabase = mongoClient.getDatabase("testdb").withCodecRegistry(pojoCodecRegistry);// 选择表personCollection = mongoDatabase.getCollection("person", Person.class);}@Testpublic void testInsert() {Person person = new Person(ObjectId.get(),"张三", 20, new Address("人民路", "上海市", "666666"));this.personCollection.insertOne(person);System.out.println("插入数据成功");}@Testpublic void testInserts() {List<Person> personList = Arrays.asList(new Person(ObjectId.get(), "张三",20, new Address("人民路", "上海市", "666666")),new Person(ObjectId.get(), "李四", 21, new Address("北京西路", "上海市", "666666")),new Person(ObjectId.get(), "王五", 22, new Address("南京东路", "上海市", "666666")),new Person(ObjectId.get(), "赵六", 23, new Address("陕西南路", "上海市", "666666")),new Person(ObjectId.get(), "孙七", 24, new Address("南京西路", "上海市", "666666")));this.personCollection.insertMany(personList);System.out.println("插入数据成功");}@Testpublic void testQuery() {this.personCollection.find(Filters.eq("name", "张三")).forEach((Consumer<? super Person>) person -> {System.out.println(person);});}@Testpublic void testUpdate() {UpdateResult updateResult = this.personCollection.updateMany(// SET age = 22 WHERE name = '张三'Filters.eq("name", "张三"), Updates.set("age", 22));System.out.println(updateResult);}@Testpublic void testDelete() {DeleteResult deleteResult = this.personCollection.deleteOne(Filters.eq("name", "张三"));System.out.println(deleteResult);}
}
9.3.4 SpringBoot接入MongoDB
因为我们在搭建项目的时候, 就已经引入了SpringBoot与MongoDB整合所需的jar, 此处不再赘述.
直接新建并编写application.properties配置文件
# Spring boot application
spring.application.name = itcast-mongodb
spring.data.mongodb.uri=mongodb://127.0.0.1:27017/testdb
编写PersonDao
package cn.itcast.mongodb.dao;import cn.itcast.mongodb.pojo.Person;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
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.Component;import java.util.List;/*** 提供一些类似Mybatis-plus的常见接口*/
@Component
public class PersonDao {/*** 这个对象是通过读取我们的properties文件生成, 就是一个简化的表对象*/@Autowiredprivate MongoTemplate mongoTemplate;public void savePerson(Person person) {// TODO 提问: 为什么 mongoTemplate 这里没有指定表, 却能准确的插入到person表中呢?// 你可以点进去看一下源码: 他使用了你传入的类的名称小写首字母, 作为目标表名.// 你不好奇如果改了类名, 那表名不会自动更改吗?// 事实上我们在Spring整合时, 可以指定对象的表名this.mongoTemplate.save(person);}public List<Person> queryPersonListByName(String name) {Query query = Query.query(Criteria.where("name").is(name));return this.mongoTemplate.find(query, Person.class);}public List<Person> queryPersonListByName(Integer page, Integer rows) {Query query = new Query().limit(rows).skip((page - 1) * rows);return this.mongoTemplate.find(query, Person.class);}public UpdateResult update(Person person) {Query query = Query.query(Criteria.where("id").is(person.getId()));Update update = Update.update("age", person.getAge());return this.mongoTemplate.updateFirst(query, update, Person.class);}public DeleteResult deleteById(String id) {Query query = Query.query(Criteria.where("id").is(id));return this.mongoTemplate.remove(query, Person.class);}
}
测试相关代码
package cn.itcast.mongodb;import cn.itcast.mongodb.dao.PersonDao;
import cn.itcast.mongodb.pojo.Address;
import cn.itcast.mongodb.pojo.Person;
import org.bson.types.ObjectId;
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.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class TestPersonDao {@Autowiredprivate PersonDao personDao;@Testpublic void testSave() {Person person = new Person(ObjectId.get(), "张三", 20,new Address("人民路", "上海市", "666666"));this.personDao.savePerson(person);}@Testpublic void testQuery() {List<Person> personList = this.personDao.queryPersonListByName("张三");for (Person person : personList) {System.out.println(person);}}@Testpublic void testQuery2() {List<Person> personList = this.personDao.queryPersonListByName(2, 2);for (Person person : personList) {System.out.println(person);}}@Testpublic void testUpdate() {Person person = new Person();person.setId(new ObjectId("5c0956ce235e192520086736"));person.setAge(30);this.personDao.update(person);}@Testpublic void testDelete() {this.personDao.deleteById("5c09ca05235e192d8887a389");}
}
到这里我们基本上已经把常见的MongoDB操作都执行一遍了.
9.4 使用MongoDB改进实时通讯系统的存储方式
我们先改造项目依赖, 引入相关整合用的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
编写application.properties配置文件
# Spring boot application
spring.application.name = itcast-mongodb
spring.data.mongodb.uri=mongodb://127.0.0.1:27017/testdb
9.4.1 改进pojo类
我们在这里只需要改进Message类即可, 改后的完整代码如下:
package cn.itcast.haoke.im.pojo;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;import java.util.Date;@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
// 新增内容: 指定表名为message
@Document(collection = "message")
public class Message {// 修改内容: long -> org.bson.types.ObjectId, 并指定这个id 与_id对应.@Idprivate ObjectId id;/*** 消息体暂不支持复杂消息.*/private String msg;/*** 消息状态,1-未读,2-已读* 建立索引*/@Indexedprivate Integer status;/*** 发送的时间和已读的时间*/@Field("send_date")@Indexedprivate Date sendDate;@Field("read_date")private Date readDate;/*** 发送方和接收方*/@Indexedprivate User from;@Indexedprivate User to;
}
9.4.2 改进Dao接口与相关实现
更改MessageDao接口, 主要就是因为主键类型的变更导致的.
package cn.itcast.haoke.im.dao;import cn.itcast.haoke.im.pojo.Message;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.types.ObjectId;import java.util.List;public interface MessageDAO {/*** 查询点对点聊天记录*/List<Message> findListByFromAndTo(Long fromId, Long toId, Integer page, Integerrows);/*** 根据id查询数据** @param id* @return*/Message findMessageById(String id);/*** 更新消息状态** @param id* @param status* @return*/UpdateResult updateMessageState(ObjectId id, Integer status);/*** 新增消息** @param message* @return*/Message saveMessage(Message message);/*** 根据消息id删除数据** @param id* @return*/DeleteResult deleteMessage(String id);}
实现类变更如下:
package cn.itcast.haoke.im.dao.impl;import cn.itcast.haoke.im.dao.MessageDAO;
import cn.itcast.haoke.im.pojo.Message;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
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.stereotype.Component;import java.util.Date;
import java.util.List;@Component
public class MessageDAOImpl implements MessageDAO {@Autowiredprivate MongoTemplate mongoTemplate;/*** 实现:查询点对点消息记录* @param fromId* @param toId* @param page* @param rows* @return*/@Overridepublic List<Message> findListByFromAndTo(Long fromId, Long toId, Integer page, Integer rows) {// 用户A发送给用户B的条件Criteria criteriaFrom = new Criteria().andOperator(Criteria.where("from.id").is(fromId),Criteria.where("to.id").is(toId));// 用户B发送给用户A的条件Criteria criteriaTo = new Criteria().andOperator(Criteria.where("from.id").is(toId),Criteria.where("to.id").is(fromId));Criteria criteria = new Criteria().orOperator(criteriaFrom, criteriaTo);PageRequest pageRequest = PageRequest.of(page - 1, rows, Sort.by(Sort.Direction.ASC, "sendDate"));// 设置查询条件,分页Query query = Query.query(criteria).with(pageRequest);// System.out.println(query);return this.mongoTemplate.find(query, Message.class);}@Overridepublic Message findMessageById(String id) {return this.mongoTemplate.findById(new ObjectId(id), Message.class);}@Overridepublic UpdateResult updateMessageState(ObjectId id, Integer status) {Query query = Query.query(Criteria.where("id").is(id));Update update = Update.update("status", status);if (status.intValue() == 1) {update.set("send_date", new Date());} else if (status.intValue() == 2) {update.set("read_date", new Date());}return this.mongoTemplate.updateFirst(query, update, Message.class);}@Overridepublic Message saveMessage(Message message) {// 写入发送时间message.setSendDate(new Date());message.setStatus(1);message.setId(ObjectId.get());return this.mongoTemplate.save(message);}@Overridepublic DeleteResult deleteMessage(String id) {Query query = Query.query(Criteria.where("id").is(id));return this.mongoTemplate.remove(query, Message.class);}
}
调整单元测试, 这里也是因为id的类型变更导致的调整.
package cn.itcast.haoke.im.dao;import cn.itcast.haoke.im.pojo.Message;
import cn.itcast.haoke.im.pojo.User;
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.test.context.junit4.SpringRunner;
import java.util.Date;
import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class TestMessageDAO {@Autowiredprivate MessageDAO messageDAO;@Testpublic void testSave(){Message message = Message.builder().msg("你好").sendDate(new Date()).status(1).from(new User(1001L, "zhangsan")).to(new User(1002L,"lisi")).build();this.messageDAO.saveMessage(message);message = Message.builder().msg("你也好").sendDate(new Date()).status(1).to(new User(1001L, "zhangsan")).from(new User(1002L,"lisi")).build();this.messageDAO.saveMessage(message);message = Message.builder().msg("我在学习开发IM").sendDate(new Date()).status(1).from(new User(1001L, "zhangsan")).to(new User(1002L,"lisi")).build();this.messageDAO.saveMessage(message);message = Message.builder().msg("那很好啊!").sendDate(new Date()).status(1).to(new User(1001L, "zhangsan")).from(new User(1002L,"lisi")).build();this.messageDAO.saveMessage(message);System.out.println("ok");}@Testpublic void testQueryList(){List<Message> list = this.messageDAO.findListByFromAndTo(1001L, 1002L, 2,1);for (Message message : list) {System.out.println(message);}}@Testpublic void testQueryById(){List<Message> list = this.messageDAO.findListByFromAndTo(1001L, 1002L, 2, 1);Message message = this.messageDAO.findMessageById(list.get(0).getId().toString());System.out.println(message);}
}
这样我们就完成了本次改造目标.