SpringBoot2.x集成MongoDB

MongoDB

MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是可以应用于各种规模的企业、各个行业以及各类应用程序的开源数据库。基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的一种。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

传统的关系数据库一般由数据库(database)、表(table)、记录(record)三个层次概念组成,MongoDB是由数据库(database)、集合(collection)、文档对象(document)三个层次组成。MongoDB对于关系型数据库里的表,但是集合中没有列、行和关系概念,这体现了模式自由的特点。

MySql MongoDB
数据库 数据库
集合
文档
记录 字段

开发环境

IDEA、Maven、SpringBoot2.0.4、Jdk1.8、MongoDB4.0、MongoDB Compass Community、PostMan

配置开始

  1. Maven 相关配置
    在pox.xml文件中添加spring-boot-starter-data-mongodb引用
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
  1. 资源文件yml配置
    笔者这里使用yml配置方式,配置时要注意缩进!!!!
1
2
3
4
5
6
7
8
9
10
11
server:
port: 8031

spring:
application:
name: spirng-boot-mongodb
data:
mongodb:
host: localhost #同127.0.0.1
port: 27017
database: test #指定操作的数据库
  1. 创建实体类
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
import org.springframework.data.annotation.Id;
import java.util.Date;
/**
* 描述:图书实体类
*
* @author zhengql
* @date 2018/8/9 10:28
*/
public class Book {
@Id
private String id;
//价格
private Integer price;
//书名
private String name;
//简介
private String info;
//出版社
private String publish;
//创建时间
private Date createTime;
//修改时间
private Date updateTime;

//Getter、Setter省略....
  1. 创建service类
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Service;

import java.util.Date;
import java.util.List;

/**
* 描述:
* mongo
*
* @author zhengql
* @date 2018/8/9 10:24
*/
@Service
public class MongoDbService {
private static final Logger logger = LoggerFactory.getLogger(MongoDbService.class);

@Autowired
private MongoTemplate mongoTemplate;

/**
* 保存对象
*
* @param book
* @return
*/
public String saveObj(Book book) {
logger.info("--------------------->[MongoDB save start]");
book.setCreateTime(new Date());
book.setUpdateTime(new Date());
mongoTemplate.save(book);
return "添加成功";
}


/**
* 查询所有
*
* @return
*/
public List<Book> findAll() {
logger.info("--------------------->[MongoDB find start]");
return mongoTemplate.findAll(Book.class);
}


/***
* 根据id查询
* @param id
* @return
*/
public Book getBookById(String id) {
logger.info("--------------------->[MongoDB find start]");
Query query = new Query(Criteria.where("_id").is(id));
return mongoTemplate.findOne(query, Book.class);
}

/**
* 根据名称查询
*
* @param name
* @return
*/
public Book getBookByName(String name) {
logger.info("--------------------->[MongoDB find start]");
Query query = new Query(Criteria.where("name").is(name));
return mongoTemplate.findOne(query, Book.class);
}

/**
* 更新对象
*
* @param book
* @return
*/
public String updateBook(Book book) {
logger.info("--------------------->[MongoDB update start]");
Query query = new Query(Criteria.where("_id").is(book.getId()));
Update update = new Update().set("publish", book.getPublish())
.set("info", book.getInfo())
.set("updateTime", new Date());
//updateFirst 更新查询返回结果集的第一条
mongoTemplate.updateFirst(query, update, Book.class);
//updateMulti 更新查询返回结果集的全部
// mongoTemplate.updateMulti(query,update,Book.class);
//upsert 更新对象不存在则去添加
// mongoTemplate.upsert(query,update,Book.class);
return "success";
}

/***
* 删除对象
* @param book
* @return
*/
public String deleteBook(Book book) {
logger.info("--------------------->[MongoDB delete start]");
mongoTemplate.remove(book);
return "success";
}

/**
* 根据id删除
*
* @param id
* @return
*/
public String deleteBookById(String id) {
logger.info("--------------------->[MongoDB delete start]");
//findOne
Book book = getBookById(id);
//delete
deleteBook(book);
return "success";
}
}
  1. controller
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
import com.example.mqdemo.mongo.Book;
import com.example.mqdemo.mongo.MongoDbService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/***
* @author zhengql
* @date 2018/8/9 10:38
*/
@RestController
public class BaseController {

@Autowired
private MongoDbService mongoDbService;

@PostMapping("/mongo/save")
public String saveObj(@RequestBody Book book) {return mongoDbService.saveObj(book);}

@GetMapping("/mongo/findAll")
public List<Book> findAll() {return mongoDbService.findAll();}

@GetMapping("/mongo/findOne")
public Book findOne(@RequestParam String id) {return mongoDbService.getBookById(id);}

@GetMapping("/mongo/findOneByName")
public Book findOneByName(@RequestParam String name) {return mongoDbService.getBookByName(name);}

@PostMapping("/mongo/update")
public String update(@RequestBody Book book) {return mongoDbService.updateBook(book);}

@PostMapping("/mongo/delOne")
public String delOne(@RequestBody Book book) {return mongoDbService.deleteBook(book);}

@GetMapping("/mongo/delById")
public String delById(@RequestParam String id) {return mongoDbService.deleteBookById(id);}
}
  1. 运行测试
    启动项目,打开postman开始接口调试,可以看到成功添加book对象。返回添加成功。

打开MongoDB Compass Community,连接本地MongoDB,可以看到刚才添加的信息。

其他接口这里就不一一测试了。

优化使用

完成以上配置,我们springBoot集成MongoDB环境基本已经搭建好了。

但是在使用中会发现一个问题,假如要对数据库操作多个对象,那岂不是每一个对象Service都需要写一套增删查改的方法。

为了解决这一问题我们可以封装一个通用的操作类来提高效率。

创建MongoDbDao类如下:

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;


/**
* 描述:
* mongoDB基础方法封装
*
* @author zhengql
* @date 2018/8/9 14:01
*/
public abstract class MongoDbDao<T> {

protected Logger logger = LoggerFactory.getLogger(MongoDbDao.class);

/**
* 反射获取泛型类型
*
* @return
*/
protected abstract Class<T> getEntityClass();

@Autowired
private MongoTemplate mongoTemplate;

/***
* 保存一个对象
* @param t
*/
public void save(T t) {
logger.info("-------------->MongoDB save start");
this.mongoTemplate.save(t);
}

/***
* 根据id从几何中查询对象
* @param id
* @return
*/
public T queryById(Integer id) {
Query query = new Query(Criteria.where("_id").is(id));
logger.info("-------------->MongoDB find start");
return this.mongoTemplate.findOne(query, this.getEntityClass());
}

/**
* 根据条件查询集合
*
* @param object
* @return
*/
public List<T> queryList(T object) {
Query query = getQueryByObject(object);
logger.info("-------------->MongoDB find start");
return mongoTemplate.find(query, this.getEntityClass());
}

/**
* 根据条件查询只返回一个文档
*
* @param object
* @return
*/
public T queryOne(T object) {
Query query = getQueryByObject(object);
logger.info("-------------->MongoDB find start");
return mongoTemplate.findOne(query, this.getEntityClass());
}

/***
* 根据条件分页查询
* @param object
* @param start 查询起始值
* @param size 查询大小
* @return
*/
public List<T> getPage(T object, int start, int size) {
Query query = getQueryByObject(object);
query.skip(start);
query.limit(size);
logger.info("-------------->MongoDB queryPage start");
return this.mongoTemplate.find(query, this.getEntityClass());
}

/***
* 根据条件查询库中符合条件的记录数量
* @param object
* @return
*/
public Long getCount(T object) {
Query query = getQueryByObject(object);
logger.info("-------------->MongoDB Count start");
return this.mongoTemplate.count(query, this.getEntityClass());
}

/***
* 删除对象
* @param t
* @return
*/
public int delete(T t) {
logger.info("-------------->MongoDB delete start");
return (int) this.mongoTemplate.remove(t).getDeletedCount();
}

/**
* 根据id删除
*
* @param id
*/
public void deleteById(Integer id) {
Criteria criteria = Criteria.where("_id").is(id);
if (null != criteria) {
Query query = new Query(criteria);
T obj = this.mongoTemplate.findOne(query, this.getEntityClass());
logger.info("-------------->MongoDB deleteById start");
if (obj != null) {
this.delete(obj);
}
}
}

/*MongoDB中更新操作分为三种
* 1:updateFirst 修改第一条
* 2:updateMulti 修改所有匹配的记录
* 3:upsert 修改时如果不存在则进行添加操作
* */

/**
* 修改匹配到的第一条记录
* @param srcObj
* @param targetObj
*/
public void updateFirst(T srcObj, T targetObj){
Query query = getQueryByObject(srcObj);
Update update = getUpdateByObject(targetObj);
logger.info("-------------->MongoDB updateFirst start");
this.mongoTemplate.updateFirst(query,update,this.getEntityClass());
}

/***
* 修改匹配到的所有记录
* @param srcObj
* @param targetObj
*/
public void updateMulti(T srcObj, T targetObj){
Query query = getQueryByObject(srcObj);
Update update = getUpdateByObject(targetObj);
logger.info("-------------->MongoDB updateFirst start");
this.mongoTemplate.updateMulti(query,update,this.getEntityClass());
}

/***
* 修改匹配到的记录,若不存在该记录则进行添加
* @param srcObj
* @param targetObj
*/
public void updateInsert(T srcObj, T targetObj){
Query query = getQueryByObject(srcObj);
Update update = getUpdateByObject(targetObj);
logger.info("-------------->MongoDB updateInsert start");
this.mongoTemplate.upsert(query,update,this.getEntityClass());
}

/**
* 将查询条件对象转换为query
*
* @param object
* @return
* @author Jason
*/
private Query getQueryByObject(T object) {
Query query = new Query();
String[] fileds = getFiledName(object);
Criteria criteria = new Criteria();
for (int i = 0; i < fileds.length; i++) {
String filedName = (String) fileds[i];
Object filedValue = getFieldValueByName(filedName, object);
if (filedValue != null) {
criteria.and(filedName).is(filedValue);
}
}
query.addCriteria(criteria);
return query;
}

/**
* 将查询条件对象转换为update
*
* @param object
* @return
* @author Jason
*/
private Update getUpdateByObject(T object) {
Update update = new Update();
String[] fileds = getFiledName(object);
for (int i = 0; i < fileds.length; i++) {
String filedName = (String) fileds[i];
Object filedValue =getFieldValueByName(filedName, object);
if (filedValue != null) {
update.set(filedName, filedValue);
}
}
return update;
}

/***
* 获取对象属性返回字符串数组
* @param o
* @return
*/
private static String[] getFiledName(Object o) {
Field[] fields = o.getClass().getDeclaredFields();
String[] fieldNames = new String[fields.length];

for (int i = 0; i < fields.length; ++i) {
fieldNames[i] = fields[i].getName();
}

return fieldNames;
}

/***
* 根据属性获取对象属性值
* @param fieldName
* @param o
* @return
*/
private static Object getFieldValueByName(String fieldName, Object o) {
try {
String e = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + e + fieldName.substring(1);
Method method = o.getClass().getMethod(getter, new Class[0]);
return method.invoke(o, new Object[0]);
} catch (Exception var6) {
return null;
}
}
}

我们将mongoDB常用的CURD操作封装为通用的父类,然后在不同的业务场景下继承该类,通过泛型和反射获取到正在操作的实体类。

比如我们可以将之前的Book实体类的CURD类进行改造

创建BookMongoDbDao类继承MongoDbDao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.stereotype.Repository;

/**
* 描述:
*
* @author zhengql
* @date 2018/8/9 20:46
*/
@Repository
public class BookMongoDbDao extends MongoDbDao<Book> {
@Override
protected Class<Book> getEntityClass() {
return Book.class;
}
}

接下来我们可以改造Book的Service类
原始版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Service
public class BookMongoDbService {
private static final Logger logger = LoggerFactory.getLogger(BookMongoDbService.class);

@Autowired
private MongoTemplate mongoTemplate;

/**
* 保存对象
*
* @param book
* @return
*/
public String saveObj(Book book) {
logger.info("--------------------->[MongoDB save start]");
book.setCreateTime(new Date());
book.setUpdateTime(new Date());
mongoTemplate.save(book);
return "添加成功";
}

//其他操作方法......
}

改造后

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
@Service
public class BookMongoDbService {
private static final Logger logger = LoggerFactory.getLogger(BookMongoDbService.class);

@Autowired
private MongoTemplate mongoTemplate;

@Autowired
private BookMongoDbDao bookMongoDbDao;

/**
* 保存对象
*
* @param book
* @return
*/
public String saveObj(Book book) {
logger.info("--------------------->[MongoDB save start]");
book.setCreateTime(new Date());
book.setUpdateTime(new Date());
mongoTemplate.save(book);
return "添加成功";
}

public String saveObj2(Book book) {
book.setCreateTime(new Date());
book.setUpdateTime(new Date());
bookMongoDbDao.save(book);
return "添加成功";
}
}

改造后的saveObj2方法的效果与以前的一致,但是大大的提高了开发效率。不需要重复的编写CURD的方法。

总结

通过以上的配置已经完成springboot与mongoDB集成环境的初步搭建,当然了MongoDB在springboot中的使用不仅于此,还有更多的功能和更优雅的使用方式等待着我们去发掘。

---------- 😏本文结束  感谢您的阅读😏 ----------
评论