JSP登录模块中的jsp:forward跳转:原理、实践与避坑

JSP Forward机制在登录系统中的应用与优化 服务器端跳转是Web开发中的核心机制,JSP的forward指令通过保持请求链路完整性和隐藏系统路径提升安全性。相比客户端重定向,forward在服务器容器内部完成页面跳转,避免额外网络开销,特别适合登录流程控制等需要保持请求状态场景。技术实现上需注意在响应提交前完成跳转,结合会话管理可构建生产级认证系统。本文通过Access数据库登录案例,详解如何利用forward机制实现参数传递、错误处理和密码加密,为传统JSP项目提供安全优化方案。 阅读详情

这几天帮人调一个学生管理系统的登录模块,页面之间清一色 <jsp:forward> :login.jsp 提交到 doLogin.jsp,校验完再 forward 到 welcome.jsp。说实话,现在正经企业项目里很少见到这种写法了,但我不打算直接上来就批它,因为在课程设计、毕业设计这类场景里,用 <jsp:forward> 做登录跳转,反而能把 HTTP 请求流转、request 作用域、页面间数据传递这些基础概念讲得特别清楚。这篇就把这条链路完整拆开,从登录页到校验页再到欢迎页,每行代码为什么这么写、跳转背后发生了什么、哪些地方容易踩坑,全说透。

提示:本文基于 Tomcat + JSP/Servlet 的传统 Web 工程写法,适合正在做课程设计、毕业设计,或者想补 JSP 基础的同学参考。项目整体很简单,但每步我都会把原理讲清楚,方便你直接照抄,也方便你应付老师的追问。

1. 先看明白 jsp:forward 在登录里到底是"怎么跳"的

1.1 一次表单提交背后发生了什么

你把用户名密码填进输入框,点登录按钮,浏览器做的事情非常单纯:根据 <form> 标签里的 action 属性,把表单字段打包成一个 HTTP POST 请求发出去。剩下的所有事,服务器说了算。

在传统 JSP 工程里,这个请求落到了 doLogin.jsp 头上。注意,doLogin.jsp 不是一个"页面",它本质上是一个被 Tomcat 编译成 Servlet 的 Java 类,它接收请求、读取参数、做逻辑判断,然后决定让谁来回应用户。这个过程里可能出现三种结果:一是直接把响应输出回浏览器;二是用 response.sendRedirect() 告诉浏览器"你再去访问另一个地址";三就是本文的主角 <jsp:forward> ,服务器内部把这次请求转交给另一个资源处理。

很多同学学到这里搞混"转发"和"重定向",根源在于没有意识到:浏览器从头到尾只发了一个请求,而服务器内部可能换了两个人的工位来处理。

1.2 forward 的本质是一次服务器内部交接

<jsp:forward> 动作标签在底层等价于调用 RequestDispatcher.forward() 。它的机制是这样的:当服务器执行到 <jsp:forward> 时,会拿到当前这个 request 对象和 response 对象,然后交给目标资源(可以是另一个 JSP、Servlet,也可以是 HTML),目标资源处理完,再由它把响应返回给浏览器。

你可以把它想成在办事大厅的窗口咨询问题:窗口A的员工看了一眼你的材料,发现自己办不了,直接把你的材料和工单递给旁边的员工B,由B接着办,然后把办好的结果给你。你本人没有重新排队,也没有换窗口。整个过程里,浏览器地址栏不会发生任何变化,用户看到的 URL 始终是提交表单时那个地址。

这个特性对登录场景非常关键:不管 forward 到成功页还是失败页,地址栏都停留在原来的 URL 上,用户不会一眼看出你内部的页面结构。但同时它也有代价——刷新页面时,浏览器会重新提交上一份表单,这就是后文要说的"重复提交"坑。

1.3 为什么课程设计都爱用它做登录跳转

原因其实很实在。第一,语法简单,没有 Servlet 配置的负担,在一个 JSP 文件里写判断逻辑、直接套 <jsp:forward> 标签,几分钟就能跑通。第二, <jsp:forward> 天然支持携带参数,通过子标签 <jsp:param> 可以把错误信息、提示信息直接传给目标页面,这不就是登录失败回显错误提示的标准需求吗?第三,JSP 教材普遍把"forward 动作标签"列为重点章节,做登录界面是对这个知识点最自然的检验。

所以这篇我不是劝你扔掉它,而是让你先把它用对、用明白,等你理解了数据流转,再用它作为跳板去理解 Servlet 和重定向,就会顺很多。

2. 最小可运行工程:目录、web.xml 与登录页原型

2.1 工程目录与 Tomcat 部署

先搭一个最小的 Web 工程。不管你是用 IDEA 还是 Eclipse,最终扔进 Tomcat 的 webapps 目录下,结构长这样:

