我们来详细解释一下如何在 Spring MVC 中定义 Controller,以及 @Controller 和 @RestController 的区别和使用场景。
如何定义一个 Controller?
在 Spring MVC 中,Controller 扮演着 MVC 模式中 “C” 的角色。它负责接收来自客户端(通常是浏览器或 API 消费者)的 HTTP 请求,处理这些请求(可能需要调用 Service 层进行业务逻辑处理),并最终决定返回什么响应给客户端。
定义一个 Controller 非常简单,主要包含以下步骤:
- 创建一个 Java 类:这只是一个普通的 Java 类。
- 使用
@Controller或@RestController注解:在这个类上添加@Controller或@RestController注解。这会告诉 Spring IoC 容器,这个类是一个 Spring MVC Controller 组件,需要被扫描和管理。 - 定义处理请求的方法(Handler Methods):在 Controller 类中创建公共方法(public methods)。
- 使用映射注解:在这些方法上使用
@RequestMapping或其更具体的变体(如@GetMapping,@PostMapping,@PutMapping,@DeleteMapping,@PatchMapping)来指定这个方法处理哪些 URL 路径和 HTTP 方法的请求。 - 处理请求和返回响应:方法内部可以包含处理请求的逻辑,例如读取请求参数、路径变量、请求体,调用服务层,并最终返回一个响应。这个响应可以是一个视图名称(由视图解析器处理)、一个包含模型数据的对象(自动序列化为 JSON/XML),或者一个
ResponseEntity对象来更精细地控制响应状态码和头信息。
基本示例 (@Controller):
package com.example.mywebapp.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller // 标记此类为 Spring MVC Controller
public class GreetingController {
// 处理对 "/greeting" 路径的 GET 请求
@GetMapping("/greeting")
public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
// 将数据添加到 Model 中,使其在视图中可用
model.addAttribute("nameAttribute", name);
// 返回视图的逻辑名称 ("greeting")
// Spring MVC 会查找名为 "greeting" 的视图(例如 greeting.html 或 greeting.jsp)来渲染
return "greeting";
}
}
@Controller 和 @RestController 的区别
这两个注解都用于标记一个类为 Spring MVC Controller,但它们在处理方法返回值方面有关键的区别:
-
@Controller:- 用途: 主要用于传统的 Spring MVC 应用,其目标是返回一个视图(View),通常是 HTML 页面,由服务器端渲染(如使用 Thymeleaf, JSP, FreeMarker 等模板引擎)。
- 返回值处理:
- 默认情况下,
@Controller中方法返回的String会被 Spring MVC 的ViewResolver解释为逻辑视图名称。Spring 会根据配置的视图解析器去查找并渲染对应的视图模板。 - 如果想让
@Controller中的某个方法直接返回数据(如 JSON 或 XML)而不是视图名称,需要在该方法上显式添加@ResponseBody注解。@ResponseBody告诉 Spring 将方法的返回值直接写入 HTTP 响应体中,而不是将其解释为视图名称。Spring 会使用配置的消息转换器(Message Converters,如 Jackson)来序列化返回值。
- 默认情况下,
-
@RestController:- 用途: 主要用于构建 RESTful Web Services(API),这些服务通常返回数据(如 JSON 或 XML)给客户端(如前端 JavaScript 框架、移动应用或其他后端服务),而不是渲染 HTML 视图。
- 返回值处理:
@RestController是一个组合注解,它本身包含了@Controller和@ResponseBody。- 这意味着,在一个用
@RestController注解的类中,所有的处理方法(handler methods)默认都带有@ResponseBody的行为。 - 方法的返回值会被自动序列化(通常为 JSON,如果类路径下有 Jackson 库)并写入 HTTP 响应体。你不需要在每个方法上单独添加
@ResponseBody注解。
- 这意味着,在一个用
总结表格:
| 特性 | @Controller | @RestController (@Controller + @ResponseBody) |
|---|---|---|
| 主要用途 | 传统 Web 应用,返回视图 (HTML) | 构建 RESTful API,返回数据 (JSON/XML) |
| 默认返回值处理 | 解释为视图名称,由 ViewResolver 处理 | 直接写入响应体,由 HttpMessageConverter 序列化 |
| 返回数据需加 | 需要在方法上加 @ResponseBody | 不需要,已默认包含 @ResponseBody 行为 |
| 组合注解 | 否 | 是 (@Controller + @ResponseBody) |
使用场景?
选择哪个注解取决于你的 Controller 的主要目的:
-
使用
@Controller:- 正在构建一个传统的、服务器端渲染的 Web 应用程序。
- Controller 主要负责返回需要由模板引擎(如 Thymeleaf, JSP)渲染的视图名称。
- Controller 中只有少数方法需要直接返回数据(这时可以在这些特定方法上使用
@ResponseBody)。
-
使用
@RestController:- 构建一个 RESTful API,目的是为客户端(如单页应用、移动应用、其他微服务)提供数据。
- Controller 中所有或绝大多数方法都需要直接返回数据(通常是 JSON 或 XML)而不是视图。
- 简化代码,避免在每个方法上都写
@ResponseBody。
示例 (@RestController):
package com.example.myapi.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.example.myapi.model.User; // 假设有一个 User Pojo
@RestController // 标记此类为 REST Controller,所有方法默认返回数据
public class UserController {
// 处理对 "/api/users/{id}" 路径的 GET 请求
@GetMapping("/api/users/{id}")
public User getUserById(@PathVariable Long id) {
// 假设 userService.findById(id) 返回一个 User 对象
// User userService = ...;
// User user = userService.findById(id);
// 模拟返回一个 User 对象
User user = new User(id, "John Doe", "john.doe@example.com");
// 这个 User 对象会被自动序列化为 JSON 并写入响应体
return user;
}
// 处理对 "/api/status" 路径的 GET 请求
@GetMapping("/api/status")
public String getStatus() {
// 即使返回 String,也会被直接写入响应体,而不是作为视图名
return "API is running";
}
}
在这个 @RestController 示例中,getUserById 方法返回的 User 对象会被 Spring 自动转换为 JSON 格式的响应体。getStatus 方法返回的字符串 "API is running" 也会被直接作为纯文本写入响应体,而不是被视图解析器处理。
开发中根据我们的应用类型(返回 HTML 视图还是返回 API 数据)来选择合适的注解。
1303

被折叠的 条评论
为什么被折叠?



