Spring启动的MongoDB
欢迎来到Spring Boot MongoDB示例。Spring Boot是最快捷的方式来迅速构建Spring项目,而MongoDB是最受欢迎的NoSQL数据库。让我们看看如何将Spring与MongoDB数据库集成起来。
Spring引导 MongoDB
我们需要以下API与Spring Boot和MongoDB数据库一起使用。
- Spring Data MongoDB
- Spring Boot
我们可以通过两种方式连接到MongoDB数据库 – MongoRepository和MongoTemplate。我们将尝试确定其中一个API相对于另一个API提供了哪些功能,并在什么情况下应选择其中之一以适应你的使用场景。我们将使用Spring Initializr工具来快速设置项目。那么,让我们开始吧。
使用Spring Boot搭建MongoDB项目
Maven 依赖
虽然我们已经使用工具完成了设置,但如果你想手动进行设置,我们在这个项目中使用的是Maven构建系统,以下是我们使用的依赖项。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.Olivia.spring</groupId>
<artifactId>spring-boot-mongodb</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-mongodb</name>
<description>Spring Boot MongoDB Example</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
请务必从Maven中央仓库使用稳定版本的Spring Boot。
Spring Boot的MongoDB模型类
我们有一个简单的模型类User.java。
package com.Olivia.bootifulmongodb.model;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class User {
@Id
private String userId;
private String name;
private Date creationDate = new Date();
private Map<String, String> userSettings = new HashMap<>();
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public Map<String, String> getUserSettings() {
return userSettings;
}
public void setUserSettings(Map<String, String> userSettings) {
this.userSettings = userSettings;
}
}
Spring Boot的MongoDB API
我们的应用程序将具有以下功能和数据库交互。
- Get all users
- Get a user with ID
- Get user settings
- Get a particular key from the Map
- Add/Update user setting
MongoRepository – Spring Data MongoDB
现在我们将使用Spring Data MongoDB存储库来访问我们的数据。Spring Data MongoRepository为我们提供了常见的功能,我们可以轻松地插入和使用它们。让我们定义我们的存储库接口。
package com.Olivia.bootifulmongodb.dal;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.Olivia.bootifulmongodb.model.User;
@Repository
public interface UserRepository extends MongoRepository<User, String> {
}
定义MongoDB属性
在我们布置控制器之前,与本地 MongoDB 实例建立连接非常重要。我们将使用 Spring Boot 属性来实现这一点。
#Local MongoDB config
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.username=root
spring.data.mongodb.password=root
spring.data.mongodb.database=user_db
spring.data.mongodb.port=27017
spring.data.mongodb.host=localhost
# App config
server.port=8102
spring.application.name=BootMongo
server.context-path=/user
因此,该应用程序将在端口8102上运行,并连接到本地的MongoDB实例,使用提供的凭据进行连接。如果您有一个没有启用授权的本地实例,您可以删除配置中的前三行。
定义Spring控制器
让我们最终转向制作我们的控制器类。
package com.Olivia.bootifulmongodb.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.Olivia.bootifulmongodb.dal.UserRepository;
import com.Olivia.bootifulmongodb.model.User;
@RestController
@RequestMapping(value = "/")
public class UserController {
private final Logger LOG = LoggerFactory.getLogger(getClass());
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
我们刚刚使用@Autowired注入了repository接口的依赖项,接下来我们将使用它。
定义应用程序编程接口 (APIs)
关于我们提到的功能,我们将会制作API,并访问用户存储库依赖,它将在内部使用Spring Data MongoRepository API。请注意,我们不需要在接口中编写任何数据库交互代码,因为Spring Data会为我们完成所有操作。
获取所有用户
@RequestMapping(value = "", method = RequestMethod.GET)
public List<User> getAllUsers() {
LOG.info("Getting all users.");
return userRepository.findAll();
}
findAll()只是一个Spring Data MongoRepository内部提供的方法。
通过用户ID获取用户
现在,让我们获取一个具有特定ID的用户。
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable String userId) {
LOG.info("Getting user with ID: {}.", userId);
return userRepository.findOne(userId);
}
findOne()只是Spring Data MongoRepository在内部提供的一种方法,用于根据ID获取对象。
添加一个新用户
在下面的函数中,我们将添加一个新用户。
@RequestMapping(value = "/create", method = RequestMethod.POST)
public User addNewUsers(@RequestBody User user) {
LOG.info("Saving user.");
return userRepository.save(user);
}
获取用户设置
现在我们已经在数据库中添加了样本数据,让我们试着提取其中的一部分。
@RequestMapping(value = "/settings/{userId}", method = RequestMethod.GET)
public Object getAllUserSettings(@PathVariable String userId) {
User user = userRepository.findOne(userId);
if (user != null) {
return user.getUserSettings();
} else {
return "User not found.";
}
}
获取特定用户设置
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(@PathVariable String userId, @PathVariable String key) {
User user = userRepository.findOne(userId);
if (user != null) {
return user.getUserSettings().get(key);
} else {
return "User not found.";
}
}
请注意,在上述查询中,我们获得了用户对象,然后提取了完整的设置映射(其中可能包含数千个对象),最后得到了我们自己的值。这是使用Spring Data查询作为直接API时的一个缺点。
新增一个用户设置
让我们尝试为现有用户添加一些数据。
@RequestMapping(value = "/settings/{userId}/{key}/{value}", method = RequestMethod.GET)
public String addUserSetting(@PathVariable String userId, @PathVariable String key, @PathVariable String value) {
User user = userRepository.findOne(userId);
if (user != null) {
user.getUserSettings().put(key, value);
userRepository.save(user);
return "Key added";
} else {
return "User not found.";
}
}
通过我们编写的所有代码可以看出,除了定义存储库接口和自动装载依赖项之外,我们根本不需要编写任何一行代码来访问数据库。这是Spring Data MongoRepository API提供的便利,但它也有一些缺点。当我们也定义了MongoTemplate版本时,我们将详细阐述这个问题。让我们也开始着手处理这个问题。
Spring Data MongoDB 是一个用于访问 MongoDB 数据库的框架,它提供了一个名为 MongoTemplate 的模板类。
我们将在这里定义MongoTemplate数据库查询。使用MongoTemplate,您会发现我们对于查询和包含在结果中的数据有更精细的控制。
定义DAL接口
为了在数据库访问层提供一个合同,我们将从定义一个接口开始,该接口的效果与我们的Spring Data内置方法相同。
package com.Olivia.bootifulmongodb.dal;
import java.util.List;
import com.Olivia.bootifulmongodb.model.User;
public interface UserDAL {
List<User> getAllUsers();
User getUserById(String userId);
User addNewUser(User user);
Object getAllUserSettings(String userId);
String getUserSetting(String userId, String key);
String addUserSetting(String userId, String key, String value);
}
实施DAL接口
我们继续并定义这些方法。
package com.Olivia.bootifulmongodb.dal;
import java.util.List;
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.stereotype.Repository;
import com.Olivia.bootifulmongodb.model.User;
@Repository
public class UserDALImpl implements UserDAL {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public List<User> getAllUsers() {
return mongoTemplate.findAll(User.class);
}
@Override
public User getUserById(String userId) {
Query query = new Query();
query.addCriteria(Criteria.where("userId").is(userId));
return mongoTemplate.findOne(query, User.class);
}
@Override
public User addNewUser(User user) {
mongoTemplate.save(user);
// Now, user object will contain the ID as well
return user;
}
@Override
public Object getAllUserSettings(String userId) {
Query query = new Query();
query.addCriteria(Criteria.where("userId").is(userId));
User user = mongoTemplate.findOne(query, User.class);
return user != null ? user.getUserSettings() : "User not found.";
}
@Override
public String getUserSetting(String userId, String key) {
Query query = new Query();
query.fields().include("userSettings");
query.addCriteria(Criteria.where("userId").is(userId).andOperator(Criteria.where("userSettings." + key).exists(true)));
User user = mongoTemplate.findOne(query, User.class);
return user != null ? user.getUserSettings().get(key) : "Not found.";
}
@Override
public String addUserSetting(String userId, String key, String value) {
Query query = new Query();
query.addCriteria(Criteria.where("userId").is(userId));
User user = mongoTemplate.findOne(query, User.class);
if (user != null) {
user.getUserSettings().put(key, value);
mongoTemplate.save(user);
return "Key added.";
} else {
return "User not found.";
}
}
}
以上类中的方法实现都使用了MongoTemplate依赖。请看getUserById(…)方法是如何获取用户的。我们构造了一个查询并传递了必要的参数。让我们来了解一下上面发生了什么事情。
- We constructed queries with criteria to check equality.
- The include method includes the field names which the result should include when it is extracted from DB. This means, in this case, userSettings key will be extracted which will save a lot of data to be fetched which is not needed
- Also, we queried upon both user and the map key. Id any of it isn’t found, we return empty data meaning the required key wasn’t found. This saves from even fetching the User object at all if the required key was not present
Spring Data MongoDB 测试运行.
只需要使用一个命令,我们就可以简单地运行这个应用程序。
mvn spring-boot:run
一旦应用程序运行,我们可以尝试使用这个API保存一个新用户。
https://localhost:8102/user/create
由于这将是一次POST请求,我们还将发送JSON数据。
{
"name" : "Shubham",
"userSettings" : {
"bike" : "pulsar"
}
}
由于我们返回的是Mongo响应本身,所以我们将会得到类似于以下的结果:
{
"userId": "5a5f28cc3178058b0fafe1dd",
"name": "Shubham",
"creationDate": 1516165830856,
"userSettings": {
"bike" : "pulsar"
}
}
https://localhost:8102/user/
我们会得到类似的东西。
[
{
"userId": "5a5f28cc3178058b0fafe1dd",
"name": "Shubham",
"creationDate": 1516165830856,
"userSettings": {
"bike" : "pulsar"
}
}
]
//define Data Access Layer object
private final UserDAL userDAL;
//initialize DAL object via constructor autowiring
public UserController(UserRepository userRepository, UserDAL userDAL) {
this.userRepository = userRepository;
this.userDAL = userDAL;
}
//change method implementation to use DAL and hence MongoTemplate
@RequestMapping(value = "/settings/{userId}", method = RequestMethod.GET)
public Object getAllUserSettings(@PathVariable String userId) {
User user = userRepository.findOne(userId);
if (user != null) {
return userDAL.getAllUserSettings(userId);
} else {
return "User not found.";
}
}
//change method implementation to use DAL and hence MongoTemplate
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(
@PathVariable String userId, @PathVariable String key) {
return userDAL.getUserSetting(userId, key);
}
MongoTemplate和MongoRepository之间的区别
- MongoTemplate provides a lot more control when it comes to querying data and what data to pull from database.
- Spring Data repositories provide us a convenient outlook on how to fetch data.
- MongoTemplate is database dependent. What this means is, with Spring Data repositories, you can easily switch to a different database altogether by simply using a different Spring Data repositories for MySQL or Neo4J or anything else. This is not possible with MongoTemplate.
Spring引导MongoDB摘要
在本课程中,我们学习了MongoTemplate如何为我们提供更多对Spring Data存储库的控制,但在涉及更深层次的查询时可能会变得有些复杂。所以,在开发您的想法时,完全由您决定选择什么。请随时在下方留下评论。从以下链接下载源代码。在运行所提供的应用程序之前,请确保更改MongoDB凭据。