login-demo/
├── login.jsp
├── doLogin.jsp
├── welcome.jsp
└── WEB-INF/
    ├── web.xml
    └── lib/

如果你的项目是通过 IDEA 的 Artifact 以 exploded war 方式部署,那么 IDEA 会在输出目录帮你生成这个结构,你要关心的是 src/main/webapp 下的这堆文件。Tomcat 启动后,访问 http://localhost:8080/login-demo/login.jsp 就能出登录页。

web.xml 在 Servlet 3.0 之后不写也能跑纯 JSP 应用,但建议还是留一个空的,指定一下应用名和编码声明。Tomcat 8/9 对应 javax 命名空间,Tomcat 10+ 要换成 jakarta 命名空间,学生项目绝大多数是前者:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <display-name>LoginDemo</display-name>
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>
</web-app>

welcome-file-list 配了之后,直接访问 http://localhost:8080/login-demo/ 就会自动落到登录页,省得每次手打 login.jsp。

2.2 login.jsp:只做一件事的输入页

登录页不要写任何业务逻辑,它的职责就是:渲染表单,以及在登录失败被 forward 回来时显示错误信息。先看最基础的版本:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>系统登录</title>
</head>
<body>
<form action="doLogin.jsp" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username" placeholder="请输入用户名"/></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password" placeholder="请输入密码"/></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="登录"/>
                <input type="reset" value="重置"/>
            </td>
        </tr>
    </table>
</form>
</body>
</html>

这里面有两个容易被忽略的细节。第一, method 必须写成 post ,而不是 get 。如果用 get,用户名和密码会拼到 URL 里,既暴露隐私又显得很不专业。第二, name 属性决定了服务器端用 request.getParameter("username") 取值时拿到的键名,name 写错了,后面对不上,排查起来非常折磨人。

2.3 form 的 action 应该写给谁

表单提交的目标就是你校验逻辑所在的资源。这里有两种主流做法:

  • 方法一(教学版,本文主推) :action 直接写给一个 JSP,比如 doLogin.jsp 。好处是配置少、看着直观,适合课程设计。
  • 方法二(工程版) :action 写给一个 Servlet 的映射地址,比如 action="loginServlet" ,再在 web.xml 或 @WebServlet 注解里做映射,由 Servlet 完成校验和 forward。

如果你以后要写 Servlet 版本,强烈建议把校验逻辑放在 Servlet 里而不是 JSP 里。不过这篇既然以 <jsp:forward> 为核心,就不引 Servlet 了,避免概念交叉太多。

还有个细节:action 里我写的是相对路径 doLogin.jsp ,意思是"当前请求 URL 的目录下找这个文件"。如果你把登录页放在 admin/ 子目录下,那 action 就要写成 admin/doLogin.jsp ,或者更稳妥地写成带上下文根的绝对路径。很多转发后页面样式错乱的问题,就是路径写法埋下的雷,第 6 章会专门讲。

3. 校验页 doLogin.jsp:条件 forward + 参数携带

3.1 取参数前先处理编码

doLogin.jsp 是整个登录模块的大脑。它的核心工作分四步:取参数、做校验、按结果转发、在转发时携带提示信息。

先看完整代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 1. 处理 POST 提交的中文编码
    request.setCharacterEncoding("UTF-8");

    // 2. 取出表单参数
    String username = request.getParameter("username");
    String password = request.getParameter("password");

    // 3. 模拟校验:实际项目中改成查数据库
    if ("admin".equals(username) && "123456".equals(password)) {
        // 登录成功:把用户写入 session,再转发到成功页
        session.setAttribute("user", username);
%>
<jsp:forward page="welcome.jsp">
    <jsp:param name="msg" value="login success" />
</jsp:forward>
<%
    } else {
%>
<jsp:forward page="login.jsp">
    <jsp:param name="error" value="用户名或密码错误,请重新输入" />
</jsp:forward>
<%
    }
%>

第一步千万别省。POST 请求的参数在 getParameter() 之前需要先设置解码字符集,否则用户名里的中文会变成乱码。这里 request.setCharacterEncoding("UTF-8") 必须在所有 getParameter() 调用之前执行,写晚了就无效了。如果你在 login.jsp 的 contentType 里声明了 UTF-8,表单页面本身的字符集是没问题,但服务器解析 POST 实体的字符集是独立设置的,容易被忽略。

3.2 两个分支的两条 forward

注意代码结构:校验成功和失败各有一条独立的 <jsp:forward> ,它们都在 <%%> 脚本片段组成的 if/else 分支内部。这里必须理解 JSP 的执行方式——JSP 页面在执行时会先输出所有静态 HTML 和表达式,再按从上到下的顺序执行脚本片段和动作标签。

<jsp:forward page="welcome.jsp"> 这一行生成到 Java 代码里,等价于先创建 RequestDispatcher ,然后调用 forward() ,并且在调用之后还有一个 return 。也就是说,一旦执行到 forward,当前 JSP 后续的内容不会继续输出,所以 if/else 分支里两个 forward 是不会互相干扰的。

