杰瑞科技汇

Java Web页面跳转如何实现?

核心概念:请求与响应

在理解页面跳转之前,必须明白 Java Web 的基本工作模型:客户端(浏览器)发送请求 -> 服务器(Tomcat等)接收并处理 -> 服务器返回响应 -> 客户端接收并渲染响应

Java Web页面跳转如何实现?-图1
(图片来源网络,侵删)

页面跳转的本质,就是服务器在处理完请求后,通过响应来告诉浏览器下一步该做什么。


服务器端跳转 - forward

这种方式是服务器内部的行为,浏览器发送请求到服务器,服务器将请求转发给内部的另一个资源(如 Servlet 或 JSP)进行处理,并将最终的响应返回给浏览器,在这个过程中,浏览器的地址栏不会发生变化

实现方式

主要在 Servlet 中使用 RequestDispatcher 对象来实现。

Servlet 代码示例

Java Web页面跳转如何实现?-图2
(图片来源网络,侵删)

假设我们有两个 Servlet:ForwardServletTargetServlet

ForwardServlet.java

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/forward")
public class ForwardServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ForwardServlet: 收到请求,准备转发...");
        // 1. 可以在转发前向 request 中添加一些数据
        req.setAttribute("messageFromForward", "你好,这是来自 ForwardServlet 的消息!");
        // 2. 获取 RequestDispatcher 对象
        // 参数是目标资源的相对路径,以斜杠 "/" 开头表示相对于当前 Web 应用的根目录
        // 如果你的 TargetServlet 映射为 "/target",那么路径就是 "/target"
        // 如果你的 target.jsp 放在 WEB-INF/views 目录下,路径就是 "/WEB-INF/views/target.jsp"
        RequestDispatcher dispatcher = req.getRequestDispatcher("/target");
        // 3. 执行 forward 跳转
        // 注意:调用 forward() 方法后,当前 Servlet 的代码会立即停止执行,控制权完全交给目标资源。
        // dispatcher.forward(req, resp);
    }
}

TargetServlet.java

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/target")
public class TargetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("TargetServlet: 收到转发的请求,开始处理...");
        // 从 request 中获取 ForwardServlet 设置的数据
        String message = (String) req.getAttribute("messageFromForward");
        // 向客户端响应
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println("<h1>这是目标页面</h1>");
        resp.getWriter().println("<p>接收到的消息: " + message + "</p>");
        resp.getWriter().println("<p>浏览器地址栏仍然是: /forward</p>");
    }
}

工作流程

  1. 浏览器访问 http://localhost:8080/your-app/forward
  2. ForwardServlet 被调用。
  3. ForwardServlet 将数据存入 request 作用域,并调用 forward 方法将请求转发给 TargetServlet
  4. 浏览器地址栏保持不变,仍然是 /forward
  5. TargetServlet 接收请求,读取 request 中的数据,生成响应并返回给浏览器。
  6. 浏览器显示 TargetServlet 生成的 HTML 内容。

优点

  • 共享数据:可以在多个 Servlet 或 JSP 之间共享 request 作用域的数据,非常适合 MVC 模式中 Controller 和 View 之间的数据传递。
  • 隐藏内部路径:可以将 JSP 等视图资源放在 WEB-INF 目录下,防止用户直接通过 URL 访问,提高安全性。

缺点

  • URL 不变:用户看到的 URL 是第一个请求的 URL,如果刷新页面,可能会重复执行第一个请求,导致数据重复提交(在登录后刷新,可能会重复注册)。
  • 不能脱离当前 Web 应用forward 只能跳转到当前应用内部的资源。

客户端跳转 - redirect

这种方式是服务器告诉浏览器:“你访问的资源不在这里,请去新的 URL 重新访问一次”,浏览器会收到这个新的 URL,并自动向该 URL 发起一次全新的请求,在这个过程中,浏览器的地址栏会更新为新的 URL

Java Web页面跳转如何实现?-图3
(图片来源网络,侵删)

实现方式

主要在 Servlet 中使用 HttpServletResponsesendRedirect() 方法。

Servlet 代码示例

RedirectServlet.java

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("RedirectServlet: 收到请求,准备重定向...");
        // 1. 同样可以设置数据,但注意:request 中的数据在重定向后无法传递到新页面!
        // 因为这是两次独立的请求。
        req.setAttribute("messageFromRedirect", "这条消息会丢失!");
        // 2. 执行 redirect 跳转
        // 参数是目标资源的完整 URL(可以是绝对路径,也可以是相对路径)
        resp.sendRedirect("target2");
    }
}

TargetServlet2.java

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import HttpServletResponse;
import java.io.IOException;
@WebServlet("/target2")
public class TargetServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("TargetServlet2: 收到重定向过来的新请求,开始处理...");
        // 尝试获取 RedirectServlet 设置的数据,会发现是 null
        String message = (String) req.getAttribute("messageFromRedirect");
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println("<h1>这是重定向的目标页面</h1>");
        resp.getWriter().println("<p>无法获取到重定向前的消息: " + message + "</p>");
        resp.getWriter().println("<p>浏览器地址栏已更新为: /target2</p>");
    }
}

工作流程

  1. 浏览器访问 http://localhost:8080/your-app/redirect
  2. RedirectServlet 被调用。
  3. RedirectServlet 生成一个响应,状态码为 302 (Found) 或 301 (Moved Permanently),并在响应头 Location 中指定新的 URL(如 /target2)。
  4. 浏览器接收到这个响应,发现是重定向指令,于是立即中断当前请求,并自动向 /target2 发起一个全新的 GET 请求。
  5. 浏览器地址栏变为 /target2
  6. TargetServlet2 被调用,处理这个新请求,并生成响应返回给浏览器。

