如何在 Controller 之间进行重定向(Redirect)和转发(Forward)?
在 Java Web 开发中(主要是 Spring MVC / Spring Boot 环境),Controller 之间的跳转主要有两种方式:重定向(Redirect) 和 转发(Forward)。
以下是具体的实现代码和两者之间的区别。
1. 重定向 (Redirect)
特点:
- 客户端行为:服务器告诉浏览器“去访问另一个地址”。
- URL 会变:浏览器地址栏会变成新的 URL。
- 请求不共享:这是一个全新的 Request,上一个请求的数据(request 作用域)会丢失,除非使用 Session 或 URL 参数传递。
实现方式 A:返回 String (最常用)
使用 redirect: 前缀。
java
@Controller
@RequestMapping("/order")
public class OrderController {
@GetMapping("/save")
public String saveOrder() {
// 处理业务逻辑...
System.out.println("订单保存成功");
// 重定向到 /order/list
return "redirect:/order/list";
}
@GetMapping("/list")
public String listOrders() {
return "order_list_page"; // 返回视图名称
}
}
实现方式 B:使用 ModelAndView
java
@GetMapping("/save")
public ModelAndView saveOrder() {
ModelAndView mv = new ModelAndView();
mv.setViewName("redirect:/order/list");
return mv;
}
如何在重定向中传递数据?
由于 Request 域不共享,通常使用 RedirectAttributes (Flash Attributes) 来传递临时数据。
java
@PostMapping("/login")
public String login(String username, RedirectAttributes attributes) {
// 模拟登录失败
attributes.addFlashAttribute("msg", "用户名或密码错误");
// 重定向回登录页,msg 数据在重定向后依然可用(一次性)
return "redirect:/loginPage";
}
2. 转发 (Forward)
特点:
- 服务器端行为:服务器内部将请求交给另一个 Controller 处理。
- URL 不变:浏览器地址栏显示的还是原来的 URL。
- 请求共享:使用的是同一个 Request 对象,数据(request.setAttribute)可以共享。
实现方式 A:返回 String (最常用)
使用 forward: 前缀。
java
@Controller
@RequestMapping("/api")
public class ApiController {
@GetMapping("/check")
public String checkUser(HttpServletRequest request) {
System.out.println("正在检查用户权限...");
// 可以在 request 中放入数据传给下一个 Controller
request.setAttribute("username", "admin");
// 转发到 /api/process
return "forward:/api/process";
}
@GetMapping("/process")
public String processUser(HttpServletRequest request) {
// 可以获取上一个 Controller 设置的数据
String user = (String) request.getAttribute("username");
System.out.println("处理用户: " + user);
return "result_page";
}
}
实现方式 B:使用 ModelAndView
java
@GetMapping("/check")
public ModelAndView checkUser() {
ModelAndView mv = new ModelAndView();
mv.setViewName("forward:/api/process");
return mv;
}
3. 总结与对比
| 特性 | 重定向 (Redirect) | 转发 (Forward) |
|---|---|---|
| 发生位置 | 客户端(浏览器) | 服务器内部 |
| 请求次数 | 2 次请求 | 1 次请求 |
| URL 地址栏 | 会发生变化 | 不会变化 |
| 数据共享 | 无法直接共享 Request 数据 (需用 FlashAttribute 或 Session) | 共享同一个 Request 数据 |
| 应用场景 | 防止表单重复提交(Post/Redirect/Get 模式)、跳转到外部网站 | 内部逻辑流转、权限校验后转交业务处理 |
| 代码前缀 | return "redirect:/..." |
return "forward:/..." |
什么时候用哪个?
- 使用重定向 (Redirect):当你完成了一个动作(如提交表单、删除数据、登录成功),不希望用户刷新页面导致重复提交时。
- 使用转发 (Forward):当你需要将请求拆分处理,或者仅仅是想复用另一个 Controller 的逻辑,且希望对用户隐藏内部跳转细节时。