<jsp:param> 子标签的作用是往请求参数列表里追加数据。注意一个坑:如果目标页面本来就有同名参数, jsp:param 会覆盖原值;如果没有同名参数,就直接新增。这些参数最终通过 request.getParameter() 来取,转发过程中 request 对象是同一个,所以无论你在原始表单里的 username 、 password ,还是通过 jsp:param 加进去的 msg 、 error ,目标页面都能取到。

3.3 用 session 补上真正的"登录状态"

上面的代码里我做了一个很多人写课程设计时会漏掉的动作: session.setAttribute("user", username) 。为什么登录成功要写 session?

因为 forward 的本质是"一次请求内部的交接",请求一结束,request 里的参数和属性就没了。如果只靠 <jsp:param> 把用户名带到 welcome.jsp,那用户刷新一下、或者直接访问 welcome.jsp,这个信息就丢了,更糟糕的是——任何人都能绕过登录页直接打开欢迎页。

session 是保存在服务器端、关联到当前浏览器会话的一块存储区域,只要浏览器不关、session 不过期,它就一直有效。把登录成功的用户写进 session,才是真正意义上的"建立登录态"。后文第 6 章讲受保护页面校验时,你会发现这个动作几乎决定了整个登录模块是否安全。

如果你的项目要求记住用户名密码(七天免登录之类),那是 Cookie 的活,不要往 session 里堆,这块先不展开。

4. 目标页面怎么接数据:welcome.jsp 接收与错误回显

4.1 参数、属性、session 三种取法

welcome.jsp 是登录成功后的落点。它需要展示"当前登录的人是谁",数据来源其实有三种:

  • request.getParameter("msg") :接收 <jsp:param> 带过来的参数
  • request.getAttribute("user") :接收通过 request.setAttribute() 设置属性
  • session.getAttribute("user") :接收会话级别的登录状态

很多人会混参数和属性。简单区分:参数来自 URL 或表单,存在于 request 里;属性是你在代码里往请求对象上挂的值,也存在于 request 里。前者用 getParameter() ,后者用 getAttribute() ,API 不一样,别换着用。

welcome.jsp 的完整写法:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>欢迎页</title>
</head>
<body>
<%
    String user = (String) session.getAttribute("user");
    String msg = request.getParameter("msg");
    if (user == null) {
        user = "访客";
    }
%>
<h2><%= msg != null ? msg : "欢迎" %>,<%= user %></h2>
<p>这里是登录后的个人信息展示区域,可以放用户名、注册时间、最近登录时间等字段。</p>
<p><a href="logout.jsp">退出登录</a></p>
</body>
</html>

这种写法是"传统 Scriptlet 式"。现在更推荐用 EL 表达式 ${sessionScope.user} 取 session 里的值,代码更干净,但如果你还在交课程设计,两种都建议掌握,至少老师问起来你能说清 EL 本质上是帮你调用了 pageContext.findAttribute() ,按 page、request、session、application 四个作用域依次查找。

4.2 失败回跳登录页时错误信息的展示

再看失败分支。doLogin.jsp 在用户名或密码错误时 forward 回 login.jsp,并带上 error 参数。这时 login.jsp 需要有能力感知到这个参数并展示出来。改造后的 login.jsp:

<%
    String error = request.getParameter("error");
%>
...
<% if (error != null && !"".equals(error)) { %>
<div style="color: red; margin-bottom: 10px;"><%= error %></div>
<% } %>

这里有个体验层面的知识点:因为 forward 不改地址栏,用户看到 URL 还是 doLogin.jsp (或者最初提交表单的地址),但内容已经切回了登录页,并且多了红色错误提示。对用户来说,这是可以接受的交互。但如果你不希望用户看到 doLogin.jsp 这串地址,可以用 response.sendRedirect("login.jsp") 来重定向,代价是没法用 request 带参数,错误信息要么拼到 URL 后面,要么放 session。这也是下一章要对比的核心差异。

4.3 顺带把个人信息展示页的数据流理清

搜"jsp个人信息展示页面"的同学其实就是在问上面这段逻辑的变体。个人信息页和 welcome.jsp 的区别只是数据量更大:用户名、性别、邮箱、头像路径、权限角色等等。它们都是同一个套路——登录时把用户对象整体放进 session:

User u = userDao.findByUsername(username);
session.setAttribute("loginUser", u);

然后在展示页直接取对象,用 EL 嵌套取属性:

<p>用户名:${sessionScope.loginUser.username}</p>
<p>邮箱:${sessionScope.loginUser.email}</p>

这比一个字段一个字段地 get 要干净得多。前提是你的 User 类有对应的 getter 方法,EL 底层就是靠 getter 取值的。

