《Java 100 天进阶之路》第69篇:JSP与EL表达式(2026版)
第69篇:JSP与EL表达式(2026版)
📌系列导航:《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第68篇:JavaWeb核心技术之Servlet |
➡️ 下一篇:第70篇:Cookie与Session(待发布)
🗺️ 本文阅读地图(3 分钟速览)
第68篇搞定了Servlet,本篇深入JSP与EL表达式。JSP曾是Java Web的“视图层王者”,虽然现在新项目多用模板引擎,但理解JSP仍是理解Java Web演进的关键:
| 模块 | 核心问题 | 一句话回答 |
|---|---|---|
| JSP本质 | JSP到底是什么? | JSP本质就是Servlet——第一次访问时被翻译成Servlet源码并编译 |
| 生命周期 | JSP从生到死经历什么? | 翻译→编译→加载→实例化→初始化→服务→销毁 |
| 九大内置对象 | JSP中可以直接用哪些对象? | request、response、out、session、application、pageContext、config、page、exception |
| EL表达式 | 怎么简化JSP取值? | ${表达式}替代<%= %>,自动从四大作用域取值 |
| 四大作用域 | 数据存在哪里? | page < request < session < application |
| JSTL | JSP中怎么做循环和判断? | 用<c:forEach>和<c:if>替代Java脚本 |
| JSP现状 | 2026年还用JSP吗? | 新项目少用,但维护老系统必备技能 |
| 面试最爱问 | 高频考点有哪些? | 见文末 🎤 小节 |
一、核心知识点
1. JSP是什么?
JSP(JavaServer Pages)是一种动态网页技术,允许在HTML中嵌入Java代码,由服务器端执行后生成动态内容返回给客户端。
💡本质:JSP本质就是Servlet。JSP页面在第一次被请求时,由Web容器(如Tomcat)翻译成Servlet源码(
.java),再编译成字节码(.class),最终执行并响应HTTP请求。
2. JSP vs Servlet 核心定位
| 对比 | Servlet | JSP |
|---|---|---|
| 角色 | 控制器(Controller)——处理业务逻辑 | 视图(View)——展示数据 |
| 代码形式 | Java类,输出HTML需要拼接字符串 | HTML + Java,更直观 |
| 适合场景 | 请求处理、业务逻辑 | 页面展示、数据渲染 |
| MVC角色 | Controller | View |
💡核心理解:Servlet负责“接活、干活”,JSP负责“展示结果”。两者配合构成Java Web的MVC模式。
3. 2026年JSP现状
新项目(Spring Boot + Thymeleaf/Vue/React)已很少使用JSP。但大量遗留系统(ERP、CRM、政府系统)仍在使用JSP,掌握JSP是维护老系统的必备技能。
二、通俗讲解(1分钟开心学)
把JSP想象成“带填空的HTML模板”
- 静态HTML:一张印好的菜单,内容固定,不能改变。
- JSP:一张带填空格的菜单模板。服务员(服务器)根据顾客(请求)的不同,在空格里填上不同的内容(动态数据),再打印出来给顾客看。
JSP本质就是Servlet:
- 你写了一个
hello.jsp,里面混着HTML和Java代码。 - 第一次有人访问时,Tomcat偷偷把
hello.jsp翻译成一个hello_jsp.java(Servlet源码)。 - 然后编译成
hello_jsp.class(Servlet字节码)。 - 以后每次访问,直接执行这个Servlet,不再重新翻译编译。
💡核心理解:JSP是“写起来像HTML,跑起来是Servlet”的混合体。
三、JSP生命周期
JSP的生命周期遵循“翻译→编译→初始化→服务→销毁”五个阶段。
💡关键点:翻译和编译只在第一次访问时执行,后续请求直接执行已编译的Servlet。所以第一次访问JSP页面会稍慢,后续速度与Servlet相同。
四、JSP三大指令
JSP指令用于设置页面属性、引入标签库等,格式为<%@ 指令名 属性="值" %>。
1. page指令:设置页面属性
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="java.util.*, java.text.*" %> <%@ page errorPage="/error.jsp" %> <!-- 指定错误页面 --> <%@ page isErrorPage="true" %> <!-- 当前页面为错误页面 --> <%@ page session="true" %> <!-- 是否启用Session -->2. include指令:静态包含其他文件
<%@ include file="/header.jsp" %> <!-- 页面编译时合并 -->💡注意:
<@include>是静态包含(编译时合并),<jsp:include>是动态包含(运行时包含,更灵活)。
3. taglib指令:引入标签库
<%@ taglib prefix="c" uri="jakarta.tags.core" %>五、JSP九大内置对象
JSP在翻译成Servlet时,容器会自动创建9个内置对象,开发者可以直接使用,无需显式声明。
5.1 九大内置对象速查表
| 对象名 | 类型 | 作用 | 使用频率 |
|---|---|---|---|
| request | HttpServletRequest | 获取请求参数、请求头、请求属性 | ⭐⭐⭐⭐⭐ |
| response | HttpServletResponse | 设置响应内容、状态码 | ⭐⭐⭐ |
| out | JspWriter | 输出内容到页面 | ⭐⭐⭐⭐ |
| session | HttpSession | 存储用户会话数据 | ⭐⭐⭐⭐⭐ |
| application | ServletContext | 存储全局应用数据 | ⭐⭐⭐ |
| pageContext | PageContext | 操作所有域对象,获取其他内置对象 | ⭐⭐⭐⭐ |
| config | ServletConfig | 获取Servlet配置参数 | ⭐ |
| page | Object(当前Servlet实例) | 当前JSP页面对象(相当于this) | ⭐ |
| exception | Throwable | 获取异常信息(仅错误页面) | ⭐ |
5.2 四大作用域与对应内置对象
| 作用域 | 对象 | 生命周期 | 使用场景 |
|---|---|---|---|
| page | pageContext | 当前页面 | 页面内临时数据 |
| request | request | 一次请求 | 请求间传递数据 |
| session | session | 一次会话 | 用户登录状态、购物车 |
| application | application | 整个应用 | 全局配置、统计数据 |
💡作用域查找顺序:page → request → session → application,从小到大。
5.3 pageContext详解
pageContext是九大内置对象中功能最强的对象,它可以获取JSP页面中的其他所有内置对象:
<% // 通过pageContext获取其他内置对象 HttpServletRequest req = (HttpServletRequest) pageContext.getRequest(); HttpServletResponse resp = (HttpServletResponse) pageContext.getResponse(); HttpSession ses = pageContext.getSession(); ServletContext app = pageContext.getServletContext(); JspWriter out2 = pageContext.getOut(); // 操作四个域对象 pageContext.setAttribute("pageData", "页面数据", PageContext.PAGE_SCOPE); pageContext.setAttribute("requestData", "请求数据", PageContext.REQUEST_SCOPE); pageContext.setAttribute("sessionData", "会话数据", PageContext.SESSION_SCOPE); pageContext.setAttribute("appData", "应用数据", PageContext.APPLICATION_SCOPE); %>六、EL表达式
6.1 什么是EL?
EL(Expression Language,表达式语言)是JSP 2.0引入的一种简化页面代码的语言。它允许开发者使用简单的语法访问JavaBean属性、集合元素、请求参数等,无需编写Java脚本(<%= %>)。
基本语法:${表达式}
<!-- 传统JSP脚本(不推荐) --> <%= request.getAttribute("userName") %> <!-- EL表达式(推荐) --> ${userName}6.2 四大作用域取值
EL表达式自动按page → request → session → application顺序查找属性:
<!-- 自动按作用域查找 --> ${userName} <!-- 指定作用域查找 --> ${pageScope.userName} ${requestScope.userName} ${sessionScope.userName} ${applicationScope.userName}6.3 EL支持的数据类型
- 基本类型、字符串
- JavaBean属性(自动调用getter)
- 数组元素:
${arr[0]} - List/Set元素:
${list[0]} - Map元素:
${map.key}或${map["key"]} - 集合遍历(配合JSTL)
6.4 EL中的运算符
| 运算符 | 示例 | 说明 |
|---|---|---|
| 算术 | ${1 + 2} | 加、减、乘、除、取余 |
| 比较 | ${age >= 18} | >、<、>=、<=、==、!= |
| 逻辑 | ${empty list} | &&、` |
| 三元 | ${score >= 60 ? "及格" : "不及格"} | 条件 ? 真值 : 假值 |
| empty | ${empty userList} | 判断是否为null或空集合 |
6.5 EL的11个隐式对象
| 隐式对象 | 类型 | 说明 |
|---|---|---|
pageScope | Map | page作用域属性 |
requestScope | Map | request作用域属性 |
sessionScope | Map | session作用域属性 |
applicationScope | Map | application作用域属性 |
param | Map | 请求参数(单个值) |
paramValues | Map | 请求参数(多个值) |
header | Map | 请求头(单个值) |
headerValues | Map | 请求头(多个值) |
cookie | Map | Cookie对象 |
initParam | Map | 上下文初始化参数 |
pageContext | PageContext | JSP的pageContext对象 |
使用示例:
${param.username} <!-- 获取请求参数 --> ${header["User-Agent"]} <!-- 获取请求头 --> ${cookie.JSESSIONID.value} <!-- 获取Cookie --> ${pageContext.request.contextPath} <!-- 获取应用上下文路径 -->七、JSTL标准标签库
7.1 什么是JSTL?
JSTL(JSP Standard Tag Library)是JSP标准标签库,用于替换和简化JSP页面上的Java代码。它提供了一组标准标签,使JSP页面更加简洁、可读、易于维护。
引入方式:
<%@ taglib prefix="c" uri="jakarta.tags.core" %>7.2 核心标签库
| 标签 | 作用 | 示例 |
|---|---|---|
<c:set> | 设置变量 | <c:set var="name" value="张三"/> |
<c:remove> | 删除变量 | <c:remove var="name"/> |
<c:out> | 输出变量 | <c:out value="${name}"/> |
<c:if> | 条件判断 | <c:if test="${age >= 18}">成年</c:if> |
<c:choose> | 多条件分支 | <c:when>/<c:otherwise> |
<c:forEach> | 循环遍历 | 遍历集合、数组 |
<c:forTokens> | 字符串分割遍历 | 按分隔符拆分 |
<c:url> | 构造URL | 自动添加Session ID |
<c:import> | 导入外部资源 | 包含其他页面内容 |
<c:redirect> | 重定向 | 跳转到其他页面 |
使用示例:
<!-- 条件判断 --> <c:if test="${user != null}"> <p>欢迎,${user.name}!</p> </c:if> <!-- 多条件分支 --> <c:choose> <c:when test="${score >= 90}">优秀</c:when> <c:when test="${score >= 60}">及格</c:when> <c:otherwise>不及格</c:otherwise> </c:choose> <!-- 循环遍历 --> <c:forEach items="${userList}" var="user" varStatus="status"> <tr> <td>${status.index + 1}</td> <td>${user.name}</td> <td>${user.age}</td> </tr> </c:forEach>八、避坑要点
| 错误/误区 | 后果 | 正确做法 |
|---|---|---|
在JSP中写大量Java脚本(<% %>) | 代码难以维护,MVC混乱 | 用EL + JSTL替代 |
| 忘记设置页面编码 | 中文乱码 | <%@ page contentType="text/html;charset=UTF-8"%> |
| 混淆四大作用域 | 数据生命周期失控 | 明确page/request/session/application的适用场景 |
误用${}和<%= %> | 语法错误或安全风险 | EL(${})是JSP 2.0推荐方式 |
| EL表达式不输出预期值 | 作用域顺序不对 | 检查数据是否在正确的作用域中 |
忽略isELIgnored属性 | EL表达式被当作文本 | 设置<%@ page isELIgnored="false" %> |
| 新项目用JSP | 技术栈落后 | 新项目推荐Thymeleaf或前后端分离 |
九、面试高频考点
Q1:JSP的本质是什么?
JSP本质就是Servlet。JSP页面第一次被访问时,由Web容器翻译成Servlet源码(
.java),再编译成字节码(.class),后续请求直接执行编译后的Servlet。
Q2:JSP的九大内置对象有哪些?
request、response、out、session、application、pageContext、config、page、exception。其中
exception只能在错误页面(isErrorPage="true")中使用。
Q3:JSP的四大作用域是什么?
page(当前页面)、request(一次请求)、session(一次会话)、application(整个应用),作用范围依次扩大。EL表达式按此顺序自动查找属性。
Q4:EL表达式和JSP脚本表达式(<%= %>)的区别?
EL表达式(
${})是声明式的,自动处理null值,语法简洁;JSP脚本表达式(<%= %>)是命令式的,需要写Java代码,null值会报错。EL是JSP 2.0推荐的取值方式。
Q5:JSTL的作用是什么?
JSTL用于替代JSP中的Java脚本代码,提供条件判断(
<c:if>、<c:choose>)、循环遍历(<c:forEach>)、变量操作(<c:set>)等标签,使JSP页面更加简洁、可读、易于维护。
🎤 面试官追问陷阱(加分题)
追问1:“JSP第一次访问为什么慢?后续为什么快?”
👉 第一次访问时,JSP需要经历**翻译(.jsp → .java)和编译(.java → .class)**两个步骤,耗时较长。后续访问直接执行已编译的Servlet,速度与普通Servlet相同。
追问2:“JSP和Servlet在MVC中分别扮演什么角色?”
👉 Servlet作为控制器(Controller),负责接收请求、处理业务逻辑、转发到JSP;JSP作为视图(View),负责展示数据。这种分离提高了代码的可维护性和可扩展性。
十、练习题
简答题:JSP的本质是什么?为什么第一次访问JSP比后续访问慢?
代码题:使用EL表达式和JSTL的
<c:forEach>,遍历一个List<User>并在表格中展示。分析题:在JSP中,
${userName}和<%= request.getAttribute("userName") %>有什么区别?哪个更好?为什么?
📊 你的学习进度
- 当前:第69篇 / 共108篇 ·进阶篇:JavaWeb核心技术(第68~72篇)
- ✅ 已完成:基础篇44篇 + 第45~69篇
- 📖 正在学:第69篇
- ⏳ 待学习:第70~108篇
👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇
👉 下一篇文章预告
🚀下一篇:《第70篇:Cookie与Session》
内容简介:Cookie与Session的原理、区别、分布式Session方案(Spring Session)、登录状态管理实战。
👉JavaWeb专题持续深入,拿下会话管理!
📌《Java 100 天进阶之路 | 从入门到上岗就业》每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!
