使用 REST 访问 MongoDB 数据

本指南将指导你完成创建应用程序的过程,该应用程序通过基于超媒体的 RESTful 前端访问基于文档的数据。

你将构建什么

你将构建一个 Spring 应用程序,它允许你创建和检索存储在 MongoDB NoSQL 数据库中的 Person 对象,方法是使用 Spring Data REST。Spring Data REST 采用了 Spring HATEOASSpring Data MongoDB 的特性,并自动将它们组合在一起。

Spring Data REST 还支持 Spring Data JPASpring Data GemfireSpring Data Neo4j 作为后端数据存储,但这些不属于本指南的一部分。

你需要什么

如何完成本指南

与大多数 Spring 入门指南 一样,你可以从头开始完成每一步,或者你可以跳过你已经熟悉的设置步骤。无论哪种方式,你最终都会得到可用的代码。

从头开始,请继续 使用 Spring Initializr 开始

跳过基础知识,请执行以下操作

完成后,你可以将你的结果与 gs-accessing-mongodb-data-rest/complete 中的代码进行对比。

使用 Spring Initializr 开始

你可以使用这个 预初始化项目,然后点击生成以下载一个 ZIP 文件。此项目已配置为适合本教程中的示例。

手动初始化项目

  1. 导航到 https://start.spring.io。此服务会提取应用程序所需的所有依赖项,并为你完成大部分设置。

  2. 选择 Gradle 或 Maven 以及你想要使用的语言。本指南假设你选择了 Java。

  3. 点击 依赖项,然后选择 Rest 存储库Spring Data MongoDB

  4. 点击 生成

  5. 下载生成的 ZIP 文件,它是一个已根据你的选择配置的 Web 应用程序的存档。

如果你的 IDE 集成了 Spring Initializr,则可以从你的 IDE 完成此过程。
你还可以从 Github 分叉项目,并在你的 IDE 或其他编辑器中打开它。

安装并启动 MongoDB

要让本指南正常工作,你必须启动一个本地 MongoDB 服务器。

在已安装 Homebrew 的 Mac OS X 机器上,运行以下命令

brew install mongodb

你可以在 https://docs.mongodb.org/manual/installation/ 找到更多安装选项。

安装 MongoDB 后,你需要启动 mongo 守护进程。在 Mac 上,你可以使用以下命令

$ mongod
all output going to: /usr/local/var/log/mongodb/mongo.log

你可以通过运行 mongo 命令从另一个终端窗口启动 MongoDB 客户端。

创建域对象

创建一个新的域对象来表示一个人,如下面的示例(在 src/main/java/com/example/accessingmongodbdatarest/Person.java)所示

package com.example.accessingmongodbdatarest;

import org.springframework.data.annotation.Id;

public class Person {

  @Id private String id;

  private String firstName;
  private String lastName;

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
}

Person 对象有一个名字和一个姓氏。(还有一个 ID 对象,它被配置为自动生成,因此不必处理它。)

创建人员存储库

接下来,你需要创建一个简单的存储库,如下面的清单(在 src/main/java/com/example/accessingmongodbdatarest/PersonRepository.java)所示

package com.example.accessingmongodbdatarest;

import java.util.List;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends MongoRepository<Person, String> {

  List<Person> findByLastName(@Param("name") String name);

}

此存储库是一个接口,可让你执行涉及 Person 对象的各种操作。它通过扩展 MongoRepository 来获取这些操作,而 MongoRepository 又扩展了 Spring Data Commons 中定义的 PagingAndSortingRepository 接口。

在运行时,Spring Data REST 会自动创建此接口的一个实现。然后,它使用 @RepositoryRestResource 注解来指示 Spring MVC 在 /people 处创建 RESTful 端点。

@RepositoryRestResource 不是存储库导出所必需的。它仅用于更改导出详细信息,例如使用 /people 而不是默认值 /persons

此处你还定义了一个自定义查询,以基于 lastName 值检索 Person 对象的列表。你可以在本指南的后面部分了解如何调用它。