5. forward 不是万能跳转:和 sendRedirect 的对比与选型

5.1 两者到底差在哪:一张表讲透

很多同学写了两年 JSP 都没真正搞懂 jsp:forward 和 response.sendRedirect() 的区别。直接看表:

对比维度 jsp:forward(服务器转发) response.sendRedirect(客户端重定向)
执行位置 服务器内部完成 浏览器收到响应后重新发请求
地址栏 不改变 变为目标地址
请求次数 1 次 2 次
request 数据 参数和属性都保留 全部丢失
目标范围 本站点内部资源(含 WEB-INF) 任意 URL,包括外部站点
刷新行为 原请求被重放,可能重复提交 变成新的 GET 请求,相对安全
能否访问 WEB-INF 能 不能

这张表背下来基本够用。核心记忆点:forward 是"内部交接",redirect 是"告知新地址、你自己再跑一趟"。

5.2 登录成功后为什么我建议你用 redirect

这句话可能和很多教材的例题相反,但这是我实际写登录模块的真实体会: 登录成功那个分支,最稳的处理不是 forward,而是 sendRedirect 。

原因有三个:

  • 防止重复提交。forward 之后地址栏还是原来的 URL,用户一按 F5,浏览器会重新 POST 一次 doLogin.jsp,表单数据再校验一遍,如果校验通过又 forward 回去。如果这个过程中涉及登录日志、积分奖励这类有副作用的操作,就等于重复执行了。
  • 地址栏会误导用户。用户明明已经登录成功看到了欢迎页,地址栏却还停在一串看起来像"提交中"的地址,这不符合直觉。重定向到 welcome.jsp 后地址栏变成明文地址,用户还可以直接收藏这个页面。
  • 刷新行为可预期。redirect 后浏览器发起的是 GET 请求,刷新只是重新拉取页面,没有表单重放的副作用。

所以我的落地方案其实是"混合式"的:登录失败用 forward 回登录页带错误提示,登录成功则设置 session 后 redirect 到 welcome.jsp。这样既保留了 forward 在错误回显上的便利,又规避了成功分支的重复提交问题。这篇文章前面为了保证 jsp:forward 的演示完整性,留了两个 forward 的写法,真正交项目时建议按这个思路改。

5.3 必须用 forward 的三个场景

既然 redirect 这么好,为什么 forward 还活着?因为有些场景只有 forward 能做:

  • 同一请求内需要传递 request 属性和参数 。比如 A 页面经过一系列计算,把中间结果 request.setAttribute() 后交给 B 页面展示,中途不能断,断了数据就没了。
  • 访问 WEB-INF 下的资源 。WEB-INF 目录对浏览器是不可见的,用户直接敲 URL 访问会 404。你只能通过服务器内部 forward 过去。想隐藏某个页面不想让它被直接打开时,把页面挪进 WEB-INF 再用 forward 接,是最朴素的保护手段。
  • 权限校验失败时回到登录页 。受保护页面顶部写一段 session 判断,没登录就拿 jsp:forward 回登录页,这是课程设计里非常经典的安全骨架。注意这里登录失败时 GET 到哪里其实无所谓,因为本来就是前一个请求的上下文里做的判断。

6. 实际项目里最容易踩的五个坑和排查思路

6.1 坑一:转发后 CSS、图片全部失效

症状很典型:登录页样式正常,forward 到 welcome.jsp 后,页面 HTML 结构出来了,但 CSS 全丢、图片裂开。

原因是 forward 不改变浏览器地址栏的 URL,而 HTML 里的相对路径是相对于"当前浏览器地址"解析的。比如你从 http://localhost:8080/login-demo/login.jsp 提交,forward 到 welcome/welcome.jsp 后,浏览器地址还是 .../login.jsp ,页面里写 <link href="css/style.css"> 就会被解析成 .../login-demo/css/style.css ,如果登录页和欢迎页不在同一目录层级,路径就错位了。

解决办法是统一用带上下文根的绝对路径,在页面 head 里加一行 base 标签:

<base href="<%=request.getContextPath()%>/">

或者手动拼接:

<link rel="stylesheet" href="<%=request.getContextPath()%>/css/style.css">

如果项目用了 EL,可以简写成 ${pageContext.request.contextPath}/css/style.css 。核心思路:只要涉及页面跳转,尤其是 forward 这种地址栏不变的跳转,资源路径一律要用绝对路径,别偷懒写相对路径。

6.2 坑二:WEB-INF 页面"进不去"反而保护了后台

我开始也说过,forward 可以到 WEB-INF,浏览器直接访问则不行。这个特性在登录场景里是把双刃剑。

好的用法:把 welcome.jsp 这类需要登录才能看的页面放 WEB-INF 下,登录成功后 forward 进去。这样用户即使在地址栏输入 http://localhost:8080/项目名/WEB-INF/welcome.jsp 也看不到页面,挡住了"绕过登录直接进后台"的低级漏洞。

