MongoDB文档数据库

1.MongoDB介绍

 对于那些需要缓存而且经常需要统计、分析和查询的数据,对于Redis这样简单的NoSQL显然不是很方便,而MongoDB对于那些需要统计、按条件查询和分析的数据提供了支持,是一个最接近于关系数据库的NoSQL。
 MongoDB是由C++编写的一种NoSQL,是一个基于分布式文件存储的开源数据库系统,在负载高时可以添加更多的节点以保证服务器性能。MongoDB将数据存储为一个文档,数据结构由键值(key-value)对组成。
 与Redis一样,我们先引入Spring Boot关于MongoDB的starter,同时推荐引入阿里巴巴开发的fastjson开发包,方便JSON操作。代码如下(Maven):

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.46</version>
</dependency>

接下来,配置MongoDB,在application.properties属性文件中添加如下代码:

spring.data.mongodb.host=192.168.11.131     //MongoDB服务器
spring.data.mongodb.username=spring          //MongoDB服务器用户名
spring.data.mongodb.password=123456
spring.data.mongodb.port=27017
spring.data.mongodb.database=springboot      //数据库名称

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

logging.level.root=INFO

2.使用MongoTemplate实例

Spring Data MongoDB主要是通过MongoTemplate进行操作数据,而Spring Boot会根据配置自动生成这个对象(不需要自己创建),下面通过实例说明如何通过MongoTemplate来操作数据。
首先创建一个用户:

/**** imports ****/
// 标识为MongoDB文档
@Document
public class User implements Serializable {
	private static final long serialVersionUID = -7895435231819517614L;

	// MongoDB文档编号,主键
	@Id
	private Long id;

	// 在MongoDB中使用user_name保存属性
	@Field("user_name")
	private String userName = null;

	private String note = null;

	// 角色列表
	private List<Role> roles = null;

/**** setter and getter ****/
}

文档被标识为@Docunment,说明它将作为MongoDB的文档存在。注解@id则将对应的字段设为主键,使用@Field,这样属性userName与MongoDB中的user_name属性对应起来了。这里引入了角色列表,下面定义角色类:

/**** imports ****/
@Document
public class Role implements Serializable {
	private static final long serialVersionUID = -6843667995895038741L;
	private Long id;
	@Field("role_name")
	private String roleName = null;
	private String note = null;

	/**** setter and getter ****/
}

为了能够测试,我们新建用户测试器,代码如下:

/**** imports ****/
@Controller
@RequestMapping("/user")
public class UserController  {
	
	// 后面会给出其操作的方法
	@Autowired
	private UserService userService = null;

	// 跳转到测试页面
	@RequestMapping("/page")
	public String page() {
		return "user";
	}
	
	/**
	 * 保存(新增或者更新)用户
	 * @param user -- 用户
	 * @return 用户信息
	 */
	@RequestMapping("/save")
	@ResponseBody
	public User saveUser(@RequestBody User user) {
		userService.saveUser(user);
		return user;
	}
	
	/***
	 * 获取用户
	 * @param id -- 用户主键
	 * @return 用户信息
	 */
	@RequestMapping("/get")
	@ResponseBody
	public User getUser(Long id) {
		User user = userService.getUser(id);
		return user;
	}
	
	
	/**
	 * 查询用户
	 * @param userName --用户名称
	 * @param note -- 备注
	 * @param skip -- 跳过用户个数
	 * @param limit -- 限制返回用户个数
	 * @return
	 */
	@RequestMapping("/find")
	@ResponseBody
	public List<User> addUser(String userName, String note, Integer skip, Integer limit) {
		List<User> userList = userService.findUser(userName, note, skip, limit);
		return userList;
	}
	
	/**
	 * 更新用户部分属性
	 * @param id —— 用户编号
	 * @param userName —— 用户名称
	 * @param note —— 备注
	 * @return 更新结果
	 */
	@RequestMapping("/update")
	@ResponseBody
	public UpdateResult updateUser(Long id, String userName, String note) {
		return userService.updateUser(id, userName, note);
	}
	
	/**
	 * 删除用户
	 * @param id -- 用户主键
	 * @return 删除结果
	 */
	@RequestMapping("/delete")
	@ResponseBody
	public DeleteResult deleteUser(Long id) {
		return userService.deleteUser(id);
	}

这里引入UserService接口,先暂时不讨论它的实现,这里的page方法会跳转到一个测试的JSP页面中,接下俩采用这个JSP进行一些测试:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello Spring Boot</title>
<script type="text/javascript"
	src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
<!--后面在此处加入JavaScript脚本-->
</script>
</head>
<body>
	<h1>操作MongoDB文档</h1>
</body>
</html>

在后面的测试中,只需在对应代码处插入JS脚本就可以对后台发送HTTP的POST请求了。

3.使用MongoTemplate操作文档

上述代码使用了用户服务接口(UserService),在它的接口设计里包含了最常用的增删改查等功能,代码如下:

package com.springboot.chapter8.service;

import java.util.List;

import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.springboot.chapter8.pojo.User;

public interface UserService {
	public void saveUser(User user);