优点

  • URL 更新:地址栏会显示最终的 URL,刷新页面不会导致重复提交操作,非常安全。
  • 可以跳转到外部网站sendRedirect 的参数可以是任何有效的 URL,如 resp.sendRedirect("https://www.google.com");

缺点

  • 无法共享数据:两次请求是完全独立的,request 作用域的数据无法在它们之间传递。
  • 性能开销:需要浏览器和服务器之间进行两次通信。

前端页面跳转 - JavaScript

这种方式完全在浏览器端执行,与服务器无关,通常用于用户操作后的即时跳转,例如点击按钮后跳转。

实现方式

在 HTML 或 JSP 页面中嵌入 JavaScript 代码。

示例 JSP (index.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>JavaScript 跳转示例</title>
    <script>
        // 1. 使用 window.location.href
        function redirectByHref() {
            // 可以是相对路径或绝对路径
            window.location.href = "javascript-target.jsp";
        }
        // 2. 使用 window.location.assign
        function redirectByAssign() {
            window.location.assign("javascript-target.jsp");
        }
        // 3. 使用 window.location.replace
        // replace() 和 href 的区别是:replace() 不会在浏览器历史记录中留下当前页面的记录,
        // 用户点击后退按钮时,会直接跳到更早的页面,而不会回到这个页面。
        function redirectByReplace() {
            window.location.replace("javascript-target.jsp");
        }
    </script>
</head>
<body>
    <h1>JavaScript 页面跳转</h1>
    <button onclick="redirectByHref()">使用 href 跳转</button>
    <button onclick="redirectByAssign()">使用 assign 跳转</button>
    <button onclick="redirectByReplace()">使用 replace 跳转</button>
</body>
</html>

目标页面 (javascript-target.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>JavaScript 跳转目标</title>
</head>
<body>
    <h1>成功通过 JavaScript 跳转到了这里!</h1>
    <p>浏览器地址栏会立即更新。</p>
</body>
</html>

优点

  • 即时响应:无需等待服务器响应,用户体验好。
  • 灵活:可以根据用户行为、表单验证结果等动态决定是否跳转以及跳转到哪里。

缺点

  • 功能受限:无法直接访问后端作用域(如 request, session)的数据,除非通过 AJAX 等技术配合。

框架层面的跳转 (推荐)

在现代 Java Web 项目中,我们很少直接在 Servlet 中手动处理页面跳转,通常我们会使用 Spring MVC 或其他 MVC 框架,它们提供了更优雅、更强大的方式。

Spring MVC 示例

Spring MVC 通过控制器方法返回一个字符串(或 View 对象)来决定视图的渲染,这个过程本质上还是 forward,但对开发者更友好。

配置视图解析器 (spring-mvc.xml)

<!-- 配置视图解析器,将逻辑视图名映射到实际的 JSP 文件 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/> <!-- JSP 文件的前缀 -->
    <property name="suffix" value=".jsp"/>           <!-- JSP 文件的后缀 -->
</bean>

控制器代码

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class MyController {
    // 使用 ModelAndView
    @GetMapping("/mv")
    public ModelAndView modelAndViewDemo() {
        ModelAndView mav = new ModelAndView("targetView"); // 逻辑视图名
        mav.addObject("message", "来自 ModelAndView 的数据");
        return mav; // Spring 会自动 forward 到 /WEB-INF/views/targetView.jsp
    }
    // 直接返回逻辑视图名
    @GetMapping("/viewName")
    public String viewNameDemo() {
        // 方法返回值 "targetView" 会被视图解析器解析为 /WEB-INF/views/targetView.jsp
        // 这本质上是一个 forward
        return "targetView";
    }
    // 重定向 (客户端跳转)
    @GetMapping("/springRedirect")
    public String redirectDemo() {
        // �值 "redirect:" 前缀告诉 Spring 执行一个客户端重定向
        return "redirect:/targetView"; // 浏览器会重新请求 /targetView
    }
}

JSP 页面 (/WEB-INF/views/targetView.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>目标页面</title>
</head>
<body>
    <h1>Spring MVC 目标页面</h1>
    <p>接收到的数据: ${message}</p>
</body>
</html>

Spring MVC 的方式将数据传递和视图选择解耦,代码更清晰,是当前 Java Web 开发的最佳实践


总结与选择

方式 类型 浏览器地址栏 数据共享 适用场景
forward 服务器端跳转 不变 可以 (request作用域) MVC架构中,Controller向View传递数据;隐藏内部资源。
redirect 客户端跳转 改变 不可以 防止表单重复提交;登录成功后跳转;跳转到外部网站。
JavaScript 前端跳转 改变 不可以 (除非AJAX) 用户交互后的即时跳转;前端逻辑控制。
Spring MVC 框架层面 可变 (取决于返回的是视图名还是redirect:) 可以 (Model) 现代Java Web开发首选,代码清晰,职责分明。

如何选择?

  1. 如果你在使用原生 Servlet

    • 需要在多个后端组件间传递数据,并且不希望用户看到真实的内部 URL -> forward
    • 完成一个操作(如登录、注册)后,需要将用户引导到新页面,并且防止刷新导致重复操作 -> redirect
  2. 如果你在使用 Spring MVC 或类似框架

    • 默认使用返回视图名的方式(本质是 forward),这是最常见的情况,用于展示数据。
    • 在需要防止重复提交或需要改变 URL 的场景下,使用 redirect: 前缀(本质是 redirect)。
    • 在页面上有复杂的交互逻辑时,使用 JavaScript
  3. 永远不要在 Servlet 中使用 out.println() 手动拼接 HTML 来做页面跳转,这是一种非常落后且难以维护的做法。

分享:
扫描分享到社交APP
上一篇
下一篇