使用 REST 访问 MongoDB 数据

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

您将构建的内容

您将构建一个 Spring 应用程序,使用 Spring Data REST,允许您创建和检索存储在MongoDB NoSQL 数据库中的Person对象。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 RepositoriesSpring 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 对象,它被配置为自动生成,因此无需处理它。)

创建 Person 存储库

接下来,您需要创建一个简单的存储库,如下面的列表所示(在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/people处有一个people链接。它有一些选项,例如?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对象包含一个包含 Frodo 的列表。请注意它包含一个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的后端的应用程序。

获取代码