Spring Boot 入门教程
RESTful API 设计
本教程共 48 篇 · 第 19 篇 · 更新于 2026-08-13 · 约 3 分钟阅读
Spring BootRESTfulAPI 设计HTTP 状态码RestControllerJSON
本节目标:理解 REST 的核心思想,学会用 HTTP 方法和状态码设计资源接口,写出规范的增删改查 API。
REST 到底在说什么
REST 全称 Representational State Transfer,表现层状态转移。名字拗口,思想很朴素。
它把一切业务对象都看成资源。用户是资源,订单是资源,文章是资源。
每个资源有唯一的 URL 地址。对资源的操作,复用 HTTP 自带的方法,不自己发明动词。
核心约定四条:
- 资源用名词命名:
/users、/orders,不用/getUser。 - 方法表达动作:GET 查、POST 增、PUT 改、DELETE 删。
- 无状态:每个请求独立,服务端不记客户端状态。
- 用状态码说话:成功、失败、找不到,都体现在 HTTP 状态码里。
REST 是风格,不是标准。团队内部约定一致,比纠结「是否纯正」更重要。
HTTP 方法与状态码对照
每个方法有它惯用的语义和状态码:
| 方法 | 语义 | 常用状态码 |
|---|---|---|
| GET | 查询资源 | 200 OK |
| POST | 新建资源 | 201 Created |
| PUT | 整体更新资源 | 200 OK |
| DELETE | 删除资源 | 204 No Content |
状态码用对地方,调用方只看响应就能判断结果,不用解析业务字段。
NotePOST 和 PUT 都带请求体,区别在语义:POST 是「新增,ID 由服务端定」,PUT 是「替换,ID 由客户端指定」。
URL 怎么设计
好的 URL 像一条路径,从集合走到单个资源:
GET /products 查询商品列表
POST /products 新建商品
GET /products/{id} 查询单个商品
PUT /products/{id} 更新商品
DELETE /products/{id} 删除商品
几点约定俗成:
- 用复数名词,
/products而不是/product。 - 层级关系用斜杠表达,
/users/1/orders表示用户 1 的订单。 - 过滤条件放查询参数,
/products?category=book。 - 不用动词,
/products/delete/1是反面教材。
用 @RestController 写一套接口
下面用 ConcurrentHashMap 当内存仓库,写一个完整的产品接口。不连数据库,专注看 Web 层的写法。
产品模型:
package com.example.demo.model;
public class Product {
private Long id;
private String name;
private Double price;
public Product() {
}
public Product(Long id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
// getter / setter 省略,IDE 自动生成
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
}
控制器:
package com.example.demo.controller;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.model.Product;
@RestController
@RequestMapping("/products")
public class ProductController {
private final Map<Long, Product> store = new ConcurrentHashMap<>();
private final AtomicLong idGen = new AtomicLong(1);
// GET /products —— 查询列表
@GetMapping
public List<Product> list() {
return List.copyOf(store.values());
}
// POST /products —— 新建,返回 201
@PostMapping
public ResponseEntity<Product> create(@RequestBody Product product) {
Product saved = new Product(idGen.getAndIncrement(),
product.getName(), product.getPrice());
store.put(saved.getId(), saved);
return ResponseEntity.status(HttpStatus.CREATED).body(saved);
}
// GET /products/{id} —— 查询单个
@GetMapping("/{id}")
public Product get(@PathVariable Long id) {
return store.get(id);
}
// PUT /products/{id} —— 整体更新
@PutMapping("/{id}")
public Product update(@PathVariable Long id, @RequestBody Product product) {
product.setId(id);
store.put(id, product);
return product;
}
// DELETE /products/{id} —— 删除,返回 204
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
store.remove(id);
return ResponseEntity.noContent().build();
}
}
几个细节值得说:
- 类上
@RequestMapping("/products")定前缀,方法上只写剩余路径。 @PathVariable把 URL 里的{id}绑定到方法参数。ResponseEntity能精细控制状态码。不想控制时,直接返回对象也行,默认 200。store.get(id)查不到时返回 null,接口照样回 200。生产代码应抛异常走 404(第 21 章 ProblemDetail 示例已覆盖),这里仅为演示简化。- 删除返回 204 无内容,符合 REST 语义。
用 curl 验证接口
启动项目后,终端里就能测:
# 新建商品
curl -X POST http://localhost:8080/products \
-H "Content-Type: application/json" \
-d '{"name":"键盘","price":199.0}'
# 查询列表
curl http://localhost:8080/products
# 更新商品
curl -X PUT http://localhost:8080/products/1 \
-H "Content-Type: application/json" \
-d '{"name":"机械键盘","price":299.0}'
# 删除商品
curl -X DELETE http://localhost:8080/products/1
TipPOST 后服务端返回 201 和新建的资源。规范的做法是响应头里带
Location指向新资源地址,调用方拿它就能查。
本节小结
- REST 把业务抽象成资源,URL 只放名词。
- GET/POST/PUT/DELETE 对应查、增、改、删。
- 状态码要选对:201 新建、204 删除、200 成功。
- @RestController 加 @RequestMapping 就能组织出一套规范接口。