构建 RESTful Web 服务

本指南将引导您完成使用 Spring 创建“Hello, World”RESTful Web 服务的流程。

您将构建什么

您将构建一个服务,该服务将接受 https://:8080/greeting 上的 HTTP GET 请求。

它将以问候语的 JSON 表示形式响应,如以下列表所示

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

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

https://:8080/greeting?name=User

name 参数值会覆盖 World 的默认值,并反映在响应中,如以下列表所示

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

你需要什么

如何完成本指南

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

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

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

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

从 Spring Initializr 开始

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

手动初始化项目

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

  2. 选择 Gradle 或 Maven 以及您想要使用的语言。

  3. 在“Artifact”表单字段中输入“rest-service”。

  4. 点击 Dependencies 并选择 Spring Web

  5. 单击生成

  6. 下载生成的 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 记录类或 Kotlin 数据类,如以下列表所示

Java
package com.example.restservice;

public record Greeting(long id, String content) { }
Kotlin
package com.example.restservice

data class Greeting(val id: Long, val content: String)
此应用程序使用 Jackson JSON 库自动将 Greeting 类型的实例编组为 JSON。Jackson 默认包含在 Web 启动器中。

创建资源控制器

在 Spring 构建 RESTful Web 服务的方法中,HTTP 请求由控制器处理。这些组件由 @RestController 注解标识,以下列表中所示的 GreetingController 类通过返回 Greeting 类的新实例来处理对 /greetingGET 请求

Java
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(defaultValue = "World") String name) {
		return new Greeting(counter.incrementAndGet(), template.formatted(name));
	}
}
Kotlin
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

private const val template = "Hello, %s!"

@RestController
class GreetingController {

    private val counter = AtomicLong()

    @GetMapping("/greeting")
    fun greeting(@RequestParam name: String = "World") =
        Greeting(counter.incrementAndGet(), template.format(name))

}

这个控制器简洁而简单,但其背后有很多事情发生。我们一步一步地进行分解。

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

还有其他 HTTP 动词的配套注解(例如,用于 POST 的 @PostMapping)。还有一个 @RequestMapping 注解,它们都派生自该注解,并且可以作为同义词(例如,@RequestMapping(method=GET))。

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

方法体的实现根据 counter 的下一个值创建并返回一个新的 Greeting 对象,其中包含 idcontent 属性,并使用问候语 template 格式化给定的 name

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

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

Greeting 对象必须转换为 JSON。多亏了 Spring 的 HTTP 消息转换器支持,您无需手动执行此转换。由于 Jackson 位于类路径上,Spring 的 JacksonJsonHttpMessageConverter 会自动选择用于将 Greeting 实例转换为 JSON。

运行服务

Spring Initializr 会为您创建一个应用程序类。在这种情况下,您无需进一步修改该类。以下列表显示了 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);
	}

}
Kotlin
package com.example.restservice

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class RestServiceApplication

fun main(args: Array<String>) {
	runApplication<RestServiceApplication>(*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 文件

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

测试服务

现在服务已启动,访问 https://:8080/greeting,您应该会看到

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

通过访问 https://: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