Spring Boot REST API 教程,第 2 部分:添加 GET 和 DELETE 端点
从 Spring Boot REST API 教程,第 1 部分:创建并运行项目 继续项目。 在本部分中,添加一个照片模型、一个将照片存储在内存中的服务,以及用于列出、检索和删除照片的端点。
创建 Photo 模型类
问候端点返回字符串,但照片端点需要处理结构化数据。 Photo 在 Java 中表示该数据。 先包含一个标识符和一个文件名称;在下一部分添加上传功能时,图像字节会随之到来。
在 model 软件包中,创建一个名为
Photo的类,其中包含一个标识符、一个文件名称和两个构造函数:public class Photo { private String id; private String fileName; public Photo() { } public Photo(String id, String fileName) { this.id = id; this.fileName = fileName; } }双实参构造函数会创建下面使用的示例照片。 无实参构造函数会在下一部分添加上传的照片时使用。
为两个字段生成访问器:将文本光标放在类中,按 Alt+Insert ,选择 Getter 和 Setter ,然后选择两个字段,并点击 OK。

Spring 使用 Jackson 将端点返回的照片转换为 JSON。 Jackson 通过 getter 读取照片属性,因此 JSON 响应包含
id和fileName。 这些 setter 可用于在创建照片时分配这些值。
创建并注入照片服务
控制器将 HTTP 请求转换为调用,并将结果转换回响应。 创建一个服务来存储 PhotosController 将返回的照片。
在下一部分中,将添加第二个控制器来提供图像下载。 两个控制器都需要相同的照片。 如果为每个控制器提供各自的映射,应用程序中会留下两组单独的照片,因此两者都将使用同一个服务。
该服务也会成为放置非 HTTP 转换逻辑的位置,例如从上传的文件构建照片。 两个控制器都可以使用此服务,并且该服务可以从映射切换到数据库,而无需在任一控制器中放置数据库操作。
在 service 软件包中,创建
PhotosService:@Service public class PhotosService { private final Map<String, Photo> db = new HashMap<>(); public PhotosService() { db.put("1", new Photo("1", "hello.jpg")); } public Collection<Photo> get() { return db.values(); } public Photo get(String id) { return db.get(id); } public Photo remove(String id) { return db.remove(id); } }对
映射、HashMap和集合使用java.util导入,并从 IntelliJ IDEA 建议的 model 软件包导入Photo。@Service会告知 Spring 在启动时创建一个实例,其方式与@RestController相同。 映射按标识符存储照片,因此检索或移除某一张照片时无需搜索列表。 它以一个示例hello.jpg开始,让端点有内容可返回。 这只是元数据,尚无图像文件。在
PhotosController中,为服务添加一个字段和一个构造函数。 保留hello()方法:private final PhotosService photosService; public PhotosController(PhotosService photosService) { this.photosService = photosService; }代码中没有任何内容会调用此构造函数。 启动时,Spring 会发现
PhotosController需要一个PhotosService,找到带有@Service注解的类,创建一个实例并将其传入。 这就是构造函数注入,并且会创建并共享一个实例,这使第二个控制器能够在下一部分看到相同的照片。
为所有照片添加 GET 端点
模型和存储已就位。 第一个照片端点通过向服务请求所有已存储的照片并返回结果,将它们连接到浏览器。
在
PhotosController中,添加一个用于 GET 请求的方法,并将其映射到/photos:@GetMapping("/photos") public Collection<Photo> get() { return photosService.get(); }重启应用程序:点击
重新运行 ,位置在 运行 工具窗口中。 然后打开
http://localhost:8080/photos。 浏览器会显示一个包含这张照片的 JSON 数组:[{"fileName":"hello.jpg","id":"1"}]
方法中没有任何内容显式创建 JSON。 它返回一个 Java 集合,并且由于该类是
@RestController,Spring 会将返回值转换为响应。 生成的 getter 提供了出现在 JSON 数组中的照片属性。
为一张照片添加 GET 端点
向
PhotosController添加另一个get()方法:@GetMapping("/photos/{id}") public Photo get(@PathVariable String id) { Photo photo = photosService.get(id); if (photo == null) { throw new ResponseStatusException(HttpStatus.NOT_FOUND); } return photo; }/photos/{id}中的大括号标识路径的变量部分。@PathVariable会将其传入具有相同名称的形参,因此对/photos/1的请求会查找标识符为1的照片。当找不到照片时,服务返回
null。 控制器通过抛出ResponseStatusException将这种缺失转换为404 Not Found。 这会将 HTTP 响应处理保留在控制器中。重启应用程序并打开
http://localhost:8080/photos/1,即可看到作为 JSON 对象的照片。 打开http://localhost:8080/photos/2以检查 404 响应。 由于不存在具有此标识符的照片,浏览器会显示默认的 Spring Boot Whitelabel Error Page,并带有type=Not Found, status=404消息。
添加 DELETE 端点
向
PhotosController添加一个用于 DELETE 请求的方法:@DeleteMapping("/photos/{id}") public void delete(@PathVariable String id) { Photo photo = photosService.remove(id); if (photo == null) { throw new ResponseStatusException(HttpStatus.NOT_FOUND); } }@DeleteMapping在同一路径上处理不同的 HTTP 动词。 服务返回被移除的照片;如果该照片不存在,则返回null,控制器会将其转换为 404。重启应用程序并打开
http://localhost:8080/photos。打开浏览器开发者工具,并切换到 控制台 标签页。
为存在的照片发送 DELETE 请求:
(async function deletePhoto(id) { await fetch("http://localhost:8080/photos/" + id, { method: "DELETE" }) })("1")
重新加载
http://localhost:8080/photos。 列表现在为空:[]。