Spring Boot 与 Docker
观察 GraphQL 的实际运行

本指南将引导您完成创建一个消费 RESTful Web 服务的应用程序的过程。

您将构建什么

您将构建一个应用程序,该应用程序使用 Spring 的 RestTemplatehttp://localhost:8080/api/random 上检索随机的 Spring Boot 引用。

所需内容

如何完成本指南

像大多数 Spring 入门指南一样,您可以从头开始并完成每个步骤,也可以跳过您已经熟悉的基本设置步骤。无论哪种方式,您最终都会得到可运行的代码。

从头开始,请继续阅读从 Spring Initializr 开始

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

完成之后,您可以对照 gs-consuming-rest/complete 中的代码检查您的结果。

从 Spring Initializr 开始

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

要手动初始化项目:

  1. 访问 https://start.spring.io。该服务会拉取应用程序所需的所有依赖项,并为您完成大部分设置。
  2. 选择 Gradle 或 Maven 以及您想要使用的语言。本指南假设您选择了 Java。
  3. 点击 Dependencies 并选择 Spring Web
  4. 点击 Generate
  5. 下载生成的 ZIP 文件,这是一个根据您的选择配置好的 Web 应用程序存档。

如果您的 IDE 集成了 Spring Initializr,您可以直接在 IDE 中完成这个过程。

您还可以从 Github 上 fork 这个项目,并在您的 IDE 或其他编辑器中打开它。

获取 REST 资源

完成项目设置后,您可以创建一个简单的应用程序来消费 RESTful 服务。

在此之前,您需要一个 REST 资源的来源。我们在 https://github.com/spring-guides/quoters 提供了一个这样的服务示例。您可以在单独的终端中运行该应用程序,并通过 http://localhost:8080/api/random 访问结果。该地址会随机获取一条关于 Spring Boot 的引用,并将其作为 JSON 文档返回。其他有效的地址包括 http://localhost:8080/api/(获取所有引用)和 http://localhost:8080/api/1(获取第一条引用)、http://localhost:8080/api/2(获取第二条引用),依此类推(目前最多 10 条)。

如果您通过网页浏览器或 curl 请求该 URL,您将收到一个类似这样的 JSON 文档:

{
   type: "success",
   value: {
      id: 10,
      quote: "Really loving Spring Boot, makes stand alone Spring apps easy."
   }
}
Plain text

虽然通过浏览器或curl获取数据足够简单,但这种方式并不太实用。

更实用的方式是通过编程来使用REST Web服务。为了帮助您完成这项任务,Spring提供了一个方便的模板类,称为RestTemplateRestTemplate使得与大多数RESTful服务的交互变得只需一行代码即可完成。它甚至可以将数据绑定到自定义的领域类型上。

首先,您需要创建一个领域类来包含所需的数据。以下清单展示了Quote记录类,您可以将其用作领域类:

src/main/java/com/example/consumingrest/Quote.java

package com.example.consumingrest;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public record Quote(String type, Value value) { }
Plain text

这个简单的 Java record 类使用了来自 Jackson JSON 处理库的 @JsonIgnoreProperties 注解,以指示应忽略未在此类型中绑定的任何属性。

要将数据直接绑定到您的自定义类型,您需要将变量名称指定为与 API 返回的 JSON 文档中的键完全相同。如果您的变量名称与 JSON 文档中的键不匹配,您可以使用 @JsonProperty 注解来指定 JSON 文档的确切键。(此示例将每个变量名称与 JSON 键匹配,因此此处不需要该注解。)

您还需要一个额外的类来嵌入内部引语本身。Value record 类满足了这一需求,并在以下列表(位于 src/main/java/com/example/consumingrest/Value.java)中展示:

package com.example.consumingrest;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public record Value(Long id, String quote) { }
Plain text

这使用了相同的注解但映射到其他数据字段上。

完成应用程序

Initializr 创建了一个包含 main() 方法的类。以下清单展示了 Initializr 创建的类(位于 src/main/java/com/example/consumingrest/ConsumingRestApplication.java):

package com.example.consumingrest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConsumingRestApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumingRestApplication.class, args);
    }

}
Plain text

现在您需要向ConsumingRestApplication类中添加一些其他内容,以便它能够显示来自我们 RESTful 源的引用。您需要添加:

  • 一个 logger,用于将输出发送到日志(在本例中为控制台)。

  • 一个 RestTemplate,它使用 Jackson JSON 处理库来处理传入的数据。

  • 一个 CommandLineRunner,它在启动时运行 RestTemplate(从而获取我们的引用)。

下面的代码清单展示了完成的 ConsumingRestApplication 类(位于 src/main/java/com/example/consumingrest/ConsumingRestApplication.java):

package com.example.consumingrest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class ConsumingRestApplication {

    private static final Logger log = LoggerFactory.getLogger(ConsumingRestApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(ConsumingRestApplication.class, args);
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }

    @Bean
    @Profile("!test")
    public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
        return args -> {
            Quote quote = restTemplate.getForObject(
                    "http://localhost:8080/api/random", Quote.class);
            log.info(quote.toString());
        };
    }
}
Plain text

最后,您需要设置服务器端口。quotes 应用程序使用了默认的服务器端口 8080,因此这个应用程序不能使用相同的端口。您可以通过在 application properties 文件中(该文件由 Initializr 为您创建)添加以下行来将服务器端口设置为 8081:

server.port=8081
Plain text

运行应用程序

您可以使用 Gradle 或 Maven 从命令行运行应用程序。您还可以构建一个包含所有必要依赖项、类和资源的单个可执行 JAR 文件并运行它。构建可执行的 JAR 文件可以轻松地在整个开发生命周期中、跨不同环境等作为应用程序进行交付、版本控制和部署。

如果您使用 Gradle,可以通过 ./gradlew bootRun 来运行应用程序。或者,您可以使用 ./gradlew build 构建 JAR 文件,然后运行该 JAR 文件,如下所示:

java -jar build/libs/gs-consuming-rest-0.1.0.jar
Plain text

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

java -jar target/gs-consuming-rest-0.1.0.jar
Plain text

这里描述的步骤会创建一个可运行的 JAR 文件。您也可以构建一个经典的 WAR 文件

您应该会看到类似于以下的输出,但会包含一个随机的引文:

2019-08-22 14:06:46.506  INFO 42940 --- [           main] c.e.c.ConsumingRestApplication           : Quote{type='success', value=Value{id=1, quote='Working with Spring Boot is like pair-programming with the Spring developers.'}}
Plain text

如果您看到错误信息显示为 Could not extract response: no suitable HttpMessageConverter found for response type [class com.example.consumingrest.Quote],这可能是因为您所处的环境无法连接到后端服务(如果您能访问,它会发送 JSON 数据)。也许您处于公司代理之后。尝试将 http.proxyHosthttp.proxyPort 系统属性设置为适合您环境的值。

总结

恭喜!您刚刚使用 Spring Boot 开发了一个简单的 REST 客户端。

另请参阅

以下指南也可能有所帮助: