JSP(JavaServer Pages)本质上是一个 Servlet,JSP 文件最终会被 Web 容器(如 Tomcat)编译成一个 Java Servlet 类,在 JSP 中定义的变量,最终会存在于这个生成的 Servlet 类中。

根据变量定义的位置和作用域,Java 代码获取它的方式完全不同,我们主要分为以下几种情况:
获取 JSP 页面作用域(Page Scope)的变量
这种变量通常是在 JSP 的脚本片段(<% ... %>)中声明的局部变量。
JSP 代码示例 (page.jsp):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>Page Scope 示例</title>
</head>
<body>
<%-- 在这里定义一个页面作用域的变量 --%>
<%!
String pageMessage = "这是一个页面作用域的变量!";
%>
<%-- 在另一个脚本片段中使用它 --%>
<%
System.out.println("在 JSP 脚本中直接访问: " + pageMessage);
%>
<h1>页面内容</h1>
<p><%= pageMessage %></p> <%-- 使用表达式输出 --%>
<%-- 我们尝试在 Java 代码中获取它 --%>
<%
// 这里的代码就在生成的 Servlet 的 _jspService 方法中
// 所以可以直接访问在 <%! ... %> 中定义的成员变量
String retrievedMessage = pageMessage;
System.out.println("在同一个 JSP 的 _jspService 方法中获取: " + retrievedMessage);
%>
</body>
</html>
Java 代码如何获取?

