构建 RESTful Web 服务

本指南将引导你完成使用 Spring 创建一个“Hello, World”RESTful Web 服务的整个过程。

你将构建什么

你将构建一个服务,该服务将接受对 http://localhost:8080/greeting 的 HTTP GET 请求。

它将响应一个问候语的 JSON 表示,如下所示:

{"id":1,"content":"Hello, World!"}

你可以使用查询字符串中的可选 name 参数来自定义问候语,如下所示:

http://localhost:8080/greeting?name=User

name 参数的值将覆盖默认值 World 并反映在响应中,如下所示:

{"id":1,"content":"Hello, User!"}

你需要什么

如何完成本指南

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

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

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

完成时,你可以将你的结果与 gs-rest-service/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 或其他编辑器中打开。

创建资源表示类

现在你已经设置好项目和构建系统,可以创建你的 Web 服务了。

从思考服务交互开始。

该服务将处理对 /greetingGET 请求,可选地包含查询字符串中的 name 参数。GET 请求应返回一个 200 OK 响应,其正文包含代表问候语的 JSON。它应该类似于以下输出:

{
    "id": 1,
    "content": "Hello, World!"
}

id 字段是问候语的唯一标识符,而 content 是问候语的文本表示。

为了建模问候语表示,创建一个资源表示类。为此,提供一个用于 idcontent 数据的 Java record 类,如下面的列表(来自 src/main/java/com/example/restservice/Greeting.java)所示:

package com.example.restservice;

public record Greeting(long id, String content) { }
此应用程序使用 Jackson JSON 库自动将 Greeting 类型的实例编组(marshal)为 JSON。Jackson 默认包含在 Web Starter 中。

创建资源控制器

在 Spring 构建 RESTful Web 服务的方法中,HTTP 请求由控制器处理。这些组件通过 @RestController 注解标识,如下面列表所示的 GreetingController(来自 src/main/java/com/example/restservice/GreetingController.java)通过返回 Greeting 类的新实例来处理对 /greetingGET 请求:

package com.example.restservice;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

	private static final String template = "Hello, %s!";
	private final AtomicLong counter = new AtomicLong();

	@GetMapping("/greeting")
	public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
		return new Greeting(counter.incrementAndGet(), String.format(template, name));
	}
}

这个控制器简洁明了,但在底层做了很多工作。我们一步步来分析。

@GetMapping 注解确保 HTTP GET 请求到 /greeting 会映射到 greeting() 方法。

对于其他 HTTP 动词(例如 POST 的 @PostMapping)也有相应的注解。此外,还有一个 @RequestMapping 注解,所有这些注解都派生自它,并且可以作为同义词使用(例如 @RequestMapping(method=GET))。

@RequestParam 将查询字符串参数 name 的值绑定到 greeting() 方法的 name 参数。如果请求中缺少 name 参数,则使用默认值 World

方法体的实现基于 counter 的下一个值创建并返回一个新的 Greeting 对象,该对象具有 idcontent 属性,并使用问候语 template 格式化给定的 name

传统 MVC 控制器与前面所示的 RESTful Web 服务控制器之间的一个关键区别在于 HTTP 响应体的创建方式。RESTful Web 服务控制器不是依靠视图技术在服务器端将问候语数据渲染成 HTML,而是填充并返回一个 Greeting 对象。对象数据将直接作为 JSON 写入 HTTP 响应。

此代码使用了 Spring 的 @RestController 注解,它将类标记为控制器,其中每个方法都返回一个领域对象而不是视图。它是包含 @Controller@ResponseBody 的简写。

Greeting 对象必须转换为 JSON。得益于 Spring 的 HTTP 消息转换器支持,你无需手动执行此转换。由于 Jackson 2 存在于类路径中,Spring 的 MappingJackson2HttpMessageConverter 会自动选择来将 Greeting 实例转换为 JSON。

运行服务

Spring Initializr 会为你创建一个应用程序类。在这种情况下,你无需进一步修改该类。以下列表(来自 src/main/java/com/example/restservice/RestServiceApplication.java)显示了该应用程序类:

package com.example.restservice;

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

@SpringBootApplication
public class RestServiceApplication {

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

}

@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-rest-service-0.1.0.jar

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

java -jar target/gs-rest-service-0.1.0.jar
此处描述的步骤会创建一个可运行的 JAR。你也可以构建一个经典的 WAR 文件

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

测试服务

服务启动后,访问 http://localhost:8080/greeting,你应该会看到:

{"id":1,"content":"Hello, World!"}

通过访问 http://localhost:8080/greeting?name=User 提供一个 name 查询字符串参数。注意 content 属性的值如何从 Hello, World! 变为 Hello, User!,如下面列表所示:

{"id":2,"content":"Hello, User!"}

此更改表明 GreetingController 中的 @RequestParam 配置按预期工作。name 参数已指定默认值 World,但可以通过查询字符串显式覆盖。

同时注意 id 属性如何从 1 变为 2。这证明你在多个请求中使用的是同一个 GreetingController 实例,并且它的 counter 字段在每次调用时都按预期递增。

总结

恭喜!你刚刚使用 Spring 开发了一个 RESTful Web 服务。

获取代码

免费

在云端工作

在 Spring Academy 云环境中完成本指南。

前往 Spring Academy