默认情况下,Spring Boot 会尝试连接到本地托管的 MongoDB 实例。阅读 参考文档,了解如何将你的应用程序指向托管在其他位置的 MongoDB 实例。

@SpringBootApplication 是一个便捷注解,它添加了以下所有内容

  • @Configuration:将类标记为应用程序上下文的 bean 定义源。

  • @EnableAutoConfiguration:告诉 Spring Boot 根据类路径设置、其他 bean 和各种属性设置开始添加 bean。例如,如果类路径中存在 spring-webmvc,此注解会将应用程序标记为 Web 应用程序并激活关键行为,例如设置 DispatcherServlet

  • @ComponentScan:告诉 Spring 在 com/example 包中查找其他组件、配置和服务,以便它找到控制器。

main() 方法使用 Spring Boot 的 SpringApplication.run() 方法启动应用程序。你是否注意到没有一行 XML?也没有 web.xml 文件。此 Web 应用程序是 100% 纯 Java,而且你无需处理任何管道或基础设施的配置。

构建可执行 JAR

你可以使用 Gradle 或 Maven 从命令行运行应用程序。你还可以构建一个包含所有必需的依赖项、类和资源的可执行 JAR 文件并运行该文件。构建可执行 jar 使得在整个开发生命周期、不同环境中轻松地交付、版本化和部署服务作为应用程序,等等。

如果你使用 Gradle,则可以使用 ./gradlew bootRun 运行应用程序。或者,你可以使用 ./gradlew build 构建 JAR 文件,然后运行 JAR 文件,如下所示

java -jar build/libs/gs-accessing-mongodb-data-rest-0.1.0.jar

如果您使用 Maven,可以使用 ./mvnw spring-boot:run 运行应用程序。或者,您可以使用 ./mvnw clean package 构建 JAR 文件,然后运行 JAR 文件,如下所示

java -jar target/gs-accessing-mongodb-data-rest-0.1.0.jar
此处描述的步骤创建可运行的 JAR。您还可以 构建经典 WAR 文件

显示日志输出。该服务应在几秒钟内启动并运行。

测试应用程序

现在应用程序正在运行,您可以对其进行测试。您可以使用任何您希望的 REST 客户端。以下示例使用 *nix 工具 curl

首先,您希望看到顶级服务,如下例所示

$ curl https://127.0.0.1:8080
{
  "_links" : {
    "people" : {
      "href" : "https://127.0.0.1:8080/people{?page,size,sort}",
      "templated" : true
    }
  }
}

前面的示例提供了此服务器提供内容的初步了解。有一个位于 https://127.0.0.1:8080/peoplepeople 链接。它有一些选项,例如 ?page?size?sort

Spring Data REST 使用 HAL 格式 作为 JSON 输出。它很灵活,并提供了一种方便的方式来提供与所提供数据相邻的链接。

当您使用 people 链接时,您将在数据库中看到 Person 记录(目前没有)

