Spring Boot: REST API 快速入门
最后更新:2026-08-26
REST API 是微服务的通用语言——用 HTTP 动词操作资源,用 JSON 传递数据,简单、标准、高效。
1. 你将学到
@RestController/@RequestMapping/@GetMapping/@PostMapping注解体系- 路径变量
@PathVariable、请求参数@RequestParam、请求体@RequestBody - HTTP 状态码与
ResponseEntity自定义响应 - Postman / curl 测试 REST 接口
- Alice 实现订单的创建、查询、更新、删除四项操作
2. 一个 API 开发者的真实故事
(1) 痛点:接口规范混乱
Alice 加入了一个老项目团队,发现 REST API 设计混乱:有的用 GET 修改数据,有的 URL 命名不一致(/getOrder、/order/list、/deleteOrderById),返回格式也不统一——有的返回 JSON,有的返回 XML,错误时返回纯文本。前端同事 Bob 每次对接新接口都要问后端的人,浪费了大量沟通时间。
(2) RESTful 风格的解法
REST 用统一的约定规范 API 设计:
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@GetMapping("/{id}") // GET /api/orders/123
@PostMapping // POST /api/orders
@PutMapping("/{id}") // PUT /api/orders/123
@DeleteMapping("/{id}") // DELETE /api/orders/123
}
(3) 收益
Alice 用 RESTful 风格重构 OrderFlow 的 API 后,URL 命名统一、HTTP 动词语义明确,前端同事 Bob 说"看 URL 就知道怎么用",接口对接时间从平均 2 小时缩短到 15 分钟。
3. REST 核心概念
(1) REST 六大约束
REST(Representational State Transfer)定义了架构风格的核心约束:
graph TD
A[REST Constraints] --> B[Client-Server<br/>Separation of Concerns]
A --> C[Stateless<br/>Each Request Contains<br/>All Needed Info]
A --> D[Cacheable<br/>Responses Define<br/>Cacheability]
A --> E[Uniform Interface<br/>Consistent API Design]
A --> F[Layered System<br/>Client Cannot Tell<br/>If Connected Directly]
A --> G[Code on Demand<br/>Optional: Server Can<br/>Send Executable Code]
(2) HTTP 动词与 CRUD 映射
| HTTP 动词 | 操作 | 幂等性 | 安全性 | 典型 URL |
|---|---|---|---|---|
| GET | 查询 | 是 | 是 | /api/orders |
| POST | 创建 | 否 | 否 | /api/orders |
| PUT | 全量更新 | 是 | 否 | /api/orders/123 |
| PATCH | 部分更新 | 否 | 否 | /api/orders/123 |
| DELETE | 删除 | 是 | 否 | /api/orders/123 |
4. @RestController 与请求映射
(1) @RestController 原理
@RestController = @Controller + @ResponseBody,表示该类所有方法返回值直接写入 HTTP 响应体(默认 JSON)。
▶ 示例: 基础 OrderController
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final List<Map<String, Object>> orders = new ArrayList<>();
@GetMapping
public List<Map<String, Object>> listOrders() {
return orders;
}
@PostMapping
public Map<String, Object> createOrder(
@RequestBody Map<String, Object> order) {
order.put("id", (long) (orders.size() + 1));
order.put("status", "PENDING");
orders.add(order);
return order;
}
}
输出:
// 执行成功
(2) 请求参数绑定
▶ 示例: @PathVariable 和 @RequestParam
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@GetMapping("/{id}")
public Map<String, Object> getOrder(@PathVariable Long id) {
return Map.of("id", id, "status", "PENDING");
}
@GetMapping
public List<Map<String, Object>> searchOrders(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) String status) {
return List.of(Map.of(
"page", page, "size", size, "status", status
));
}
}
输出:
// 执行成功
| 注解 | 用途 | 示例 | URL |
|---|---|---|---|
@PathVariable |
提取路径中的变量 | @PathVariable Long id |
/api/orders/123 |
@RequestParam |
提取查询参数 | @RequestParam String status |
/api/orders?status=PENDING |
@RequestBody |
提取请求体 JSON | @RequestBody OrderRequest req |
POST body |
@RequestHeader |
提取请求头 | @RequestHeader String auth |
Header: Authorization |
▶ 示例: 使用 DTO 接收请求体
public record CreateOrderRequest(
Long productId,
Integer quantity,
String shippingAddress
) {}
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@PostMapping
public ResponseEntity<Map<String, Object>> createOrder(
@RequestBody CreateOrderRequest request) {
Map<String, Object> order = Map.of(
"productId", request.productId(),
"quantity", request.quantity(),
"shippingAddress", request.shippingAddress(),
"status", "PENDING"
);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(order);
}
}
输出:
// 执行成功
5. ResponseEntity 与 HTTP 状态码
(1) ResponseEntity 的使用
ResponseEntity 允许你完全控制 HTTP 响应:状态码、响应头、响应体。
| 方式 | 适用场景 | 灵活度 |
|---|---|---|
| 直接返回对象 | 简单成功响应 | 低(固定 200) |
ResponseEntity.ok(body) |
需要指定 200 | 中 |
ResponseEntity.status(CREATED).body(body) |
创建资源返回 201 | 高 |
ResponseEntity.notFound().build() |
资源不存在返回 404 | 高 |
▶ 示例: 完整 CRUD 操作
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final Map<Long, Map<String, Object>> orderStore = new ConcurrentHashMap<>();
private final AtomicLong idGenerator = new AtomicLong(1);
@PostMapping
public ResponseEntity<Map<String, Object>> create(
@RequestBody CreateOrderRequest request) {
Long id = idGenerator.getAndIncrement();
Map<String, Object> order = new HashMap<>();
order.put("id", id);
order.put("productId", request.productId());
order.put("quantity", request.quantity());
order.put("status", "PENDING");
orderStore.put(id, order);
return ResponseEntity.status(HttpStatus.CREATED).body(order);
}
@GetMapping("/{id}")
public ResponseEntity<Map<String, Object>> getOne(@PathVariable Long id) {
Map<String, Object> order = orderStore.get(id);
if (order == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(order);
}
@PutMapping("/{id}")
public ResponseEntity<Map<String, Object>> update(
@PathVariable Long id,
@RequestBody CreateOrderRequest request) {
if (!orderStore.containsKey(id)) {
return ResponseEntity.notFound().build();
}
Map<String, Object> order = new HashMap<>();
order.put("id", id);
order.put("productId", request.productId());
order.put("quantity", request.quantity());
order.put("status", "CONFIRMED");
orderStore.put(id, order);
return ResponseEntity.ok(order);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
if (orderStore.remove(id) == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.noContent().build();
}
}
输出:
// 执行成功
6. API 测试方法
(1) curl 测试命令
▶ 示例: curl 测试 CRUD 接口
# Create order
curl -X POST http://localhost:8080/api/orders \
-H "Content-Type: application/json" \
-d '{"productId":1, "quantity":3, "shippingAddress":"123 Main St"}'
# Get order
curl http://localhost:8080/api/orders/1
# List orders with pagination
curl "http://localhost:8080/api/orders?page=0&size=10"
# Update order
curl -X PUT http://localhost:8080/api/orders/1 \
-H "Content-Type: application/json" \
-d '{"productId":2, "quantity":5, "shippingAddress":"456 Oak Ave"}'
# Delete order
curl -X DELETE http://localhost:8080/api/orders/1
输出:
{"status":"ok","data":{}}
| HTTP 状态码 | 含义 | 何时返回 |
|---|---|---|
| 200 OK | 成功 | GET / PUT 成功 |
| 201 Created | 已创建 | POST 创建资源成功 |
| 204 No Content | 无内容 | DELETE 成功 |
| 400 Bad Request | 请求错误 | 参数校验失败 |
| 404 Not Found | 未找到 | 资源不存在 |
7. RESTful API 设计规范
(1) URL 命名规范
| 规则 | 错误写法 | 正确写法 |
|---|---|---|
| 使用名词复数 | /getOrder |
/api/orders |
| 嵌套资源关系 | /orderItems?orderId=1 |
/api/orders/1/items |
| 用路径而非查询 | /api/orders?id=1 |
/api/orders/1 |
| 版本控制 | 无 | /api/v1/orders |
| 过滤用查询参数 | /api/pendingOrders |
/api/orders?status=PENDING |
8. 综合示例:OrderFlow 订单 CRUD API
package com.orderflow.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
public record CreateOrderRequest(
Long productId, Integer quantity, String shippingAddress
) {}
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
private final Map<Long, Map<String, Object>> store = new ConcurrentHashMap<>();
private final AtomicLong seq = new AtomicLong(1);
@PostMapping
public ResponseEntity<Map<String, Object>> create(
@RequestBody CreateOrderRequest req) {
Long id = seq.getAndIncrement();
Map<String, Object> order = new LinkedHashMap<>();
order.put("id", id);
order.put("productId", req.productId());
order.put("quantity", req.quantity());
order.put("shippingAddress", req.shippingAddress());
order.put("status", "PENDING");
order.put("createdAt", java.time.Instant.now());
store.put(id, order);
return ResponseEntity.status(HttpStatus.CREATED).body(order);
}
@GetMapping
public List<Map<String, Object>> list(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
return store.values().stream()
.skip((long) page * size).limit(size).toList();
}
@GetMapping("/{id}")
public ResponseEntity<Map<String, Object>> get(@PathVariable Long id) {
Map<String, Object> order = store.get(id);
return order != null ? ResponseEntity.ok(order)
: ResponseEntity.notFound().build();
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
return store.remove(id) != null
? ResponseEntity.noContent().build()
: ResponseEntity.notFound().build();
}
}
❓ 常见问题
application.yml 中配置 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss,或在字段上用 @JsonFormat(pattern = "yyyy-MM-dd")。/api/v1/orders),简单直观。也可以用 Header 版本控制(Accept: application/vnd.orderflow.v1+json),更 RESTful 但实现复杂。📖 小节
- REST 用 HTTP 动词映射 CRUD:GET 查询、POST 创建、PUT 更新、DELETE 删除
@RestController=@Controller+@ResponseBody,返回 JSON@PathVariable取路径变量,@RequestParam取查询参数,@RequestBody取请求体ResponseEntity完全控制响应状态码、头部和正文- RESTful URL 使用名词复数,嵌套表示资源关系,查询参数用于过滤
📝 作业
-
基础题(难度⭐):为 OrderFlow 实现商品(Product)资源的 CRUD API,包括
GET /api/v1/products、POST /api/v1/products、GET /api/v1/products/{id}、DELETE /api/v1/products/{id}。 -
进阶题(难度⭐⭐):在订单 API 中添加
PATCH /api/v1/orders/{id}/status接口,只更新订单状态字段,思考 PATCH 与 PUT 的区别。 -
挑战题(难度⭐⭐⭐):实现
GET /api/v1/orders/{id}/items嵌套资源接口,返回指定订单下的所有订单项,并支持分页参数。