本文收录于「Java 学习日记:从入门到架构师」专栏,聚焦 Java Web 经典技术 JSP,从核心语法到内置对象实战,帮你搞懂 “前端页面 + 后端逻辑” 如何融合~
一、为什么要学 JSP?
在上一篇的会话管理中,我们用 Servlet 向客户端返回的是纯文本 / HTML 字符串,写起来又繁琐又不直观 —— 比如要拼接大量 HTML 标签,维护性极差。
而JSP(Java Server Pages) 就是为解决这个问题而生的:
- JSP 本质上是 “特殊的 Servlet”(Tomcat 会自动将 JSP 编译成 Servlet 类);
- 允许在 HTML 页面中嵌入 Java 代码,实现 “前端页面 + 后端逻辑” 的一体化开发;
- 虽然现在主流是 “前后端分离”,但 JSP 是 Java Web 的基础,很多老项目 / 传统项目仍在使用,理解 JSP 能帮你更好地掌握 Servlet 容器的工作原理。
今天这篇日记,我们从 JSP 的核心语法、指令、内置对象入手,手把手写第一个 JSP 程序。
二、JSP 核心认知:什么是 JSP?
JSP 是运行在服务器端的页面技术,核心特点:
JSP 的执行流程:

三、JSP 核心语法:嵌入 Java 代码的 3 种方式
JSP 中嵌入 Java 代码主要有 3 种形式,是入门的核心,必须掌握:
1. 脚本片段(Scriptlet):<% 代码 %>
- 作用:编写多行 Java 代码(变量定义、逻辑判断、循环等);
- 特点:代码会被编译到 Servlet 的_jspService()方法中(对应 Servlet 的 doGet/doPost);
- 注意:不能定义方法(只能定义局部变量和逻辑代码)。
示例:
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP脚本片段</title>
</head>
<body>
<h1>JSP脚本片段示例</h1>
<%
// 定义局部变量
String username = "Java日记";
int age = 18;
// 逻辑判断
if (age >= 18) {
// 输出到页面(等价于out.write())
out.write("你好," + username + "!你是成年人<br>");
} else {
out.write("你好," + username + "!你是未成年人<br>");
}
// 循环输出
for (int i = 1; i <= 3; i++) {
out.write("循环次数:" + i + "<br>");
}
%>
</body>
</html>
2. 表达式(Expression):<%= 变量/表达式 %>
- 作用:直接输出变量或表达式的结果到页面,无需写out.write();
- 特点:末尾不能加分号,是简化输出的语法糖。
示例:
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP表达式</title>
</head>
<body>
<h1>JSP表达式示例</h1>
<%
String nickname = "Java学习日记";
int num = 100;
%>
<!– 表达式输出,无需分号 –>
昵称:<%= nickname %><br>
数字+10:<%= num + 10 %><br>
当前时间:<%= new java.util.Date() %><br>
</body>
</html>
3. 声明(Declaration):<%! 代码 %>
- 作用:定义 JSP 对应的 Servlet 类的成员变量 / 成员方法;
- 特点:代码会被编译到 Servlet 类的成员位置,而非_jspService()方法中;
- 注意:声明的成员变量是线程不安全的(Servlet 单例),慎用!
示例:
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP声明</title>
</head>
<body>
<h1>JSP声明示例</h1>
<%!
// 声明成员变量(线程不安全!)
private int count = 0;
// 声明成员方法
public String getHello() {
return "Hello JSP!";
}
%>
<%
// 每次访问,count自增(多线程下会出错)
count++;
%>
访问次数:<%= count %><br>
方法调用:<%= getHello() %><br>
</body>
</html>
四、JSP 指令:配置 JSP 的核心规则
JSP 指令用于告诉 Tomcat 如何编译 JSP,格式:<%@ 指令名 属性="值" %>,核心有 3 个指令:
1. page 指令(最常用)
用于配置 JSP 页面的核心属性,如编码、语言、导入包、会话支持等。
高频属性:
| language | 指定页面使用的语言(默认 java) | language="java" |
| contentType | 设置响应编码和数据格式 | contentType="text/html;charset=UTF-8" |
| pageEncoding | 设置 JSP 文件本身的编码(推荐 UTF-8) | pageEncoding="UTF-8" |
| import | 导入 Java 包(可多个,用逗号分隔) | import="java.util.List,java.util.Map" |
| session | 是否支持 Session(默认 true) | session="false" |
| errorPage | 指定错误页面(当前页面出错时跳转) | errorPage="error.jsp" |
示例:
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java"
pageEncoding="UTF-8"
import="java.util.List,java.util.ArrayList"
session="true" %>
<html>
<head>
<title>page指令示例</title>
</head>
<body>
<%
List<String> list = new ArrayList<>();
list.add("Java");
list.add("JSP");
list.add("Servlet");
%>
集合内容:<%= list %><br>
SessionID:<%= session.getId() %><br>
</body>
</html>
2. include 指令:静态包含
用于将另一个 JSP/HTML 文件静态包含到当前页面(编译时合并),格式:<%@ include file="文件路径" %>。
特点:
- 静态包含:Tomcat 编译时,会将包含的文件内容直接合并到当前 JSP 中,生成一个 Servlet;
- 路径:推荐使用相对路径,如header.jsp、/common/footer.jsp;
- 注意:包含的文件和当前页面不能有同名变量(会冲突)。
示例:header.jsp(公共头部):
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div style="background: #eee; padding: 20px;">
<h2>Java学习日记 – 公共头部</h2>
</div>
index.jsp(主页面):
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>静态包含示例</title>
</head>
<body>
<%– 包含公共头部 –%>
<%@ include file="header.jsp" %>
<div style="padding: 20px;">
<h3>主页面内容</h3>
<p>这是通过include指令包含的公共头部</p>
</div>
</body>
</html>
3. taglib 指令:引入标签库
用于引入自定义标签库或 JSTL 标签库(后续进阶篇讲),格式:<%@ taglib prefix="前缀" uri="标签库URI" %>。
示例(引入 JSTL 核心标签库):
jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
五、JSP 内置对象(隐式对象):9 个 “免创建” 的核心对象
JSP 提供了 9 个内置对象,无需new即可直接使用,本质是 Tomcat 在编译 JSP 时,自动在_jspService()方法中创建并传入的对象。
1. 核心内置对象(必掌握)
| request | HttpServletRequest | 获取请求参数、请求头、域数据 | 完全一致 |
| response | HttpServletResponse | 发送响应、重定向、设置响应头 | 完全一致 |
| session | HttpSession | 存储会话数据、保持登录状态 | 完全一致 |
| out | JspWriter | 向页面输出内容(等价于 response.getWriter ()) | 类似 PrintWriter |
| pageContext | PageContext | 页面上下文,获取其他内置对象、域数据 | 独有 |
| application | ServletContext | 全局应用对象,存储整个应用的共享数据 | getServletContext() |
2. 内置对象实战:登录状态展示
login.jsp(登录页面):
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP登录</title>
</head>
<body>
<h1>用户登录</h1>
<form action="loginHandle.jsp" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
loginHandle.jsp(登录处理):
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 1. 解决POST中文乱码
request.setCharacterEncoding("UTF-8");
// 2. 获取请求参数(request内置对象)
String username = request.getParameter("username");
String password = request.getParameter("password");
// 3. 模拟登录校验
if ("admin".equals(username) && "123456".equals(password)) {
// 4. 存储用户信息到Session(session内置对象)
session.setAttribute("loginUser", username);
// 5. 重定向(response内置对象)
response.sendRedirect("userCenter.jsp");
} else {
out.write("用户名或密码错误!<a href='login.jsp'>返回登录</a>");
}
%>
userCenter.jsp(个人中心):
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>个人中心</title>
</head>
<body>
<%
// 1. 从Session获取登录用户
String loginUser = (String) session.getAttribute("loginUser");
if (loginUser == null) {
// 未登录,重定向到登录页
response.sendRedirect("login.jsp");
return; // 终止页面执行
}
%>
<h1>欢迎你,<%= loginUser %>!</h1>
<p>SessionID:<%= session.getId() %></p>
<p>应用名:<%= application.getContextPath() %></p>
<a href="logout.jsp">退出登录</a>
</body>
</html>
logout.jsp(退出登录):
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 销毁Session
session.invalidate();
response.sendRedirect("login.jsp");
%>
3. 测试步骤
六、避坑指南:JSP 常见问题
- 页面乱码:确保page指令中contentType和pageEncoding都设为UTF-8;
- 请求参数乱码:POST 请求需加request.setCharacterEncoding("UTF-8"),GET 请求需修改 Tomcat 的server.xml添加URIEncoding="UTF-8";
- session对象使用前无需创建,直接调用session.getAttribute()即可;
- out.write()和<%= %>等价,推荐用表达式简化输出;
七、今日实战小任务
总结
下一篇【Day36】预告:JSTL 标签库与 EL 表达式(告别 JSP 脚本片段,简化页面逻辑),关注专栏持续解锁 Java Web 核心知识点~若本文对你有帮助,欢迎点赞 + 收藏 + 关注,你的支持是我更新的最大动力💖!