坏的用法:有些同学把 login.jsp 也放进 WEB-INF,结果部署后发现无论如何都访问不到登录页,因为浏览器没办法直接把 WEB-INF 下的 JSP 当 URL 访问。记住: 入口页面必须在 WEB-INF 外面,受保护页面才放里面 。

6.3 坑三:F5 一下,表单又提交了一遍

这是 forward 在登录成功分支最尴尬的地方。地址栏没变,F5 或 Ctrl+R 会重复发送上一次的 POST 请求,doLogin.jsp 又重新执行一遍:重新判断、重新 forward。对纯展示型登录来说危害不大,但如果登录时有写日志、发短信、扣积分这类副作用,重复提交就是事故。

我见过一个真实的课程设计,登录页有个计数器,统计"登录次数",结果用户每次刷新都 +2,闹出笑话。解决方案就是第 5 章说过的 PRG 模式:Post-Redirect-Get。POST 提交校验成功后,不要 forward,而是 response.sendRedirect("welcome.jsp") ,浏览器先收到 302,再 GET 一次 welcome.jsp,刷新页面时重复的是 GET 请求,而不是 POST 登录请求。这是所有登录模块都建议遵守的实践。

6.4 坑四:受保护页面没有会话校验

顺着 session 的思路再进一步。welcome.jsp 如果放在根目录且没有任何判断,用户在未登录状态下直接访问 .../welcome.jsp 也能打开,登录模块形同虚设。课程设计里最常见的补救是在每个受保护页面的最顶部写:

<%
    if (session.getAttribute("user") == null) {
%>
<jsp:forward page="login.jsp" />
<%
        return;
    }
%>

这样未登录用户访问 welcome.jsp,会被直接转发回登录页。注意这里我加了一个 return; ,防止 JSP 容器在处理完 forward 后,又往下渲染了 welcome.jsp 的正文内容。虽然在标准实现中 forward 调用后 Java 方法会返回,但加上 return 能让编译后的代码更明确地结束当前处理,避免某些容器差异造成的内容泄露。

不过要提醒一句:每个页面都贴这段会非常啰嗦且容易漏,正规做法是写一个 Filter 统一拦截,配置好 URL 规则后一个类搞定。课程设计阶段先用页面顶部判断,成本最低,也够演示了。

6.5 坑五:forward 之后还有代码?看编译后的 class 就懂了

排查 forward 相关问题最有效的办法,是直接看 JSP 编译后的 Java 源码。有很多人问"jsp编译class文件保存在哪里"——在 Tomcat 的 work 目录下,默认路径是:

TOMCAT_HOME/work/Catalina/localhost/项目名/org/apache/jsp/

里面能找到 doLogin_jsp.java 和对应的 .class 。打开 _jspService 方法,找到 <jsp:forward> 对应的代码,你会发现它是这样的结构:

if (true) {
    _jspx_page_context.forward("welcome.jsp" + "?" + _jspx_qfe);
    return;
}

return 的存在说明 forward 之后当前页面确实不会再继续输出了。同时你也能看到, <jsp:param> 拼接成了查询字符串附加在目标地址后面,这就是为什么目标页面能用 request.getParameter("msg") 取到值。理解了这段编译结果,你就能解释很多看似诡异的现象:比如 forward 前页面已经输出了一点 HTML,到目标页面时这些输出不见了——因为 JSP 容器在 forward 之前清空了响应缓冲区。

注意:如果 forward 之前已经往响应里写入了大量内容,导致缓冲区被写满并提交到浏览器(response 已 committed),再执行 forward 就会抛出 IllegalStateException 。所以页面里别在 <jsp:forward> 之前乱输出,尤其别用 out.flush() 。

另外再补充一个编码相关的坑。doLogin.jsp 里设置 request.setCharacterEncoding("UTF-8") 只对 POST 请求体有效。如果用 GET 方式提交表单,参数编码取决于 Tomcat 的 URIEncoding 配置, setCharacterEncoding 就不管用了。所以表单老老实实用 POST,能躲开一大半乱码问题。

还有一个被问得很多的"退出登录"问题。logout 页面别用 forward 回登录页,因为地址栏不变会让用户很困惑。正确做法是:

<%
    session.invalidate();  // 销毁整个会话
    response.sendRedirect("login.jsp");
%>

session.invalidate() 会把当前会话里所有属性清掉,比逐个 removeAttribute 干净。如果你已经写了页面离开确认脚本( window.onbeforeunload ),重定向前会先触发浏览器的离开提示,这是预期行为,点击"离开"后才会跳到登录页,不用觉得奇怪。