- 在同一个 JSP 文件内:如上所示,如果你在一个
<% ... %>脚本片段中,你可以直接访问在<%! ... %>声明的成员变量,因为它们都属于同一个 Servlet 类。 - 在另一个独立的 Java 类(如 Servlet)中:这是不可能的,因为
pageMessage是生成 Servlet 的一个实例成员变量,它的生命周期和当前这个 JSP 页面请求的生命周期绑定,外部类无法直接访问这个特定的 Servlet 实例的私有或受保护成员。
页面作用域的变量仅限于在 JSP 文件内部使用,无法被外部的 Java 代码直接调用。
获取 JSP 作用域(JSP Scope)的变量
这是最常见、最规范的用法,JSP 提供了四个内置的域对象(Scope Objects),用于在不同范围内存储和共享数据。
| 作用域 | 内置对象 | 生命周期 | 适用场景 |
|---|---|---|---|
| Page | pageContext |
当前页面请求 | 仅在当前页面有效,极少使用。 |
| Request | request |
当前 HTTP 请求 | 数据在同一个请求的多个组件(如 forward 的 Servlet/JSP)间共享。 |
| Session | session |
用户会话 | 数据在用户多次请求之间共享(如登录状态、购物车)。 |
| Application | application |
Web 应用 | 数据在整个 Web 应用中所有用户间共享(如全局计数器)。 |
正确的工作流程是:JSP 存储数据,Java 代码(通常是 Servlet)从作用域中获取数据。
在 JSP 中设置变量到作用域
JSP 代码示例 (set_data.jsp):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>设置作用域变量</title>
</head>
<body>
<h1>正在设置变量...</h1>
<%
// 1. 设置到 Request 作用域
String requestMsg = "Hello from Request Scope!";
request.setAttribute("requestMessage", requestMsg);
// 2. 设置到 Session 作用域
String sessionMsg = "Hello from Session Scope!";
session.setAttribute("sessionMessage", sessionMsg);
// 3. 设置到 Application 作用域
int appCounter = application.getAttribute("appCounter") == null ? 0 : (int)application.getAttribute("appCounter");
application.setAttribute("appCounter", ++appCounter);
%>
<p>已设置变量,请点击下面的链接跳转到 Servlet 查看。</p>
<a href="GetServlet">跳转到 Servlet 获取数据</a>
</body>
</html>
在 Java Servlet 中获取变量
Java 代码示例 (GetServlet.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("/GetServlet") // 映射 URL
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 从 Request 作用域获取
// 使用与 JSP 中 setAttribute 时相同的 key
String requestMessage = (String) request.getAttribute("requestMessage");
// 2. 从 Session 作用域获取
// 注意:需要先获取 session 对象
String sessionMessage = (String) request.getSession().getAttribute("sessionMessage");
// 3. 从 Application 作用域获取
Integer appCounter = (Integer) getServletContext().getAttribute("appCounter");
// 打印到控制台
System.out.println("--- 从 Servlet 中获取的变量 ---");
System.out.println("Request Message: " + requestMessage);
System.out.println("Session Message: " + sessionMessage);
System.out.println("Application Counter: " + appCounter);
// 也可以将获取到的数据存入 request,forward 到一个 JSP 页面进行显示
request.setAttribute("retrievedRequestMsg", requestMessage);
request.getRequestDispatcher("display_data.jsp").forward(request, response);
}
}
显示数据的 JSP (display_data.jsp):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>显示从 Servlet 获取的数据</title>
</head>
<body>
<h1>从 Servlet 获取并显示的数据</h1>
<%-- 从 request 作用域中取出数据并显示 --%>
<p>从 Request 作用域获取的消息是: <strong><%= request.getAttribute("retrievedRequestMsg") %></strong></p>
<%-- 也可以直接显示从 Servlet forward 过来的所有 request 数据 --%>
<p>原始的 Request 消息 (通过EL表达式): <strong>${requestMessage}</strong></p>
</body>
</html>
获取 JSP EL 表达式中的变量
EL (Expression Language) 如 ${variable} 是 JSP 2.0 之后推荐的表达式写法,它通常从作用域中查找变量。
JSP 代码示例 (el_example.jsp):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.List" %>
<html>
<head>EL 变量示例</title>
</head>
<body>
<%
// 在 request 作用域中存入一个 List
List<String> names = List.of("Alice", "Bob", "Charlie");
request.setAttribute("userList", names);
%>
<h1>使用 EL 表达式访问变量</h1>
<p>用户列表: ${userList}</p>
<p>第一个用户: ${userList[0]}</p>
</body>
</html>
Java 代码如何获取?
EL 表达式 ${userList} 本质上就是 pageContext.findAttribute("userList") 的简写,它会在 Page -> Request -> Session -> Application 作用域中依次查找名为 "userList" 的属性。
获取 EL 变量的方式和场景二完全一样:你只需要知道 EL 表达式使用的 key(这里是 "userList"),然后在 Java 代码中从相应的作用域(通常是 request.getAttribute("userList"))中获取即可。
总结与最佳实践
| 变量类型 | 位置 | Java 代码如何获取 | 推荐用法 |
|---|---|---|---|
| 页面作用域变量 | <%! %> |
无法被外部 Java 代码调用,仅限 JSP 内部。 | 尽量避免使用,逻辑应放在 Java 类中。 |
| 作用域变量 | request/session/application.setAttribute() |
通过 request.getAttribute(), session.getAttribute(), application.getAttribute() 使用相同的 key 来获取。 |
这是标准做法,JSP 负责展示数据,Servlet/Java 类负责处理业务逻辑和设置数据。 |
| EL 变量 | ${key} |
和作用域变量一样,通过 key 从作用域中获取。 |
JSP 2.0+ 的首选,用于简化页面数据输出。 |
核心思想:分层架构
现代 Java Web 开发遵循 MVC(Model-View-Controller)模式:
- Model (模型): JavaBean/POJO,代表数据。
- View (视图): JSP/HTML,负责展示数据。
- Controller (控制器): Servlet,负责接收请求、调用业务逻辑、处理数据,然后将数据存入作用域,并选择合适的视图进行响应。
在这种模式下,Java 代码(Controller)不会去“调用” JSP 的变量,而是将数据“放入”作用域,然后由 JSP(View)从作用域中“取出”并显示,这实现了数据和视图的解耦,是项目可维护性的关键。
