构建 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!"}

所需条件

  • 大约15分钟。
  • 喜欢的文本编辑器或 IDE。
  • Java 17或以上版本。
  • Gradle 7.5+或 Maven 3.5+。
  • 也可以直接将代码导入 Spring Tool Suite(STS)、IntelliJ IDEA 或 VSCode。

如何完成指南

与大多数 Spring 入门指南一样,可以从零开始逐步完成,也可以跳过熟悉的基础设置。两种方式都得到可工作的代码。

从零开始,请进入“使用 Spring Initializr”。如果跳过基础设置:

  1. 下载并解压 源码仓库,或使用 Git 克隆: git clone https://github.com/spring-guides/gs-rest-service.git
  2. 进入 gs-rest-service/initial。
  3. 从“创建资源表示类”继续。

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

使用 Spring Initializr

可以使用原文链接的预初始化项目,点击 Generate 下载 ZIP。项目已配置为适配本教程。

手动初始化:

  1. 打开 Spring Initializr。它会引入所需依赖,并完成大部分设置。
  2. 选择 Gradle 或 Maven,以及希望使用的语言。
  3. 在 Artifact 字段填写 rest-service。
  4. 点击 Dependencies,选择 Spring Web。
  5. 点击 Generate。
  6. 下载生成的 ZIP,其中包含按所选配置创建的 Web 应用。

如果 IDE 集成 Spring Initializr,也可以直接在 IDE 中完成。还可以在 GitHub 上 fork 项目,用 IDE 或其他编辑器打开。

创建资源表示类

项目和构建系统设置完成后,就可以创建 Web 服务。先考虑服务交互方式。

服务处理对 /greeting 的 GET 请求,可选接收查询字符串中的 name。响应应为 200 OK,正文包含问候语的 JSON,例如:

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

id 是问候语的唯一标识符,content 是文字内容。

创建资源表示类,建模这两个字段。Java 使用 record,文件为 src/main/java/com/example/restservice/Greeting.java:

package com.example.restservice;

public record Greeting(long id, String content) { }

Kotlin 使用 data class,文件为 src/main/kotlin/com/example/restservice/Greeting.kt:

package com.example.restservice

data class Greeting(val id: Long, val content: String)

应用通过 Jackson JSON 库自动将 Greeting 实例转换为 JSON。Web starter 默认包含 Jackson。

创建资源控制器

在 Spring 的 RESTful Web 服务中,HTTP 请求由控制器处理。控制器由 @RestController 标识。下面的 GreetingController 处理 /greeting 的 GET 请求,并返回新的 Greeting 实例。

Java 文件为 src/main/java/com/example/restservice/GreetingController.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 文件为 src/main/kotlin/com/example/restservice/GreetingController.kt:

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 绑定到方法的 name 参数。请求缺少参数时,使用默认值 World。
  • 方法使用计数器的下一个值作为 id,用问候模板格式化传入的名称作为 content,创建并返回 Greeting。

传统 MVC 控制器与这个 RESTful 服务控制器的关键差别,在于响应正文的生成方式。这个控制器不依赖视图技术在服务器端把问候数据渲染为 HTML,而是填充并返回 Greeting 对象,再直接写入 JSON 响应。

@RestController 表示类中的方法返回领域对象而非视图,它是同时使用 @Controller 和 @ResponseBody 的简写。

Greeting 必须转换为 JSON。Spring 的 HTTP 消息转换器使你无需手工转换。由于 Jackson 位于类路径,Spring 自动选择 JacksonJsonHttpMessageConverter 转换实例。

运行服务

Spring Initializr 会创建应用类,本例无需进一步修改。

Java 文件为 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);
  }

}

Kotlin 文件为 src/main/kotlin/com/example/restservice/RestServiceApplication.kt:

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:根据类路径、其他 bean 和属性设置添加 bean。例如,存在 spring-webmvc 时,把应用识别为 Web 应用并配置 DispatcherServlet 等核心行为。
  • @ComponentScan:查找 com/example 包中的组件、配置和服务,从而发现控制器。

main() 用 SpringApplication.run() 启动应用。没有任何 XML,也没有 web.xml;这个 Web 应用完全使用 Java,不必手动配置底层设施。

构建可执行 JAR

可从命令行通过 Gradle 或 Maven 运行,也可构建包含全部依赖、类和资源的可执行 JAR。单个可执行 JAR 便于在开发生命周期中跨环境分发、版本管理和部署。

Gradle 运行:./gradlew bootRun。也可用 ./gradlew build 构建,然后:

java -jar build/libs/gs-rest-service-0.0.1-SNAPSHOT.jar

Maven 运行:./mvnw spring-boot:run。也可用 ./mvnw clean package 构建,然后:

java -jar target/gs-rest-service-0.0.1-SNAPSHOT.jar

会显示日志输出,服务应在数秒内启动。

测试服务

启动后访问 http://localhost:8080/greeting,应看到:

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

访问 http://localhost:8080/greeting?name=User,传入查询参数后,content 从 Hello, World! 变为 Hello, User!:

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

这展示了 GreetingController 中 @RequestParam 的工作方式:默认名称为 World,也可由查询参数覆盖。

id 从1变为2,表明多个请求由同一个 GreetingController 实例处理,其 counter 按预期在每次调用时递增。

完成与延伸阅读

你已经使用 Spring 创建了 RESTful Web 服务。原文还列出这些相关指南:通过 REST 访问 GemFire、MongoDB、JPA、Neo4j 数据;使用 MySQL 访问数据;消费 RESTful 服务及其 AngularJS、jQuery、rest.js 示例;保护 Web 应用;构建 REST 服务;React.js 与 Spring Data REST;Spring Boot 应用;Restdocs API 文档;跨域请求;超媒体驱动的 REST 服务;Circuit Breaker。各指南链接请从原文“See Also”进入。

如想撰写新指南或参与已有指南,请参阅原文贡献指南。


原文:Building a RESTful Web Service;作者/来源:Spring Guides。本文为中文译稿,代码与示例输出保留原文,未在本环境运行 Java、Kotlin 或构建命令。
原文明确:代码采用 ASLv2(Apache License 2.0);文字采用 Attribution, NoDerivatives Creative Commons 许可。NoDerivatives 不自动授予公开分享译文的权利;本任务中用户已明确授权本批汉化转载,该额外授权的权利人来源与范围需在实际发布前核验。
Spring、Java、Windows、Microsoft Azure、AWS、Amazon Web Services 等商标归各自权利人所有。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容