对于那些需要缓存而且经常需要统计、分析和查询的数据,对于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=INFOSpring 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请求了。
上述代码使用了用户服务接口(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¬e=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
学习永不止步,继续加油~