1.目标
构建一个服务,该服务将接受来自http://localhost:8080/greeting的HTTP GET请求。它将以JSON表示形式响应问候语,如下所示:
{"id":1,"content":"Hello, World!"}
你可以在查询字符串中使用可选的名称参数来自定义问候语,如下所示:
http://localhost:8080/greeting?name=User
name参数值覆盖了默认的World值,并在响应中反映出来,如下所示:
{"id":1,"content":"Hello, User!"}
2.准备工作
- 大约15分钟
- 一个喜欢的文本编辑器或IDE
- Java 17或更高版本
- Gradle 7.5+或Maven 3.5+
- 您还可以直接将代码导入到您的IDE中:
- Spring Tool Suite(STS)
- IntelliJ IDEA
- VSCode
我使用的是Java17,Maven3.8.3,IDE使用的是Jetbrain的IDEA
3.如何完成这个demo?
像大多数Spring入门指南一样,你可以从头开始完成每个步骤,或者跳过对你已经熟悉的基本设置步骤。无论哪种方式,最终都会得到可工作的代码。
要从头开始,请继续使用Spring Initializr进行起步。
要跳过基础知识,请执行以下操作:
- 下载并解压此指南的源代码库,或使用Git克隆它:git clone https://github.com/spring-guides/gs-rest-service.git
- cd 进入gs-rest-service/initial目录
- 跳转到创建资源表示类部分。完成后,你可以将结果与gs-rest-service/complete中的代码进行比较。
这里我选择的是从头开始
4.从Spring Initializr开始
你可以使用此预初始化项目并单击“生成”以下载ZIP文件。该项目已配置为适用于本教程中的示例。
要手动初始化项目:
- 导航到https://start.spring.io。该服务会引入您应用程序所需的所有依赖项,并为您完成大部分设置工作。
- 选择Gradle或Maven和您想要使用的语言。本指南假设您选择了Java语言。
- 单击“Dependencies”并选择Spring Web。
- 单击“Generate”。
- 下载结果ZIP文件,这是一个根据您的选择进行配置的Web应用程序存档文件。
5.创建一个资源表示类
如果已经设置好了项目和构建系统,现在可以创建自己的网络服务。
开始这个过程时,请考虑服务之间的交互。
该服务将处理对于/greeting
的GET
请求,可选择性地在查询字符串中包含一个名字参数。GET
请求应该返回一个200 OK
响应,并在正文中以JSON格式表示问候语。它应该类似于以下输出:
{
"id": 1,
"content": "Hello, World!"
}
id字段是问候的唯一标识符,content是问候的文本表示。
为了建模问候表示,创建一个资源表示类。
为此,请提供一个Java记录类来处理id和content数据,如下面的清单所示(来自src/main/java/com/example/restservice/Greeting.java)。
package com.example.restservice;
public record Greeting(long id, String content) { }
该应用程序使用Jackson JSON库将Greeting类型的实例自动转换为JSON。 Jackson默认由Web启动器包含在内。
6.创建一个资源Controller
在Spring构建RESTful Web服务的方法中,HTTP请求由控制器处理。这些组件通过@RestController注解进行标识,在以下清单(来自src/main/java/com/example/restservice/GreetingController.java)中显示的GreetingController处理对/greeting的GET请求,并返回Greeting类的新实例:
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注释确保将对/greeting的HTTP GET请求映射到greeting()方法。
有其他HTTP动词的伴随注解(例如,@PostMapping用于POST)。还有一个@RequestMapping注解,它们都是从中派生出来的,并且可以作为同义词使用(例如,@RequestMapping(method=GET))。
@RequestParam将查询字符串参数name的值绑定到greeting()方法的name参数。如果请求中缺少name参数,则使用默认值World。
该方法体的实现根据计数器的下一个值创建并返回一个具有id和content属性的新Greeting对象,并使用问候模板格式化给定的名称。
传统MVC控制器和之前展示的RESTful Web服务控制器之间一个关键区别是如何创建HTTP响应体。这个RESTful Web服务控制器不依赖于视图技术来对问候数据进行服务器端渲染生成HTML,而是填充并返回一个Greeting对象。对象数据将直接以JSON形式写入HTTP响应中。
此代码使用Spring @RestController注解,将类标记为每个方法都返回域对象而不是视图。它相当于同时包含@Controller和@ResponseBody两个注解。
必须将Greeting对象转换为JSON格式。由于Jackson 2在类路径上,所以Spring会自动选择MappingJackson2HttpMessageConverter来将Greeting实例转换为JSON格式,无需手动进行转换。
@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的,你不需要处理任何管道或基础设施配置。
7.构建一个可执行的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
显示日志输出。服务应在几秒钟内启动并运行。
这里可以直接使用IDEA进行run起来。与./mvnw spring-boot:run效果一样。执行./mvnw clean package之后会生成jar文件,这里我生成的文件名称是
rest-service-0.0.1-SNAPSHOT.jar
与pom.xml中的声明有关.
<groupId>com.example</groupId>
<artifactId>rest-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rest-service</name>
<description>Demo project for Spring Boot</description>
8.测试服务
现在服务已经启动,请访问http://localhost:8080/greeting,在这里你应该能看到:
{"id":1,"content":"Hello, World!"}
通过访问http://localhost:8080/greeting?name=User提供一个名字查询字符串参数。注意到内容属性的值从Hello, World!变为Hello, User!,如下所示:
{"id":2,"content":"Hello, User!"}
这个变化表明GreetingController中的@RequestParam安排按预期工作。name参数已经被赋予了默认值World,但可以通过查询字符串显式地覆盖。
还要注意id属性从1变为2。这证明您在多个请求中使用同一个GreetingController实例,并且它的counter字段如预期般在每次调用时递增。