REST API 开发
约 1309 字大约 4 分钟
布欧-Lewyon
2026-05-15
首页 › Spring Boot › Web 与 REST › REST API 开发
本节从 @RestController 入手,编写资源端点、处理请求参数、定义统一响应结构。
@RestController
@RestController = @Controller + @ResponseBody,返回的对象自动序列化为 JSON(Jackson):
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
public List<User> list() {
return userService.findAll();
}
@GetMapping("/{id}")
public User getById(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping
public User create(@RequestBody User user) {
return userService.create(user);
}
}请求参数绑定
| 注解 | 来源 | 典型场景 |
|---|---|---|
@PathVariable | URL 路径 | /users/{id} |
@RequestParam | 查询参数 | /users?page=1 |
@RequestBody | 请求体 | JSON |
@RequestHeader | 请求头 | 认证 Token |
@CookieValue | Cookie | Session ID |
@RequestParam
@GetMapping
public List<User> list(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
return userService.findAll(page, size);
}@PathVariable
@GetMapping("/{id}")
public User getById(@PathVariable Long id) {
return userService.findById(id);
}统一响应结构
让所有接口返回一致的 JSON 结构,便于前端处理:
public class Result<T> {
private int code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> r = new Result<>();
r.code = 200;
r.message = "success";
r.data = data;
return r;
}
public static <T> Result<T> error(int code, String message) {
Result<T> r = new Result<>();
r.code = code;
r.message = message;
return r;
}
// getter / setter
}@GetMapping("/{id}")
public Result<User> getById(@PathVariable Long id) {
return Result.success(userService.findById(id));
}响应示例:
{
"code": 200,
"message": "success",
"data": {
"id": 1,
"name": "张三"
}
}进阶阅读:DispatcherServlet 请求处理流程
初学者先关注"怎么写接口",之后再理解内部路由。
DispatcherServlet 是 Spring MVC 的核心前端控制器(Front Controller 模式),所有 HTTP 请求最终都由它分发。其核心方法 doDispatch() 的源码流程如下:
HandlerInterceptor 的三个方法
public interface HandlerInterceptor {
// 在 Controller 方法执行之前调用
// 返回 false 可阻止继续执行
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {}
// 在 Controller 方法执行之后、视图渲染之前调用
// @RestController 场景,响应体已经在第 ⑤ 步写入,postHandle 中修改 ModelAndView 无效
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {}
// 请求完成后的回调(无论是否异常)
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {}
}扩展点:添加自定义拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RateLimitInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**");
}
}生产意识:
@ResponseBody的返回值处理在postHandle之前已经完成(因为RequestResponseBodyMethodProcessor在适配器中直接将对象写入HttpServletResponse的输出流),因此postHandle中的ModelAndView参数为null。如果你需要在响应写入前后做处理(如响应加密、统一审计 Header),应使用ResponseBodyAdvice(实现@ControllerAdvice + ResponseBodyAdvice接口)或自定义Filter(在DispatcherServlet之前执行)。Filter和HandlerInterceptor的区别:Filter 基于 Servlet API,在DispatcherServlet前后执行;Interceptor 基于 Spring MVC,在 Handler 前后执行,可以访问 Spring 上下文和HandlerMethod元数据。
内容协商与 JSON 默认行为
Spring Boot 默认使用 Jackson 2.x 处理 JSON 序列化。常见默认行为:
| 场景 | 默认行为 |
|---|---|
| null 字段 | 包含(不会自动排除) |
| 日期类型 | Instant / LocalDateTime 序列化为数组(不是 ISO 字符串) |
| 未知属性 | 反序列化时忽略,不会抛异常 |
控制序列化
spring:
jackson:
default-property-inclusion: non_null # 排除 null 字段
date-format: yyyy-MM-dd HH:mm:ss # 日期格式
time-zone: Asia/Shanghai # 时区
serialization:
write-dates-as-timestamps: false # 日期用字符串而非时间戳常用 Jackson 注解
public class User {
private Long id;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String nickname;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@JsonIgnore
private String password; // 序列化时忽略
}生产意识:全局
spring.jackson.default-property-inclusion: non_null可以防止大量 null 字段污染响应体积,但要注意某些前端可能依赖特定字段始终存在(即使为 null),改为 non_null 前需前端确认。@JsonIgnore作用于 getter 上同时影响序列化和反序列化——接收请求时该字段被忽略,用户无法通过 PUT 接口更新密码;更好的做法是在 DTO 中定义不同的请求/响应模型,响应对象不包含密码字段即可。
小结
@RestController=@Controller+@ResponseBody,返回值自动转为 JSON。@PathVariable/@RequestParam/@RequestBody覆盖了大部分参数绑定场景。- 统一响应结构(code / message / data)使前端异常处理更加简洁一致。
- Jackson 默认包含 null 字段、日期序列化为时间戳;通过
application.yml或@JsonInclude/@JsonFormat调整。 - 易错:
@RequestBody只能有一个,且不能与@RequestParam混用于同一参数来源。@JsonIgnore在反序列化时也会忽略对应字段,所以传入的 JSON 中包含该字段也不会被赋值。 - 思考任务:创建
UserController,实现完整的 CRUD 端点,所有返回值包装为Result<T>,配置 JackJSON 全局忽略 null 字段。
上一节:配置绑定
下一节:参数校验与异常处理