	public DeleteResult deleteUser(Long id);

	public List<User> findUser(String userName, String note, int skip, int limit);

	public UpdateResult updateUser(Long id, String userName, String note);

	public User getUser(Long id);
}

下面看实现类,先来看查询,包括获取用户(getUser方法)和查询用户(findUser方法):

@Service
public class UserServiceImpl implements UserService {

	// 注入MongoTemplate对象
	@Autowired
	private MongoTemplate mongoTmpl = null;

	@Override
	public User getUser(Long id) {
		return mongoTmpl.findById(id, User.class);
		// 如果只需要获取第一个也可以采用如下查询方法
		// Criteria criteriaId = Criteria.where("id").is(id);
		// Query queryId = Query.query(criteriaId);
		// return mongoTmpl.findOne(queryId, User.class);
	}

	@Override
	public List<User> findUser(String userName, String note, int skip, int limit) {
		// 将用户名称和备注设置为模糊查询准则
		Criteria criteria = Criteria.where("user_name").regex(userName).and("note").regex(note);
		// 构建查询条件,并设置分页跳过前skip个,至多返回limit个
		Query query = Query.query(criteria).limit(limit).skip(skip);
		// 执行
		List<User> userList = mongoTmpl.find(query, User.class);
		return userList;
	}

其中的Criteria criteria = Criteria.where("user_name").regex(userName).and("note").regex(note);

这里的where方法的参数设置为“userName”,这个字符串代表的是类User的属性userName;regex方法代表的是正则表达式匹配,即执行模糊查询;and方法代表连接字,代表同时满足。

启动SpringBoot应用程序后,我们可以对findUser方法进行验证,在浏览器地址输入http://localhost:8080/user/find?userName=user&note=note&skip=5&limit=5,可以看到结果。

接着是新增用户信息,代码如下:

@Override
	public void saveUser(User user) {
		// 使用名称为user文档保存用户信息
		mongoTmpl.save(user, "user");
		// 如果文档采用类名首字符小写,则可以这样保存
		// mongoTmpl.save(user);
	}

为了测试这个方法的结果,我们用之前定义的JS脚本进行验证,代码如下:

unction post(user) {
	var url = "./save"
	$.post({
		url : url,
		// 此处需要告知传递参数类型为JSON,不能缺少
		contentType : "application/json",
		// 将JSON转化为字符串传递
		data : JSON.stringify(user),
		// 成功后的方法
		success : function(result, status) {
			if (result == null || result.id == null) {
				alert("插入失败");
				return;
			}
		}
	});
}
for (var i = 1; i <= 10; i++) {
	var user = {
		'id' : i,
		'userName' : 'user_name_' + i,
		'note' : "note_" + i,
		'roles' : [ {
			'id' : i,
			'roleName' : 'role_' + i,
			'note' : 'note_' + i
		}, {
			'id' : i + 1,
			'roleName' : 'role_' + (i + 1),
			'note' : 'note_' + (i + 1)
		} ]
	};
	post(user);
}

通过它就能够插入10条用户数据,这里可以看到用户会多一个"_class"属性,这个属性保存的是类的全限定名,通过它可以通过Java的反射机制生成对应的User。有时候我们可能需要删除或者更新,代码如下:

@Override
	public DeleteResult deleteUser(Long id) {
		// 构建id相等的条件
		Criteria criteriaId = Criteria.where("id").is(id);
		// 查询对象
		Query queryId = Query.query(criteriaId);
		// 删除用户
		DeleteResult result = mongoTmpl.remove(queryId, User.class);
		return result;
	}

	@Override
	public UpdateResult updateUser(Long id, String userName, String note) {
		// 确定要更新的对象
		Criteria criteriaId = Criteria.where("id").is(id);
		Query query = Query.query(criteriaId);
		// 定义更新对象,后续可变化的字符串代表排除在外的属性
		Update update = Update.update("user_name", userName);
		update.set("note", note);
		// 更新单个对象
		UpdateResult result = mongoTmpl.updateFirst(query, update, User.class);
		// 更新多个对象
		// UpdateResult result2 = mongoTmpl.updateMulti(query, update, User.class);
		return result;
	}

这里与查询一样,使用主键构建了一个准则,然后使用remove方法将数据删除,执行删除后会返回一个DeleteResult对象来记录此次操作的结果。deleteCount代表删除文档的条数。

在更新方法中,定义了一个更新对象(Update),在创建它的时候,使用构造方法设置了对用户名的更新,然后使用set方法设置了note的更新,这样表明我们只是对这两个属性进行更新,其他属性并不更新。


本节代码已上传Github: https://github.com/lizeyang18/SpringBoot-2.x/tree/master/chapter8

学习永不止步,继续加油~