我在实际带项目时发现,所有关于登录跳转的疑难杂症,只要抓住三条主线就能快速定位:请求是哪个(forward 还是 redirect)、数据在哪(request 还是 session)、地址栏是什么(变了还是没变)。把这几个问题问清楚,问题基本先解决一半。剩下的一半,就是用第 6 章那个 work 目录下的编译产物去验证你的猜测。JSP 这东西看着老,但把这种"猜不出来的就去看底层"的排查思路练熟了,后面学 Spring MVC、过滤器链那些更复杂的请求流转,都会轻松得多。

登录功能中的请求转发与重定向:原理、区别与选型 在Web后端开发中,请求转发与重定向是HTTP请求流转的两种基础机制。请求转发由服务器内部完成,一次请求即可将数据传递到目标资源;重定向则通过302响应让浏览器发起第二次请求,地址栏随之变化。理解二者的差异,不仅关乎页面跳转是否正确,更直接影响表单重复提交、登录状态保持等工程实践。尤其在登录场景中,PRG模式借助重定向避免刷新时重复提交,而登录失败携带错误信息则常依赖转发。无论是Servlet原生写法还是Spring MVC的forward和redirect封装,底层原理始终一致。掌握这些核心概念,能帮助后 阅读详情

相关推荐

Struts2登录注册与用户信息管理:框架原理、拦截器与避坑实践

Java Web开发中,Struts2曾是主流的MVC框架之一,其核心价值在于将请求处理抽象为拦截器链,让Action作为普通POJO承担业务逻辑。理解一次HTTP请求从Filter、ActionProxy到Result的完整生命周期,是从底层排查404、校验失效和中文乱码等问题的关键。基于Struts2实现登录注册与用户信息管理,能够覆盖表单双层校验、CRUD操作、分页查询、结果重定向等典型工程场景,同时也暴露出jar包版本冲突、动态方法调用被禁用以及S2-029远程代码执行漏洞等老项目常见隐患。对于课设

weixin_30235225的博客 525

Java Swing实现烟花效果(含音乐效果)

Java Swing实现烟花效果,在idea里面运行,要导入一个音乐的jar包。注解:这两个类要一起用才能运行。

快乐学习 3634

JSP课设源码全解析:三层架构、部署避坑与项目改造

Java Web开发中,JSP与Servlet是绕不开的经典技术组合。以Servlet负责请求控制、JSP负责页面渲染、Service层处理业务、DAO层访问数据库为骨架的三层架构,至今仍是很多课程设计与小型项目的首选方案。理解一次请求从Controller到Service再到JSP的完整路径,掌握PageBean分页、JDBC连接配置、Tomcat部署等关键环节,是排查乱码、端口占用、重复提交等问题的基础。在设备管理、客户关系管理等典型场景中,基于Servlet+JSP的轻量工程能快速落地,也更利于学习底

weixin_33801856的博客 321

java拜年源码_拜年拜年,红包红包,手快有…

1、排序算法给大家拜年了!冒泡排序,选择排序,插入排序,快速排序,堆排序,归并排序,希尔排序,桶排序,基数排序新年帮您排忧解难。有向图,无向图,有环图,无环图,完全图,稠密图,稀疏图,拓扑图祝您新年宏图大展。最长路,最短路,单源路径,所有节点对路径祝您新年路路通畅。二叉树,红黑树,van Emde Boas树,最小生成树祝您新年好运枝繁叶茂。最大流,网络流,标准输入流,标准输出流,文件输入流,文...

weixin_42133415的博客 1326

避坑指南:PCIe设备兼容性那些坑——聊聊MPS/MRRS设置不当引发的血泪史

本文深入探讨了PCIe设备兼容性问题,特别是MPS/MRRS参数设置不当引发的常见故障。通过详细解析MPS(Max Payload Size)和MRRS(Max Read Request Size)的作用机制,提供Linux内核五大配置策略的对比分析,并分享FPGA加速卡等实战案例的排查经验。文章还介绍了诊断工具链、动态调试技巧以及性能优化方法,帮助工程师有效解决PCIe兼容性难题。

weixin_30872499的博客 419

一维光子晶体态密度计算与应用解析

态密度(DOS)是凝聚态物理和光子学中的核心概念,描述了量子态在能量空间的分布规律。基于麦克斯韦方程组的周期性介电结构分析表明,一维光子晶体通过布拉格散射形成光子带隙,其态密度曲线呈现典型的范霍夫奇点和禁带特征。这种特性使光子晶体在光学工程中具有重要价值,特别是在滤波器设计和传感器开发领域。通过转移矩阵法等数值计算手段,可以精确预测带隙位置和宽度,其中折射率对比度与周期数是关键设计参数。实际应用中,1550nm通信波段滤波器常采用Si/SiO2交替结构,而引入缺陷层则能产生高Q值缺陷模。计算优化时需注意数值

weixin_36487018的博客 193

做程序猿的老婆应该注意的一些事情

