调用 RESTful Web Service

本指南将引导您完成创建一个调用 RESTful web service 的应用的过程。

您将构建什么

您将构建一个应用,该应用使用 Spring 的 RestTemplatehttp://localhost:8080/api/random 获取一个随机的 Spring Boot 引用。

您需要什么

如何完成本指南

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

从头开始,请转到从 Spring Initializr 开始

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

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

从 Spring Initializr 开始

您可以使用这个预初始化的项目,然后点击 Generate 下载 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 service 的简单应用。

在此之前,您需要一个 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 个)。

如果您通过 web 浏览器或 curl 请求该 URL,您将收到一个类似如下的 JSON 文档

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

这足够简单,但通过浏览器或 curl 获取时并不是特别有用。

更实用的调用 REST web service 的方法是编程方式。为了帮助您完成此任务,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) { }

这个简单的 Java 记录类使用 Jackson JSON 处理库的 @JsonIgnoreProperties 注解,表明应该忽略此类型中未绑定的任何属性。

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

您还需要一个额外的类,用于嵌入内部引用本身。Value 记录类满足了这一需求,并在以下清单中显示(位于 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) { }

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

完成应用

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);
	}

}

现在您需要向 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());
		};
	}
}

最后,您需要设置服务器端口。quoter 应用使用了默认的服务器端口 8080,因此本应用不能再使用同一个端口。您可以通过在应用属性文件(Initializr 为您创建的)中添加以下行将服务器端口设置为 8081

server.port=8081

运行应用

您可以从命令行使用 Gradle 或 Maven 运行该应用。您也可以构建一个包含所有必需依赖项、类和资源的单个可执行 JAR 文件,并运行它。构建可执行 JAR 可以轻松地在整个开发生命周期、跨不同环境等阶段,将服务作为应用进行分发、版本管理和部署。

如果您使用 Gradle,可以使用 ./gradlew bootRun 运行应用。或者,您可以使用 ./gradlew build 构建 JAR 文件,然后按如下方式运行 JAR 文件:

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

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

java -jar target/gs-consuming-rest-0.1.0.jar
此处描述的步骤会创建一个可运行的 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.'}}
如果您看到类似这样的错误:Could not extract response: no suitable HttpMessageConverter found for response type [class com.example.consumingrest.Quote],则可能是您所处的环境无法连接到后端服务(如果您能连接到它,它会发送 JSON)。也许您在公司代理后面。请尝试将 http.proxyHosthttp.proxyPort 系统属性设置为适合您环境的值。

总结

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

获取代码