为了方便大家更好的理解Restful风格的api请求方式,我将以最简单的图书管理系统来举例,逐一举证说明每种请求方式的实际用法,包含URI设计、请求示例和注意事项。
我们常用的Restful风格的api主要有五种,分别是GET、POST、PUT、PATCH、DELETE
一、环境准备
1、引入依赖
在pom.xml文件中引入以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、实体类和模拟数据
// 图书实体类
public class Book {
private Long id;
private String title;
private String author;
private Integer stock;
// 构造方法、Getter/Setter 省略(可用Lombok @Data简化)
}
// 模拟内存数据库
@Service
public class BookService {
private final Map<Long, Book> books = new HashMap<>();
private Long nextId = 1L;
// 初始化测试数据
public BookService() {
saveBook(new Book(null, "Java编程思想", "Bruce Eckel", 5));
saveBook(new Book(null, "Python数据分析", "Wes McKinney", 3));
}
// 保存图书(自动生成ID)
public Book saveBook(Book book) {
book.setId(nextId);
books.put(nextId, book);
nextId++;
return book;
}
// 其他方法(findById, findAll, update, delete)见下文控制器代码
}
二、具体接口类(Controller)
@RestController
@RequestMapping("/api/books")
public class BookController {
@Autowired
private BookService bookService;
// --- GET: 查询所有图书 ---
@GetMapping
public ResponseEntity<List<Book>> getAllBooks() {
List<Book> bookList = new ArrayList<>(bookService.findAll());
return ResponseEntity.ok(bookList);
}
// --- GET: 根据ID查询图书 ---
@GetMapping("/{id}")
public ResponseEntity<Book> getBookById(@PathVariable Long id) {
Book book = bookService.findById(id);
if (book == null) {
return ResponseEntity.notFound().build(); // 404
}
return ResponseEntity.ok(book); // 200
}
// --- POST: 新增图书 ---
@PostMapping
public ResponseEntity<Book> createBook(@RequestBody Book book) {
Book savedBook = bookService.saveBook(book);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedBook.getId())
.toUri();
return ResponseEntity.created(location).body(savedBook); // 201
}
// --- PUT: 全量更新图书 ---
@PutMapping("/{id}")
public ResponseEntity<Book> updateBook(
@PathVariable Long id,
@RequestBody Book bookDetails) {
Book existingBook = bookService.findById(id);
if (existingBook == null) {
return ResponseEntity.notFound().build(); // 404
}
// 全量覆盖字段
existingBook.setTitle(bookDetails.getTitle());
existingBook.setAuthor(bookDetails.getAuthor());
existingBook.setStock(bookDetails.getStock());
bookService.update(existingBook);
return ResponseEntity.ok(existingBook); // 200
}
// --- PATCH: 局部更新库存 ---
@PatchMapping("/{id}/stock")
public ResponseEntity<Book> updateStock(
@PathVariable Long id,
@RequestBody Map<String, Integer> updates) {
Book existingBook = bookService.findById(id);
if (existingBook == null) {
return ResponseEntity.notFound().build(); // 404
}
// 仅更新stock字段
Integer newStock = updates.get("stock");
if (newStock != null) {
existingBook.setStock(newStock);
bookService.update(existingBook);
}
return ResponseEntity.ok(existingBook); // 200
}
// --- DELETE: 删除图书 ---
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
if (bookService.findById(id) == null) {
return ResponseEntity.notFound().build(); // 404
}
bookService.delete(id);
return ResponseEntity.noContent().build(); // 204
}
}
三、接口介绍
1、GET:获取资源(获取全部数据)
对应注解:@GetMapping
可以看到,此处的注解并没有像其他接口那样,后面跟上参数,那么说明这是一个不需要传任何参数就可以直接调用的接口。直接返回所有数据,同时,如果加上参数,那么就可以实现条件查询(根据id或其他数据查询)。
URI: GET /api/books
响应:
[
{ "id": 1, "title": "Java编程思想", "stock": 5 },
{ "id": 2, "title": "Python数据分析", "stock": 3 }
]
状态码: 200 OK
2、GET:获取资源(获取单本书籍详情)
对应注解:@GetMapping(“/{id}”)
根据条件查询,就在注解后面加上(“/{id}”),表示根据id查询,如果要根据名字查询,就可以写成(“/{name}”)。同时,需要在方法的参数前面加上@PathVariable注解,表示是由请求路径传递过来的参数。
URI: GET /api/books/1
响应:
{
"id": 1,
"title": "Java编程思想",
"author": "Bruce Eckel",
"stock": 5
}
状态码: 200 OK
注意:若书籍不存在(如GET /api/books/999),应返回null
3、POST:创建资源(新增一本书籍)
对应注解:@PostMapping,可以看到,PostMapping也是不需要带参数的,这些注解如果携带参数,一般是在请求地址中“我们可以看到”的参数。那么有同学就要问了,没有携带参数我们怎么新增数据呢。那是因为还有另一种携带参数的方法,那就是请求体。
public ResponseEntity createBook(@RequestBody Book book)
可以看到,在Book参数前面我们加上了@RequestBody,代表这就是通过请求体形式传递过来的参数。
URI: POST /api/books
请求体:
{
"title": "深入理解计算机系统",
"author": "Randal E.Bryant",
"stock": 10
}
成功响应:
{
"id": 3, // 系统自动生成ID
"title": "深入理解计算机系统",
"author": "Randal E.Bryant",
"stock": 10
}
状态码: 201 Created
Header: Location: /api/books/3(指向新资源的URI)
常见错误:若未传必填字段(如title),应返回400 Bad Request。
4、PUT:全量更新资源(更新书籍信息)
请求路径参数用于指向需要修改的数据,请求体为更新后的数据
URI: PUT /api/books/1
请求体:
{
"title": "Java编程思想(第5版)",
"author": "Bruce Eckel",
"stock": 8
}
响应:返回更新后的完整数据(字段必须全量提交)。
状态码: 200 OK
风险案例:
若仅提交部分字段(如只传title),其他字段可能被覆盖为空值!
👉 错误用法:
// 请求体
{ "title": "新书名" } // 缺少author和stock字段
此时,author和stock会被置为null。若需局部更新,应改用PATCH。
5、PATCH:局部更新资源
场景:调整书籍库存
URI: PATCH /api/books/1
请求体:
{
"stock": 3 // 只修改库存字段
}
响应:返回更新后的完整数据(仅stock变化,其他字段保留原值)。
状态码: 200 OK
对比PUT:PUT需提交完整数据,PATCH只需传需修改的字段。
6、DELETE:删除资源
场景:下架一本书籍
URI: DELETE /api/books/1
响应: 无内容(表示删除成功)。
四、总结:图书管理API速查表
HTTP方法对照表
| 方法 | 场景 | 示例URI | 幂等性 | 安全性 |
|---|---|---|---|---|
| GET | 查书单/查详情 | /api/books/1 | 是 | 是 |
| POST | 新增书籍 | /api/books | 否 | 否 |
| PUT | 全量更新书籍信息 | /api/books/1 | 是 | 否 |
| PATCH | 调整库存/局部更新 | /api/books/1 | 否 | 否 |
| DELETE | 下架书籍 | /api/books/1 | 是 | 否 |

418

被折叠的 条评论
为什么被折叠?



