Spring Boot集成MongoDB完整教程:从配置到实战应用

欢迎来到Spring Boot MongoDB示例。Spring Boot是快速构建Spring项目的最快方式,而MongoDB是最受欢迎的NoSQL数据库。让我们看看如何将Spring与MongoDB数据库集成起来。

Spring Boot MongoDB

我们需要以下API来与Spring Boot和MongoDB数据库一起使用:

  • Spring Data MongoDB
  • Spring Boot

我们可以通过两种方式连接到MongoDB数据库 – MongoRepository和MongoTemplate。我们将尝试确定其中一个API相对于另一个API提供了哪些功能,以及在什么情况下应选择其中之一以适应你的使用场景。我们将使用Spring Initializr工具来快速设置项目。那么,让我们开始吧。

使用Spring Boot搭建MongoDB项目

spring boot mongodb project setup using spring initializr

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

我们的应用程序将具有以下功能和数据库交互:

  • 获取所有用户
  • 根据ID获取用户
  • 获取用户设置
  • 从Map中获取特定键
  • 添加/更新用户设置

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 属性来实现这一点。

# 本地MongoDB配置
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

# 应用程序配置
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("获取所有用户。");
	return userRepository.findAll();
}

findAll()只是一个Spring Data MongoRepository内部提供的方法。

通过用户ID获取用户

现在,让我们获取一个具有特定ID的用户。

@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable String userId) {
	LOG.info("获取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("保存用户。");
	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 "未找到用户。";
	}
}

获取特定用户设置

@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 "未找到用户。";
	}
}

请注意,在上述查询中,我们获得了用户对象,然后提取了完整的设置映射(其中可能包含数千个对象),最后得到了我们自己的值。这是使用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 "键已添加";
	} else {
		return "未找到用户。";
	}
}

通过我们编写的所有代码可以看出,除了定义存储库接口和自动装载依赖项之外,我们根本不需要编写任何一行代码来访问数据库。这是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接口

我们继续并定义这些方法。

这是文章《Spring启动的MongoDB》的第3部分(共4部分)。

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(…)方法是如何获取用户的。我们构造了一个查询并传递了必要的参数。让我们来了解一下上面发生了什么事情。

  • 我们使用条件构造查询来检查相等性。
  • include方法包含了从数据库提取结果时应包含的字段名。这意味着,在这种情况下,将提取userSettings键,这将节省大量不需要获取的数据。
  • 此外,我们同时查询了用户和映射键。如果其中任何一个未找到,我们返回空数据,表示未找到所需的键。如果所需的键不存在,这可以避免甚至获取User对象。

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"
  }
}
Spring Data MongoDB MongoRepository Example Create
https://localhost:8102/user/

我们会得到类似的东西。

[
  {
    "userId": "5a5f28cc3178058b0fafe1dd",
    "name": "Shubham",
    "creationDate": 1516165830856,
    "userSettings": {
      "bike" : "pulsar"
    }
  }
]
Spring Data MongoDB
//定义数据访问层对象
private final UserDAL userDAL;

//通过构造函数自动装配初始化DAL对象
public UserController(UserRepository userRepository, UserDAL userDAL) {
	this.userRepository = userRepository;
	this.userDAL = userDAL;
}

//更改方法实现以使用DAL,从而使用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.";
    }
}

//更改方法实现以使用DAL,从而使用MongoTemplate
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(
        @PathVariable String userId, @PathVariable String key) {
    return userDAL.getUserSetting(userId, key);
}
Spring Data MongoDB MongoTemplate示例条件查询

MongoTemplate和MongoRepository之间的区别

  • MongoTemplate在查询数据和从数据库中提取什么数据方面提供了更多控制。
  • Spring Data存储库为我们提供了获取数据的便捷视角。
  • MongoTemplate依赖于数据库。这意味着,使用Spring Data存储库,您可以通过简单地使用不同的Spring Data存储库(如MySQL或Neo4J等)轻松切换到完全不同的数据库。而使用MongoTemplate则无法做到这一点。

Spring Boot MongoDB摘要

在本课程中,我们学习了MongoTemplate如何为我们提供更多对Spring Data存储库的控制,但在涉及更深层次的查询时可能会变得有些复杂。所以,在开发您的应用时,选择哪种方式完全取决于您的需求。请随时在下方留下评论。您可以从以下链接下载源代码。在运行所提供的应用程序之前,请确保更改MongoDB凭据。

bannerAds