前端视角 Java Web 入门手册 5.3:真实世界 Web 开发——RESTful API 与 Spring MVC

RESTful API 设计指南 - 阮一峰的网络日志

RESTful API 最佳实践 - 阮一峰的网络日志

RESTful API 设计规范

REST(Representational State Transfer)是一种软件架构风格,用于设计可扩展的网络应用程序。RESTful API 根据 REST 原则构建,旨在利用现有的网络协议(特别是 HTTP)来创建高效、可扩展和易于维护的接口。RESTful API 包含一些关键设计规范和最佳实践:

1. 资源导向

所有的实体(如用户、订单、产品)都被视为资源,每个资源通过唯一的 URI(统一资源标识符)进行标识

plain 复制代码
https://api.example.com/users
https://api.example.com/orders/{id}
https://api.example.com/products/{id}

在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词。一般来说,数据库中的表都是同种记录的"集合"(collection),所以 API 中的名词也应该使用复数。

2. 使用标准的 HTTP 方法

  • GET:检索资源。例如,GET /users 获取用户列表,GET /users/{id} 获取特定用户。
  • POST:创建新资源。例如,POST /users 创建新用户。
  • PUT:更新资源的全部内容。例如,PUT /users/{id} 更新特定用户的所有信息。
  • PATCH:部分更新资源。例如,PATCH /users/{id} 部分更新用户信息。
  • DELETE:删除资源。例如,DELETE /users/{id} 删除特定用户。

3. 版本控制

通过 URI 版本号或其他方式管理 API 的版本,确保向后兼容。例如:

  • /v1/users
  • /api/v2/orders

4. 分页、过滤和排序

对于返回大量数据的 API,提供分页、过滤和排序功能,以提高性能和用户体验。例如:

ini 复制代码
GET /users?page=2&size=20&sort=name,asc
GET /products?category=electronics&price_lt=500

5. 返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

plain 复制代码
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档

Spring MVC

Spring MVC 是 Spring 框架中的一个模块,专门用于构建 Web 应用程序,借助 Spring MVC,开发者可以方便地创建 RESTful 风格的 Web 服务

控制器

在 RESTful 服务中,控制器负责处理 HTTP 请求,并返回资源表示。Spring MVC 提供了多个注解来简化这一过程

  • @RestController:表示控制器中的所有方法默认返回 JSON 或 XML 数据,而不是视图
  • @RequestMapping:将特定的 HTTP 请求路径和方法与控制器的方法关联起来,实现资源的操作。为了简化常用的HTTP方法映射,Spring MVC提供了一系列快捷注解,如 @GetMapping、@PostMapping 等
java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {

    // 继承类级别的基础路径 /api/users
    @GetMapping
    public List<User> getAllUsers() {
        // 获取所有用户
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        // 根据 ID 获取用户
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        // 创建新用户
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        // 更新用户信息
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        // 删除用户
    }
}

请求与响应

  • @RequestBody:将HTTP请求体中的JSON或XML数据绑定到方法参数中。
  • @PathVariable:从URL路径中提取变量。
  • @RequestParam:从查询参数(query)中提取变量。
  • @ResponseStatus:用于为方法或异常类设置HTTP响应状态码
java 复制代码
@PutMapping("/users/{id}")
@ResponseStatus(HttpStatus.CREATED)
public User updateUser(@PathVariable Long id, @RequestBody User user) {
    // 方法实现
}

简单 demo

java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {

    private final Map<Long, User> userRepository = new ConcurrentHashMap<>();

    @GetMapping
    public Collection<User> getAllUsers() {
        return userRepository.values();
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userRepository.get(id);
        if (user != null) {
            return ResponseEntity.ok(user);
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        }
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        user.setId(System.currentTimeMillis());
        userRepository.put(user.getId(), user);
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }

    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        if (userRepository.containsKey(id)) {
            user.setId(id);
            userRepository.put(id, user);
            return ResponseEntity.ok(user);
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        }
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        if (userRepository.containsKey(id)) {
            userRepository.remove(id);
            return ResponseEntity.noContent().build();
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }
    }
}
相关推荐
飞翔的佩奇1 小时前
基于SpringBoot+MyBatis+MySQL+VUE实现的房屋交易平台管理系统(附源码+数据库+毕业论文+部署教程+配套软件)
数据库·spring boot·mysql·vue·毕业设计·mybatis·房屋交易平台
海狸老先生4 小时前
Apache Tomcat样例目录session操纵漏洞解读
java·网络安全·tomcat
Jinkxs5 小时前
基础14-Java集合框架:掌握List、Set和Map的使用
java·list
你的人类朋友6 小时前
✨什么是SaaS?什么是多租户?
后端·架构·设计
遗憾皆是温柔6 小时前
3.JVM,JRE和JDK的关系是什么
java·开发语言·jvm·面试
M1A16 小时前
全球语言无障碍:Unicode标准解读与技术演进史
后端
无限大66 小时前
多数元素问题:从暴力美学到摩尔投票神仙解法
后端
无限大67 小时前
《计算机“十万个为什么”》之 面向对象 vs 面向过程:编程世界的积木与流水线
后端
洛可可白7 小时前
Spring Boot 应用结合 Knife4j 进行 API 分组授权管理配置
java·spring boot·后端
亲爱的非洲野猪7 小时前
ZooKeeper 深度实践:从原理到 Spring Boot 全栈落地
spring boot·zookeeper·java-zookeeper