REST 全称为 Representational State Transfer(表征状态转移),是 Roy Fielding 博士在 2000 年博士论文中提出的软件架构设计风格(不是协议、不是框架、不是库)。 遵循 REST 设计规范的 API 称为 RESTful API,是目前前后端分离、微服务架构中最主流的接口设计标准。
简单理解:
资源:互联网中一切实体都是资源(用户、订单、商品)
表征:资源的表现形式(JSON/XML,主流用 JSON)
状态转移:通过 HTTP 方法对资源进行增删改查,实现资源状态的变化
只有满足以下约束,才能称为标准 RESTful API:
客户端 - 服务器分离:前后端解耦,独立开发、独立部署、独立扩展
无状态(核心):服务器不存储客户端会话信息,每个请求必须携带完整参数
可缓存:响应支持 HTTP 缓存,提升性能
统一接口:使用标准 HTTP 方法操作资源,接口语义统一
分层系统:网关、负载均衡、服务器分层部署,提高扩展性
按需代码(可选):服务器可向客户端传输可执行代码(极少用)
相比传统接口(如 getUser.php、addOrder),RESTful 具备绝对优势:
HTTP 方法 + CRUD + 幂等性 + 状态码
RESTful 核心:用标准 HTTP 方法操作资源,不使用动词,只用名词
关键概念:幂等性
幂等:同一请求执行 1 次和执行 N 次,结果完全一致(无脏数据)
非幂等:重复执行会创建多条数据(POST 必须做防重复提交)
RESTful 项目必须采用分层架构,解耦代码、便于维护:
├── EmployeeApiApplication.java # 启动类(项目入口)
├── controller # 控制层:接收请求、参数校验、返回响应
├── service # 业务层:核心业务逻辑、事务控制
├── mapper/dao # 持久层:数据库交互(MyBatis/JPA)
├── entity/model # 实体层:数据库映射对象
├── common # 公共层:统一响应、全局异常、常量
└── vo # 视图对象:前端返回的数据封装(可选)每层职责
Controller:只处理 HTTP 相关,不写业务逻辑
Service:核心业务处理、事务、数据校验
Mapper:只做数据库增删改查
Entity:数据库表映射
Common:全局工具、统一响应、异常处理
<dependencies>
<!-- Spring Web 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>统一响应结果(企业必备)
解决原生返回格式不统一问题,前端更容易处理:
package com.example.employeeapi.common;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 全局统一响应结果
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private int code; // 响应码
private String msg; // 响应信息
private T data; // 响应数据
// 成功响应
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
// 成功响应(无数据)
public static <T> Result<T> success() {
return new Result<>(200, "操作成功", null);
}
// 失败响应
public static <T> Result<T> fail(String msg) {
return new Result<>(500, msg, null);
}
}package com.example.employeeapi.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer id;
@NotBlank(message = "名不能为空") // 参数校验
private String firstName;
@NotBlank(message = "姓不能为空")
private String lastName;
@Email(message = "邮箱格式不正确") // 邮箱校验
private String email;
}package com.example.employeeapi.mapper;
import com.example.employeeapi.entity.Employee;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Repository
public class EmployeeMapper {
// 内存集合模拟数据库
private final List<Employee> db = new ArrayList<>();
// 初始化数据
{
db.add(new Employee(1, "Prem", "Tiwari", "prem@gmail.com"));
db.add(new Employee(2, "Vikash", "Kumar", "vikash@gmail.com"));
}
// 查询所有
public List<Employee> findAll() {
return db;
}
// 根据ID查询
public Optional<Employee> findById(Integer id) {
return db.stream().filter(e -> e.getId().equals(id)).findFirst();
}
// 新增
public Employee save(Employee employee) {
employee.setId(db.size() + 1);
db.add(employee);
return employee;
}
// 全量更新
public Employee update(Employee employee) {
db.removeIf(e -> e.getId().equals(employee.getId()));
db.add(employee);
return employee;
}
// 删除
public boolean deleteById(Integer id) {
return db.removeIf(e -> e.getId().equals(id));
}
}package com.example.employeeapi.service;
import com.example.employeeapi.entity.Employee;
import com.example.employeeapi.mapper.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
// 查询所有员工
public List<Employee> getAll() {
return employeeMapper.findAll();
}
// 根据ID查询
public Optional<Employee> getById(Integer id) {
return employeeMapper.findById(id);
}
// 新增员工
public Employee create(Employee employee) {
return employeeMapper.save(employee);
}
// 全量更新员工
public Employee update(Employee employee) {
return employeeMapper.update(employee);
}
// 删除员工
public boolean delete(Integer id) {
return employeeMapper.deleteById(id);
}
}package com.example.employeeapi.controller;
import com.example.employeeapi.common.Result;
import com.example.employeeapi.entity.Employee;
import com.example.employeeapi.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.net.URI;
import java.util.List;
@RestController
@RequestMapping("/api/v1/employees")
@Validated // 开启参数校验
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
// 1. 查询所有员工 GET /api/v1/employees
@GetMapping
public Result<List<Employee>> getAll() {
return Result.success(employeeService.getAll());
}
// 2. 根据ID查询员工 GET /api/v1/employees/{id}
@GetMapping("/{id}")
public Result<Employee> getById(@PathVariable Integer id) {
return employeeService.getById(id)
.map(Result::success)
.orElse(Result.fail("员工不存在"));
}
// 3. 新增员工 POST /api/v1/employees
@PostMapping
public ResponseEntity<Result<Employee>> create(@Valid @RequestBody Employee employee) {
Employee emp = employeeService.create(employee);
URI uri = URI.create("/api/v1/employees/" + emp.getId());
// 返回201状态码(REST标准)
return ResponseEntity.created(uri).body(Result.success(emp));
}
// 4. 全量更新员工 PUT /api/v1/employees/{id}
@PutMapping("/{id}")
public Result<Employee> update(
@PathVariable Integer id,
@Valid @RequestBody Employee employee
) {
employee.setId(id);
return Result.success(employeeService.update(employee));
}
// 5. 删除员工 DELETE /api/v1/employees/{id}
@DeleteMapping("/{id}")
public Result<Void> delete(@PathVariable Integer id) {
if (employeeService.delete(id)) {
return Result.success();
}
return Result.fail("删除失败,员工不存在");
}
}package com.example.employeeapi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EmployeeApiApplication {
public static void main(String[] args) {
SpringApplication.run(EmployeeApiApplication.class, args);
}
}新增 / 更新请求体示例
{
"firstName": "Elon",
"lastName": "Musk",
"email": "elon@tesla.com"
}接口必须版本化:/api/v1/xxx,避免升级影响旧业务
统一响应格式:所有接口返回统一结构,前端无需适配多种格式
参数必校验:使用 @Valid 校验前端参数,防止非法数据
全局异常处理:统一捕获异常,避免前端收到杂乱错误
幂等性保障:POST 接口增加防重机制,PUT/DELETE 天然幂等
日志记录:接口请求、异常、业务操作全量日志
接口文档:集成 Swagger/Knife4j 自动生成接口文档
REST 本质:基于 HTTP 协议,用标准方法操作资源的架构风格
核心规范:GET 查、POST 增、PUT 改、DELETE 删,URL 用名词复数
分层架构:Controller→Service→Mapper,职责分离,代码易维护
企业标准:统一响应、参数校验、全局异常、版本控制是必备能力
核心优势:解耦、无状态、可扩展、跨平台,是微服务 / 前后端分离的首选