MongoDB教程:使用Java从头开始

有许多数据库系统采用非表格NoSQL方法来处理数据管理。其中最受欢迎的是MongoDB,它用于各种行业。虽然MongoDB只是Ruby on Rails或Node.js开发人员的选择,但使用MongoDB和Spring Boot这样的现代Java框架,可以成为解决问题的强大工具。

在本文中,我们将学习如何将MongoDB合并到我们的Java应用程序中,同时创建一个使用嵌入式MongoDB数据库,Spring Boot,  Spring Data和Thymeleaf的简化todo应用程序。

为什么要使用MongoDB?

您可能想知道为什么有人会使用像MongoDB这样的NoSQL数据库而不是传统的关系数据库。这真的取决于。NoSQL方法要求您对数据进行非规范化。也就是说,您需要将有关特定对象的所有数据存储在MongoDB调用Document的内容中。NoSQL数据库也使用非结构化数据。此外,没有需要创建的架构。这使得添加其他属性或更改数据类型比在关系数据库中更容易。最后,如果你有一个非常大的数据库,MongoDB将非常适合你的需求。它提供了出色的可扩展性和性能。

如果您不想从头开始创建项目,可以在GitHub上找到本文中开发的已完成的应用程序

创建一个Java Spring项目

在本文中,我们将从使用在线Spring Initializr创建的Gradle项目开始。使用下面的屏幕截图作为参考,并使用Web,Thymeleaf和MongoDB依赖项创建Gradle项目。(也可以使用Eclipse 来创建 spring 项目

1539761893(1).jpg

在生成Gradle项目之后,我们需要将以下两个依赖项添加到build.gradle  文件中以使用嵌入式MongoDB实例:

 

完成后,检查build.gradle  文件是否如下所示:

 

首次运行应用程序时,它将比正常时间长几分钟。这是因为正在下载和配置MongoDB依赖项。完成所有操作后,控制台输出将指示MongoDB的嵌入式实例已启动并运行:

目前,我们的项目缺少一个处理Web请求的控制器。让我们通过创建一个控制器和相应的Thymeleaf视图来解决这个问题。这将为我们进一步的工作提供一个良好的起点。

1539765153(1).jpg

创建任务控制器和视图

在做任何其他事情之前,我们将创建一个控制器来处理我们的应用程序的Web请求并路由到我们的视图。在 名为TodoController的src / main / java / com / flammulina/ mongodb / controllers中创建以下Spring控制器:

 

此控制器 为我们的index.html  模板创建“/”端点的URL映射,我们将在下一步创建该模板。 在src / main / resources / templates中创建一个名为index.html的新文件, 并向其中添加以下HTML:

 

除了一些静态样板HTML之外,我们的观点确实没有任何意义。 我们将在后面的部分中更新它以从我们的MongoDB实例动态提取数据。 现在,让我们进行测试,以确保我们正确设置一切。 执行以下Gradle命令以启动Spring Boot应用程序:

接下来,打开浏览器到http:// localhost:8080,您将看到以下内容,表明我们的控制器和视图已成功连接在一起:1539765546(1).jpg

这是不是很令人兴奋。 现在让我们将我们的应用程序配置为使用Mongo并创建一些待办事项。

创建MongoDB配置
Spring Boot的一个好处是它使用了Spring注释。 这减轻了必须使用XML配置我们的应用程序的痛苦。 使用适当的注释,Spring Boot将为我们处理所有配置和设置。 我们将利用此功能来配置我们的嵌入式MongoDB实例。 继续在src / main / java / com / stackify / mongodb / config包中创建以下MongoConfig类:

 

此配置创建一个新的EmbeddedMongoFactoryBean,将MongoDB绑定到localhost,然后 为我们创建与embedded_db数据库的连接。每次运行我们的应用程序时,我们都会从一个空数据库开始。我们将在应用程序启动后将一些数据预加载到数据库实例中,以便我们可以使用数据。

实体,表格,集合和文档

如果您之前使用过Spring Data,那么您将熟悉@Entity  注释。这告诉Spring Data将该类视为映射到数据库中的行的域对象。如前所述,MongoDB不使用表。相反,它将对象创建为文档,而多个文档称为集合。在MongoDB中,域对象映射到单个文档。因此,有一个相应的@Document  注释与我们的MongoDB域对象一起使用,以区别于关系数据库映射中使用的域对象,这是很自然的。 在src / main / java / com / flammulina/ mongodb / domain  包中创建以下  Todo类,并将以下代码添加到其中:

 

您会注意到我们使用了@Document注释,表明这是一个MongoDB文档。您还会注意到我们正在使用 您之前在Spring Data工作中熟悉的标准@Id注释。但是,这里我们已经使用ObjectId  数据类型声明了id属性。在MongoDB中,文档不对标识符使用顺序数值。相反,它们使用由以下数据组成的12字节十六进制值:

  • 一个4字节的值,表示自Unix时代以来的秒数,
  • 一个3字节的机器标识符,
  • 一个2字节的进程ID,和
  • 一个3字节的计数器,以随机值开始。

这导致我们的对象具有类似于以下内容的标识符:

的ObjectId(5b5615914434ad438bf3ea43)

当我们需要使用ObjectId  作为字符串值时,我们可以使用toHexString  方法或ObjectId的重载toString  方法。1539765993.jpg

创建Todo存储库

我们要解决的下一个应用程序是创建我们的TodoRepository。在这里,我们使用Repository设计模式来处理我们的域和数据映射。有了这个允许我们创建几个待办事项对象并将它们保存到数据库。然后,我们将更新视图以查询MongoDB数据库并显示它们。

继续 在src / main / java / com / stackify / mongodb / repositories中创建TodoRepository接口:

 

正如您所看到的,这个界面并不是很多。由于  CrudRepository的神奇之处,我们实现了所有通用的创建,读取,更新和删除(CRUD)操作。我们不需要在界面中添加任何其他内容。

让我们通过创建几个待办事项并坚持它们来尝试。我们可以通过各种方式将数据预加载到数据库中,但为了简单起见,我们将创建Spring ApplicationListener  接口的实现。通过创建实现此接口的组件,我们可以在应用程序完成加载之前运行代码。

因此, 在src / main / java / com / stackify / mongodb / components中创建以下ApplicationStartup 组件。我们将使用它来使用我们的新TodoRepository创建几个待办事项:

 

请注意,我们已经使用了@Autowired注释,因此Spring将为我们处理TodoRepository的实例化 。控制台将显示每个创建的待办事项的日志消息:

 

接下来,让我们更新视图以显示此数据,而不是我们不再使用的空白页面。

在视图中显示数据

虽然我们可以 直接在我们的控制器中使用我们的TodoRepository接口来处理我们的todo对象,但良好的设计要求我们创建一个服务类来充当模型和视图之间的中介。这样做使我们能够围绕域对象创建更复杂的功能,而不会污染TodoRepository  接口,将其留给CRUD操作。

首先 在src / main / java / com / stackify / mongodb / services  包中创建TodoService接口:

 

这里我们添加了一个listAll  方法,它将返回Todo  对象的集合。在src / main / java / com / stackify / mongodb / services中使用  名为TodoServiceImpl的接口创建相应的实现 ,并将以下代码添加到其中:

 

请注意,此类使用@Service注释, 以向Spring指示它是一个将在其他位置自动连接的服务。我们也在 这里使用@Autowired注释让Spring 处理器  为我们实例化TodoRepository。我们使用todo存储库的自动实现的findAll  方法来检索所有现有的待办事项。我们现在只需进行一些其他更改即可在视图中显示待办事项。说到这个观点,让我们现在更新。

最初我们创建了一个简单的HTML文件,其中没有任何动态数据。现在,我们将使用Thymeleaf模板语言创建一个表格,显示我们的待办事项的名称及其完成状态。完成的index.html  如下所示:

 

我们使用“if”语句来检查todos  属性是否为空。如果此属性不为空,则我们创建一个表并使用Thymeleaf循环迭代todos集合中的每个项目。集合中的每个项目在表格中都有一行,其中包含其名称和完成状态。

现在,如果你想知道todos  属性来自何处以及它如何进入我们的视图,这是因为我们尚未修改TodoController  。打开 我们在文章开头创建的TodoController。我们需要更新索引  方法,将todos  属性添加到视图使用的模型中。我们还需要将TodoService自动连接到控制器中。进行以下更改以获得以下控制器更新:

 

在我们更新的索引方法中,我们调用我们的todo服务的listAll  方法并将此集合映射到todos  密钥。这就是我们将todo域对象列表传递到视图中的方法。重新启动应用程序并刷新浏览器。我们的待办事项现在显示在我们的索引页面上:1539766446(1).jpg

虽然它没什么特别的,但这是一个成功的测试,我们所有的代码都在运行。此时我们已经创建并更新了不少文件。作为参考,这是我们现在应该拥有的项目结构:1539766621(1).jpg

我们在本文中介绍了很多内容。既然我们已经掌握了所有这些管道,那么在这里退出它就会感到羞耻。让我们再添加一个所需的功能。如果我们没有办法将项目标记为已完成,则todo系统不是非常有效。让我们添加将待办事项标记为已完成的功能,并查看我们如何更新MongoDB域对象。

更新和保存我们的Todo对象

值得庆幸的是,我们不会在这里创建任何新文件。我们只需要更新视图,控制器和服务。首先,让我们从更新视图开始。让我们保持简单,只需使用链接将待办事项标记为已完成。以下index.html  文件是我们的更新视图,其中包含每行将对/ todo / complete  端点具有的操作链接的新列。继续并立即更新视图:

 

在这里,我们使用Todo  域对象 上的toHexString属性将todo项的标识符传递给我们的/ todo / complete  URL端点。我们现在需要使用新方法更新控制器以处理此URL操作。打开TodoController  并将其替换为以下内容:

 

该@GetMapping  表示该端点将只对HTTP GET请求作出响应,并预计标识要传递给它。我们使用尚未将要实现的getById  我们的方法TodoService  检索具有相应标识的ToDo对象。如果找到一个,我们将其completed属性设置为True,然后调用saveOrUpdate  服务方法并将更新的todo对象传递给它。我们需要实现这两种方法来完成我们的功能。
通过更新启动TodoService  与两个新的方法,接口getById  和saveOrUpdate。确保他们具有以下方法签名:

 

现在,更新相应的实现类TodoServiceImpl:

 

由于自动连接和Spring Data CRUD魔术,我们不必编写任何代码来实际处理MongoDB数据库。只要我们处理日常的CRUD操作,这些都是为我们实现的。在我们的应用程序中,我们现在可以单击特定待办事项的完整链接。这将更新其已完成的属性并将我们重定向回列表。1539766845(1).jpg我们可以通过查看日志消息来验证控制台中的更新。在这里,我们可以验证todo项目是否已更新:

 

下一步

在这一点上,我们使用Spring Boot和MongoDB的嵌入式实例创建了一个非常简单的todo应用程序。虽然它不会赢得任何设计奖项,但我们的应用程序是进一步实验的良好起点。例如,删除待办事项或编辑现有待办事项的能力将是熟悉Spring Data和MongoDB的好方法。作为一个额外的好处,所有这些代码将继续使用完整的MongoDB安装。您只需更改配置即可。

MongoDB不是解决所有问题的解决方案。在切换到完全不同的数据库实现之前,您需要考虑应用程序需求。如果您正在处理非常大的数据集,以及缩放和聚类时,MongoDB非常适合。但是,如果您的应用程序使用高度结构化的数据,那么最好坚持使用关系数据库系统。

正如本文开头所提到的,如果您遇到任何问题或者只是想克隆它并玩游戏,可以在GitHub上找到所有这些代码。