$ curl https://127.0.0.1:8080/people
{
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "https://127.0.0.1:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

当前没有元素,因此没有页面。现在是时候创建一个新的 Person 了!

如果您多次运行此指南,可能会留下剩余数据。请参阅 MongoDB shell 快速参考,了解在需要重新开始时查找和删除数据库的命令。

以下命令创建了一个名为“Frodo Baggins”的人

$ curl -i -X POST -H "Content-Type:application/json" -d "{  \"firstName\" : \"Frodo\",  \"lastName\" : \"Baggins\" }" https://127.0.0.1:8080/people
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: https://127.0.0.1:8080/people/53149b8e3004990b1af9f229
Content-Length: 0
Date: Mon, 03 Mar 2014 15:08:46 GMT
  • -i:确保您可以看到包括标头的响应消息。将显示新创建的 Person 的 URI。

  • -X POST:表示这是一个用于创建新条目的 POST

  • -H "Content-Type:application/json":设置内容类型,以便应用程序知道有效负载包含一个 JSON 对象。

  • -d '{ "firstName" : "Frodo", "lastName" : "Baggins" }':是要发送的数据。

请注意,前面的 POST 操作如何包括一个 Location 标头。其中包含新创建的资源的 URI。Spring Data REST 还有两种方法(RepositoryRestConfiguration.setReturnBodyOnCreate(…)setReturnBodyOnUpdate(…)),您可以使用它们来配置框架以立即返回刚创建/更新的资源的表示。

通过此操作,您可以查询所有人员,如下例所示

$ curl https://127.0.0.1:8080/people
{
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "https://127.0.0.1:8080/people/search"
    }
  },
  "_embedded" : {
    "persons" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "https://127.0.0.1:8080/people/53149b8e3004990b1af9f229"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

persons 对象包含一个包含弗罗多的列表。请注意,它包含一个 self 链接。Spring Data REST 还使用 Evo Inflector 对分组的实体名称进行复数化。

您可以直接查询单个记录,如下例所示

$ curl https://127.0.0.1:8080/people/53149b8e3004990b1af9f229
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/people/53149b8e3004990b1af9f229"
    }
  }
}
这似乎完全基于 Web,但实际上它正在与您启动的 MongoDB 数据库进行通信。

在本指南中,只有一个域对象。对于域对象相互关联的更复杂系统,Spring Data REST 会呈现其他链接以帮助导航到连接的记录。

查找所有自定义查询,如下例所示

$ curl https://127.0.0.1:8080/people/search
{
  "_links" : {
    "findByLastName" : {
      "href" : "https://127.0.0.1:8080/people/search/findByLastName{?name}",
      "templated" : true
    }
  }
}

您可以看到查询的 URL,包括 HTTP 查询参数 name。这与嵌入在接口中的 @Param("name") 注释相匹配。

要使用 findByLastName 查询,请运行以下命令

$ curl https://127.0.0.1:8080/people/search/findByLastName?name=Baggins
{
  "_embedded" : {
    "persons" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "https://127.0.0.1:8080/people/53149b8e3004990b1af9f229"
        }
      }
    } ]
  }
}

由于您在代码中将其定义为返回 List<Person>,因此它会返回所有结果。如果您已将其定义为仅返回 Person,它会选择一个 Person 对象进行返回。由于这不可预测,因此您可能不想对可以返回多个条目的查询执行此操作。

您还可以发出 PUTPATCHDELETE REST 调用以分别替换、更新或删除现有记录。以下示例使用 PUT 调用

$ curl -X PUT -H "Content-Type:application/json" -d "{ \"firstName\": \"Bilbo\", \"lastName\": \"Baggins\" }" https://127.0.0.1:8080/people/53149b8e3004990b1af9f229
$ curl https://127.0.0.1:8080/people/53149b8e3004990b1af9f229
{
  "firstName" : "Bilbo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/people/53149b8e3004990b1af9f229"
    }
  }
}

以下示例使用 PATCH 调用

$ curl -X PATCH -H "Content-Type:application/json" -d "{ \"firstName\": \"Bilbo Jr.\" }" https://127.0.0.1:8080/people/53149b8e3004990b1af9f229
$ curl https://127.0.0.1:8080/people/53149b8e3004990b1af9f229
{
  "firstName" : "Bilbo Jr.",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/people/53149b8e3004990b1af9f229"
    }
  }
}
PUT 替换整个记录。未提供字段将被替换为 null。您可以使用 PATCH 更新项目子集。

您还可以删除记录,如下例所示

$ curl -X DELETE https://127.0.0.1:8080/people/53149b8e3004990b1af9f229
$ curl https://127.0.0.1:8080/people
{
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "https://127.0.0.1:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

超媒体驱动接口 的一个便利方面是,您可以使用 curl(或您喜欢的任何 REST 客户端)发现所有 RESTful 端点。无需与客户交换正式合同或接口文档。

摘要

恭喜!您刚刚开发了一个应用程序,该应用程序具有基于 超媒体 的 REST 前端和基于 MongoDB 的后端。

获取代码