从零到一:用 SpringBoot 打造 RESTful API 实战指南

目录

[一、什么是 RESTful API?](#一、什么是 RESTful API?)

二、设计规范

[2.1 controller接口设计规范](#2.1 controller接口设计规范)

[2.2 返回结构设计规范](#2.2 返回结构设计规范)

三、restful与非restful风格对比

3.1查询图书

[3.2 新增图书](#3.2 新增图书)

[3.3 修改图书](#3.3 修改图书)

[3.4 删除图书](#3.4 删除图书)

[四、SpringBoot 实战](#四、SpringBoot 实战)

[4.1 前提准备实体类](#4.1 前提准备实体类)

[4.2 restful返回规范](#4.2 restful返回规范)

[4.3 Controller类(RESTful 核心)](#4.3 Controller类(RESTful 核心))

[4.4 请求示例](#4.4 请求示例)


一、什么是 RESTful API?

REST (Representational State Transfer)是一种 面向资源 的架构风格,核心思想:

用 URL 定位资源,用 HTTP 动词描述操作

面向资源怎么理解呢?:

RESTful API 就是符合 REST 约束的接口,特点:

  • 无状态(每次请求自带上下文)

  • 统一接口(GET/POST/PUT/DELETE)

  • 资源导向(URL 是名词,不是动词)

二、设计规范

2.1 controller接口设计规范

RESTful API的RequestMapping的方式有4种,以图书为例,每一种的应用场景如下:

|--------|---------------|--------------------|
| 动作 | 资源集合 /books | 单个资源 /books/{id} |
| GET | 查询集合 | 查询单个 |
| POST | 新增集合 | ❌ |
| PUT | 批量更新 | 更新单个 |
| DELETE | 批量删除 | 删除单个 |

2.2 返回结构设计规范

|---------|--------|---------------------------|
| 字段 | 类型 | 说明 |
| code | int | HTTP 状态码(200/400/404/500) |
| message | string | 用户可读提示信息 |
| data | 泛型T | 业务数据(含分页) |

三、restful与非restful风格对比

3.1查询图书

非 RESTful 代码:

java 复制代码
@GetMapping("/getBook")
public List<Book> getBooks(@RequestParam int page,@RequestParam int size) {
    return bookService.list(page,size);   // 直接 List
}

RESTful 代码:

java 复制代码
@GetMapping("/book")
public ApiResponse<PageVO<Book>> list(@RequestParam(defaultValue = "1") int page,@RequestParam(defaultValue = "10") int size) {
    return ApiResponse.success(PageVO.of(bookService.list(page,size)));
}

对比表格:

|----------|------------------------------|--------------------------------------------|
| 纬度 | 非 RESTful | RESTful |
| URL | /getBook.php?page=1&size=20 | /book?page=1&size=20 |
| HTTP | GET | GET |
| 返回 | List<Book> | ApiResponse<PageVO<Book>> |
| 状态码 | 200(包一切) | 200(正常) |
| 示例返回 | [{...}, {...}] | {code:200,data:{records:[...],total:90}} |

3.2 新增图书

非 RESTful 代码:

java 复制代码
@PostMapping("/addBook")
public Book addBook(@RequestBody Book book) {
    return bookService.create(book);   // 直接实体
}

RESTful 代码:

java 复制代码
@PostMapping("/book")
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse<Book> create(@Valid @RequestBody Book book) {
    return ApiResponse.success(bookService.create(book));
}

对比表格:

|----------|--------------|---------------------|
| 纬度 | 非 RESTful | RESTful |
| URL | /addBook.php | /book |
| HTTP | POST | POST |
| 返回 | Book | ApiResponse<Book> |
| 状态码 | 200(包一切) | 201(Created) |
| 示例返回 | {...} | {code:200,data:{}} |

3.3 修改图书

非 RESTful 代码:

java 复制代码
    @PostMapping("/updateBook")
    public Book update(@Valid @RequestBody Book book) {
           //处理修改逻辑
        return book;
    }

RESTful 代码:

java 复制代码
    @PutMapping("/book")
    public ApiResponse<Book> update(@Valid @RequestBody Book book) {
           //处理修改逻辑
        return ApiResponse.success(book);
    }

对比表格:

|----------|-----------------|---------------------|
| 纬度 | 非 RESTful | RESTful |
| URL | /updateBook.php | /book |
| HTTP | POST | PUT |
| 返回 | Book | ApiResponse<Book> |
| 示例返回 | {...} | {code:200,data:{}} |

3.4 删除图书

非 RESTful 代码:

java 复制代码
@GetMapping("/deleteBook")
public String deleteBook(@RequestParam Long id) {
    bookService.delete(id);
    return "删除成功";   // 字符串
}

RESTful 代码:

java 复制代码
@DeleteMapping("/book/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public ApiResponse<String> delete(@PathVariable Long id) {
    bookService.deleteById(id);
    return ApiResponse.success("删除成功");
}

对比表格:

|----------|----------------------|-----------------------|
| 纬度 | 非 RESTful | RESTful |
| URL | /deleteBook.php?id=1 | /book/1 |
| HTTP | GET(❌) | DELETE |
| 返回 | String("删除成功") | ApiResponse<String> |

从上述可以看出,使用restful风格,增删查改接口的url可以命名相同/book,因为是根据不同的方式(GET、POST、PUT、DELETE)来区分的。

四、SpringBoot 实战

4.1 前提准备实体类

java 复制代码
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    private Long id;
    private String name;
    private BigDecimal price;
}

4.2 restful返回规范

java 复制代码
@Data
public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;

    public static <T> ApiResponse<T> success(T data) {
        ApiResponse<T> resp = new ApiResponse<>();
        resp.code = 200;
        resp.message = "success";
        resp.data = data;
        return resp;
    }
}

4.3 Controller类(RESTful 核心)

java 复制代码
@RestController
@RequestMapping("/books")
@Validated
public class BookController {

    private final Map<Long, Book> repo = new ConcurrentHashMap<>();

    // 查询集合
    @GetMapping
    public ApiResponse<List<Book>> list(@RequestParam(required = false) String name) {
        List<Book> list = repo.values().stream()
                .filter(b -> name == null || b.getName().contains(name))
                .collect(Collectors.toList());
        return ApiResponse.success(list);
    }

    // 查询单个
    @GetMapping("/{id}")
    public ApiResponse<Book> get(@PathVariable Long id) {
        Book book = Optional.ofNullable(repo.get(id))
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
        return ApiResponse.success(book );
    }

    // 新增
    @PostMapping
    public ApiResponse<Book>create(@Valid @RequestBody Book book) {
        book.setId(System.currentTimeMillis());
        repo.put(book.getId(), book);
        return ApiResponse.success(list);
    }

    // 全量更新
    @PutMapping("/{id}")
    public ApiResponse<Book> update(@PathVariable Long id, @Valid @RequestBody Book book) {
           //自定义更新逻辑
        return ApiResponse.success(list);
    }

    // 删除
    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public ApiResponse<?> delete(@PathVariable Long id) {
        return ApiResponse.success(repo.remove(id));
    }
}

4.4 请求示例

GET /books → 查询图书列表

GET /books/1 → 查询 id=1 的图书

POST /books → 新增图书

PUT /books/1 → 全量更新 id=1 的图书

DELETE /books/1 → 删除 id=1 的图书

暂时分享到这里啦,点赞 + 收藏 + fork ,一起 RESTful

如果有任何疑问欢迎在评论区留言,谢谢。

相关推荐
嘻哈baby10 小时前
如何理解Rust语言中Send和Sync?
后端
用户2986985301411 小时前
.NET 文档自动化:Spire.Doc 设置奇偶页页眉/页脚的最佳实践
后端·c#·.net
码路飞11 小时前
GPT-5.3 Instant 终于学会好好说话了,顺手对比了下同天发布的 Gemini 3.1 Flash-Lite
java·javascript
序安InToo11 小时前
第6课|注释与代码风格
后端·操作系统·嵌入式
xyy12311 小时前
C#: Newtonsoft.Json 到 System.Text.Json 迁移避坑指南
后端
洋洋技术笔记12 小时前
Spring Boot Web MVC配置详解
spring boot·后端
JxWang0512 小时前
VS Code 配置 Markdown 环境
后端
navms12 小时前
搞懂线程池,先把 Worker 机制啃明白
后端
JxWang0512 小时前
离线数仓的优化及重构
后端
Nyarlathotep011312 小时前
gin01:初探gin的启动
后端·go