摘要
@RestController 就是 @Controller 加 @ResponseBody 的组合,类里所有方法返回值自动写成 JSON,不用逐个加注解。
@RestController 是 Spring MVC 里最常用的注解之一,专门用于前后端分离的 REST API 开发。它是 @Controller + @ResponseBody 的组合,让类里所有方法的返回值都自动转成 JSON。
一、先看它的本质
@RestController 的源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller // ← 继承 @Controller
@ResponseBody // ← 继承 @ResponseBody
public @interface RestController {
@AliasFor(annotation = Controller.class)
String value() default "";
}
所以:
@RestController
public class XxxController { ... }
完全等价于:
@Controller
@ResponseBody
public class XxxController { ... }
二、对比示例:@Controller vs @RestController
示例1:用 @Controller(传统方式,返回页面)
@Controller
public class PageController {
@GetMapping("/index")
public String index() {
return "index"; // 返回视图名,去找 index.html
}
}
- 浏览器访问
/index,Spring 会去找index.html/index.jsp,渲染成 HTML 页面。 - 返回值是"页面名",不是数据。
示例2:用 @Controller + @ResponseBody(返回 JSON)
@Controller
public class UserController {
@GetMapping("/user")
@ResponseBody // ← 每个方法都要加,很麻烦
public User getUser() {
return new User(1L, "张三");
}
}
- 返回的是 JSON 数据,不再跳转页面。
- 每个方法都要写
@ResponseBody,啰嗦。
示例3:用 @RestController(推荐,返回 JSON)
@RestController
public class UserController {
@GetMapping("/user")
public User getUser() { // 不用加 @ResponseBody
return new User(1L, "张三");
}
}
- 整个类所有方法都自动返回 JSON,不用逐个加
@ResponseBody。 - 这就是前后端分离项目的标准写法。
三者对比
| 写法 | 返回值含义 | 是否需要 @ResponseBody |
|---|---|---|
@Controller | 视图名(页面) | 不需要(就是跳页面) |
@Controller + @ResponseBody | JSON 数据 | 每个方法都要加 |
@RestController | JSON 数据 | 不用加(类级别已生效) |
三、完整可运行示例
1. 定义实体类
public class User {
private Long id;
private String username;
private Integer age;
// 构造器、getter/setter 省略
public User(Long id, String username, Integer age) {
this.id = id;
this.username = username;
this.age = age;
}
}
2. 写 Controller
@RestController
@RequestMapping("/users") // 统一路径前缀
public class UserController {
// 模拟数据库
private static final Map<Long, User> DB = new HashMap<>();
static {
DB.put(1L, new User(1L, "张三", 20));
DB.put(2L, new User(2L, "李四", 22));
}
// ① 查询单个用户:GET /users/1
@GetMapping("/{id}")
public Response<User> getUser(@PathVariable Long id) {
User user = DB.get(id);
if (user == null) {
return Response.fail(404, "用户不存在");
}
return Response.success(user);
}
// ② 查询列表:GET /users
@GetMapping
public Response<List<User>> listUsers() {
return Response.success(new ArrayList<>(DB.values()));
}
// ③ 新增用户:POST /users
@PostMapping
public Response<User> createUser(@RequestBody User user) {
DB.put(user.getId(), user);
return Response.success("创建成功", user);
}
// ④ 删除用户:DELETE /users/1
@DeleteMapping("/{id}")
public Response<Void> deleteUser(@PathVariable Long id) {
DB.remove(id);
return Response.success();
}
}
3. 前端请求与响应
查询单个用户:
GET /users/1
响应(JSON):
{
"code": 200,
"data": { "id": 1, "username": "张三", "age": 20 },
"message": "请求成功",
"success": true
}
查询列表:
GET /users
响应:
{
"code": 200,
"data": [
{ "id": 1, "username": "张三", "age": 20 },
{ "id": 2, "username": "李四", "age": 22 }
],
"message": "请求成功",
"success": true
}
新增用户:
POST /users
Content-Type: application/json
{ "id": 3, "username": "王五", "age": 25 }
响应:
{
"code": 200,
"data": { "id": 3, "username": "王五", "age": 25 },
"message": "创建成功",
"success": true
}
删除用户:
DELETE /users/1
响应:
{
"code": 200,
"data": null,
"message": "请求成功",
"success": true
}
四、@RestController 常配合的注解
| 注解 | 作用 | 示例 |
|---|---|---|
@RequestMapping | 类/方法级别的路径映射 | @RequestMapping("/users") |
@GetMapping | GET 请求 | @GetMapping("/{id}") |
@PostMapping | POST 请求 | @PostMapping |
@PutMapping | PUT 请求 | @PutMapping("/{id}") |
@DeleteMapping | DELETE 请求 | @DeleteMapping("/{id}") |
@PathVariable | 取 URL 路径变量 | @PathVariable Long id |
@RequestParam | 取 URL 查询参数 | @RequestParam String name |
@RequestBody | 取请求体 JSON | @RequestBody User user |
@Validated | 参数校验 | @Validated @RequestBody User user |
一个综合示例:
@RestController
@RequestMapping("/api/articles")
public class ArticleController {
// GET /api/articles?page=1&size=10
@GetMapping
public Response<List<Article>> list(
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
return Response.success(articleService.page(page, size));
}
// GET /api/articles/5
@GetMapping("/{id}")
public Response<Article> detail(@PathVariable Long id) {
return Response.success(articleService.findById(id));
}
// POST /api/articles
@PostMapping
public Response<Article> create(@Validated @RequestBody Article article) {
return Response.success(articleService.save(article));
}
// PUT /api/articles/5
@PutMapping("/{id}")
public Response<Article> update(@PathVariable Long id,
@RequestBody Article article) {
article.setId(id);
return Response.success(articleService.update(article));
}
// DELETE /api/articles/5
@DeleteMapping("/{id}")
public Response<Void> delete(@PathVariable Long id) {
articleService.delete(id);
return Response.success();
}
}
五、常见误区
误区1:用 @RestController 却想返回页面
@RestController
public class PageController {
@GetMapping("/index")
public String index() {
return "index"; // ❌ 返回的是字符串 "index",不是跳转页面
}
}
- 用
@RestController就没法返回页面了,返回的"index"会原样输出。 - 要返回页面,请用
@Controller。
误区2:以为 @RestController 只能返回 JSON
- 其实它只是"返回值直接写响应体",具体格式由
HttpMessageConverter决定。 - 返回
User→ JSON(Jackson 转换) - 返回
String→ 纯文本 - 返回
byte[]→ 二进制
误区3:类上加了,方法上又加 @ResponseBody
@RestController
public class UserController {
@GetMapping("/user")
@ResponseBody // ← 多余,可省略
public User getUser() { ... }
}
- 类上已有
@RestController,方法上不用再加@ResponseBody。
六、@Controller 和 @RestController 怎么选?
| 场景 | 推荐注解 |
|---|---|
| 前后端分离,只返回 JSON 数据 | @RestController |
| 传统服务端渲染(Thymeleaf/JSP) | @Controller |
| 同一个类里既返回页面又返回数据 | @Controller + 方法级 @ResponseBody |
如今绝大多数新项目都是前后端分离,所以 @RestController 是主流。
七、总结
| 问题 | 答案 |
|---|---|
@RestController 是什么? | @Controller + @ResponseBody 的组合注解 |
| 干啥用的? | 让类的所有方法返回值自动转成 JSON 写响应体 |
和 @Controller 区别? | @Controller 返回视图名(跳页面),@RestController 返回数据(JSON) |
还需要写 @ResponseBody 吗? | 不用,类级别已生效 |
| 能返回页面吗? | 不能,要返回页面用 @Controller |
| 最常配什么注解? | @RequestMapping、@GetMapping、@RequestBody 等 |
一句话记住:
@RestController= "这个类里所有方法都返回 JSON 数据",是前后端分离项目 Controller 层的标配注解。 用了它,方法返回User、List、Response等对象,都会自动被 Jackson 转成 JSON 返回给前端。
全部评论(0)
还没有任何评论哟~