今天来说说一位女青年的老公以及他们的事儿。如有雷同,纯属巧合。 十一年前我和程序猿第一次见面,还是大一军训期间。我甚至不确定程序猿是否记得那是第一次见面。当时不小心装伪文艺参加了吉他社,想借一本吉他入门书,然后同在吉他社热心的海哥说他一同学有,就带着我去拿书了。于是我们第一次“见面”了,我只看见一个对着电脑,佝偻着背的背影……严重怀疑程序猿根本没抬头看一眼那个已经晒得像反转熊猫一样的妹子,因

MUM的专栏 1736

CASIA数据集解析:图像篡改检测的黄金标准与实践指南

本文深入解析了CASIA数据集在图像篡改检测领域的核心价值与应用实践。作为中科院自动化所打造的黄金标准,CASIA数据集通过模拟真实篡改场景(如拼接和复制移动)为研究者提供全面支持。文章详细对比了v1.0与v2.0版本差异,分享数据预处理和模型训练的最佳实践,并探讨了未来研究方向,是图像篡改检测领域的重要参考指南。

kappa的博客 785

Java程序到过年还有多少天_java实现距离指定时间还有多少天

import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.util.Locale;import java.util.TimeZone;public class 距离指定时间还有多少天 {/*** 默认时区为...

weixin_42511091的博客 1131

到底什么是指令集?什么是微架构?他们是什么关系?

指令集、处理器架构、芯片厂商、ARM、x86,其间关系还在迷糊吗?一文迅速理清!!

车载系统攻城狮 7813

【C# + HALCON 机器视觉】HALCON经典算子:光流法运动分析(optical_flow_mg)

摘要:本文面向智能监控人流统计需求,研究C#与HALCON集成开发中optical_flow_mg算子的应用。通过RTSP获取视频流,利用光流法计算运动矢量,结合形态学操作与区域筛选实现行人区域分割,最终完成人流量统计与热力图可视化。详细阐述ROI局部处理等性能优化策略、try-catch异常捕获机制及跨平台集成方案。实验表明,该系统检测准确率达93.6%,单帧处理时间42ms,为公共场所人流量统计提供了完整可行的技术方案。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1444

JSP登录跳转核心:jsp:forward与request作用域实战解析

在Java Web开发中,页面跳转与请求流转是构建动态Web应用的基础能力。服务端跳转作为区别于客户端重定向的关键机制,由容器内部完成请求转发,全程仅发起一次HTTP请求,并保持request对象不变。依托这一原理,开发者可在登录校验场景中利用请求作用域在页面间安全传递用户信息与错误提示,实现真正的“先处理、后展示”流程。同时,透彻理解转发与重定向的差异,有助于掌握状态保持、参数传递及编码处理等高频实践问题,并为后续学习Servlet、Spring MVC乃至安全框架奠定坚实根基。本文将结合经典认证登录项目

weixin_28700593的博客 254

使用Python实现卷积神经网络(CNN)

卷积神经网络是一种专门用于处理具有网格状拓扑结构数据(如图像、声音)的深度学习模型。CNN的核心组件是卷积层和池化层,它们能够有效地从图像中提取特征并实现空间不变性,使得模型能够对图像中的物体进行识别和分类。我们定义一个简单的卷积神经网络模型,包括卷积层、池化层和全连接层。return x# 创建模型实例我们选择交叉熵损失函数作为分类任务的损失函数,并使用随机梯度下降(SGD)作为优化器。

Echo_Wish 4489

JSP动作标签<jsp:forward>原理与登录验证实战

JSP动作标签是Java Web开发中的核心组件,其中<jsp:forward>实现服务器端页面跳转,保持请求连贯性。其工作原理是通过服务器内部转发请求,不改变浏览器地址栏,完整传递request属性。相比客户端跳转(如sendRedirect),具有性能消耗低、保持请求作用域等优势,特别适合登录验证、权限控制等场景。在安全实践中,需注意SQL注入防护(使用PreparedStatement)、密码加密存储(推荐BCrypt算法)等关键点。现代Web开发中,虽然Spring MVC等框架提供了更优雅的解决方

weixin_33508411的博客 175

华为 MetaERP · 本体论驱动的 PTP 全流程智能建模方案

华为MetaERP通过“本体+事件+图谱+Agent”四位一体架构,将传统ERP从“记录系统”升级为“智能执行系统”。基于OWL本体实现业务语义精准表达,融合LLM与元数据多租能力,构建可推理、可治理的PTP全流程智能模型,解决AI理解业务逻辑难题,实现三单匹配自动化、关账效率提升30%、成本降低50%,推动企业数字化迈向可信智能新范式。

金牌架构师 182

多角度模板匹配的模板创建技巧

基于形状的模板匹配多角度创建技巧

manuoo的专栏 3403

JSP登录界面实现:jsp:forward请求转发与会话管理

在Java Web开发中,请求转发与重定向是控制页面跳转的两种基础机制,而JSP动作标签<jsp:forward>正是实现服务器端请求转发的核心方式。其原理是容器在内部直接将请求对象和响应对象传递给目标资源,地址栏不变,适合登录校验等逻辑分发场景。与response.sendRedirect相比,jsp:forward保留同一request对象,参数传递更高效,但需注意缓冲区刷新可能引发IllegalStateException。在构建登录界面时,利用jsp:forward根据用户名密码校验结果决定跳转方向

weixin_32430941的博客 311

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

HoRain云--Forward与Redirect:Web跳转核心差异解析

摘要: Forward(转发)与Redirect(重定向)是Web开发中的两种跳转机制。Forward由服务器内部完成,客户端无感知,仅一次请求,URL不变,适合同一应用内的数据共享跳转;Redirect需客户端发起新请求,两次HTTP交互,URL更新,支持跨应用跳转,常用于防表单重复提交或跨站点跳转。核心差异在于执行主体、请求次数及数据共享能力。选择时,优先Forward实现高效内部协作,需灵活跳转或更新地址栏时用Redirect。技术实现需注意参数传递与路径限制。(150字)

2401_86544677的博客 668

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

php跳转到某一个php页面,JSP页面跳转方法小结

实现JSP页面跳转,有如下几种方式:n 使用href超链接标记 (客户端跳转)n 使用JavaScript (客户端跳转)n 提交表单 (客户端跳转)n 使用response对象 ...

weixin_32568425的博客 222

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

forward与redirect的区别

1)forword是服务器内部的重定向,服务器直接访问目标地址的url网址,把里面的东西读取出来,但是客户端并不知道,因此用forward的话,客户端浏览器的网址是不会发生变化的。1)由于在整个定向的过程中用的是同一个request,因此forward会将request的信息带到被重定向的jsp或者servlet中使用。2)redirect是服务器根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的地址。1)forword一般用于用户登录的时候,根据角色转发到相应的模块。...

qq_36967200的博客 1668

JSP forward机制与登录验证实现详解

在Java Web开发中,页面跳转是基础而重要的技术环节。服务器端跳转机制如JSP forward通过保持请求连贯性,避免了浏览器地址栏变化带来的问题,特别适合登录验证等场景。其核心原理是通过RequestDispatcher将请求和响应对象传递给目标页面,同时保持所有参数不变。相比客户端跳转,这种技术能更好地维护应用状态,提升用户体验。在实际开发中,开发者常采用Servlet+JSP的分层架构,或结合Filter实现统一验证,既保证了代码可维护性,又能有效防范安全风险。随着技术发展,虽然现代框架如Spri

weixin_33428613的博客 311

JSP forward动作标签与登录验证机制详解

在Java Web开发中,JSP动作标签是实现页面跳转和逻辑控制的重要工具。其中,`<jsp:forward>`标签通过服务器端请求派发机制,实现了资源的无缝切换,同时保持了请求属性的完整性。这种机制在传统的MVC架构中扮演着关键角色,特别是在用户登录验证流程中。登录验证作为系统安全的第一道防线,通常涉及参数接收、数据库查询、会话管理等多个环节。通过结合JSP forward与Servlet技术,开发者可以构建出既安全又高效的验证系统。现代框架如Spring MVC虽然提供了更优雅的实现方式,但理解这些底层

weixin_31155097的博客 215

JSP中实现系统登录后的退出原理及代码

首先要在你登录的页面的某个地方,写上一个超级链接,让它链接到exit.jsp页面去,然后新建一个exit.jsp页面在其body中写上如下代码,即可以实现登录后的退出,感兴趣的朋友可以了解下啊,或许对你有所帮助 首先要在你登录的页面的某个地方,写上一个超级链接: 复制代码 代码如下: 退出 让它链接到exit.jsp页面去,然后新建一个exit.jsp页面在其body中

1106

jsp中:forward 与 redirect区别

[quote]1.从地址栏显示来说 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容 再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址. redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.所 以redirect等于客...

iteye_1836的博客 269

web - Forward与Redirect的区别

Forward与Redirect 在做前台开发过程中你可能经常遇到关于转发页面得操作,很显然的就想到了forward和redirect,但是到底用哪一个呢,他们之间有什么区别呢,现在我将我自己的理解以及开发的时候怎么应用写出来供大家参考一下: (1)共同点: 都实现了根据自己的条件实现的页面得跳转。 (2)区别 类别 概念 共享数据 应用 ...

快乐 333
上一篇: 光储直流微电网Simulink仿真:从拓扑搭建到母线电压控制详解
下一篇: Vue3动画角色登录页开发指南:从设计到性能优化
weixin_34026276
博客等级 码龄11年 6372粉丝 1272原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值