1.2 技术演进与规范版本脉络


1.2 技术演进与规范版本脉络

本节摘要:JSP 从 1999 年的 1.0 版走到 2013 年的 2.3 版,再到 Jakarta EE 时代的定位固化,二十多年间每个大版本都在回应上一代留下的痛点:1.1 引入自定义标签、2.0 引入 EL 与对 MVC 的官方背书、2.1 之后转向与 Servlet 规范的协同。读懂这条时间线,你就能对着青梧书肆里风格混杂的页面判断出各自的"出生年代",并预判它们各自的兼容性雷区。上一节我们建立了"页面即翻译后的类"的图景,本节解释这份图景在不同年代呈现的不同面貌,下一节则让它在你的机器上真正跑起来。

代码库里为什么同时住着三个年代

上节末尾你已经能用"模板文本加脚本片段"的眼光拆解一个页面了。现在把视野拉远:打开青梧书肆的页面目录,你会注意到一个奇怪现象——同样是列表页,book_list.jsp 里全是 <% %> 包裹的 Java 循环,search.jsp 却写着 ${param.keyword} 这种从未见过的美元花括号语法,还有个别老页面在用 <jsp:include> 动作元素拼页面。三种风格并存,不是前任维护者精神分裂,而是三个规范年代的地层堆积。

JSP 的规范演进不是推倒重来式的换代,每一版都在旧地层之上加新层,且默认兼容旧写法。这就是老站点最典型的样貌:它是一份技术考古现场,最底层可能有二十岁的高龄,最上层也有十年没动过了。想安全施工,先得会读地层。

图1-2 JSP 规范演进的地层剖面

图1-2 JSP 规范演进的地层剖面

版本时间线:每一版都在还上一版的债

把地层展开成清单,脉络会更清楚。读这张表时别背年份,盯住"它解决了什么"这一列——规范的每次升级都是对已暴露问题的回应,这条因果链才是接手老站时真正用得上的东西。

版本与年份 关键变化 它解决了上一版的什么问题
JSP 1.0 · 1999 脚本片段、指令、动作元素的基本语法 让 Java 程序员不用字符串拼接就能写动态页面
JSP 1.1 · 1999 自定义标签机制 脚本片段把逻辑摊在页面里,无法复用也无法封装
JSP 1.2 · 2001 标签扩展完善、错误处理增强 早期标签能力太弱,页面出错时缺乏体面的处理通道
JSP 2.0 · 2003 EL 表达式、JSTL 官方化、明确 MVC 视图定位 取值还要写 Java 代码,视图与逻辑仍然纠缠
JSP 2.1 · 2006 EL 独立成规范 表达式语言被钉死在 JSP 里,其他技术无法复用
JSP 2.2 · 2009 与 Servlet 3.0 协同、注解配置 配置全靠描述文件,改个映射也要动全局文件
JSP 2.3 · 2013 安全性与细节打磨 无颠覆性变化,标志着技术进入维护期

三个值得单独点名的节点。其一是 2.0:EL 表达式用 ${user.name} 取代 <%= user.getName() %>,看似只是省键盘,实际意义在于页面里从此可以不出现 Java 语句——视图去脚本化的路从这里才真正打通,第 5 章的改造全靠这层地基。其二是 1.1 的自定义标签:它证明"页面里除了脚本还可以有第三种东西",第 6 章的标签车间直接继承这套机制。其三是 Jakarta 更名:2017 年 Java EE 移交 Eclipse 基金会后,包名前缀从 javax 逐步迁往 jakarta,这是今天维护老站时判断"容器能不能直接跑这套代码"的硬约束之一,第 10 章部署时会再次撞上它。

一个真实的雷区:EL 在老容器配置里集体失灵

年代地层最阴险的地方在于:新语法写在旧层里不会报错,只会悄悄失效。给你讲青梧书肆里的一个真实案例。

背景:搜索页 search.jsp 用 EL 写成,本地新容器上一切正常;部署到站点所在的旧容器后,页面上的搜索关键词、结果数量全部原样显示成 ${param.keyword} 字符串,数据一个都没取到。

操作:先怀疑标签库没导入,检查发现页面压根没用 JSTL;再翻容器日志,没有异常。最后对比新旧容器的部署描述文件,找到差异——旧工程里这样声明:

<!-- 旧工程的部署描述文件片段 --> <web-app version="2.3" xmlns="http://java.sun.com/xml/ns/j2ee"> <jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <el-ignored>true</el-ignored> </jsp-property-group> </jsp-config> </web-app>

结果:把开关改为 false 并升级声明的规范版本后重新部署,EL 恢复取值。

解读:规范版本低于 2.0 的工程,或被显式设置了忽略 EL 开关的页面组,容器会按老规则把 ${...} 当普通文本。这不失信心的地方在于它完全符合规范——旧工程按旧规范办事,天经地义。类似的时代裂缝还有不少:2.0 之前的页面里写 EL 注释、统一表达式里的函数调用,都会遇到同类沉默失败。

变式:反过来也成立——你往最老的基岩层页面里加 EL,想顺手"现代化"一下,结果整页白屏或输出乱码,原因往往是那个页面声明了旧的页面指令或工程本身按 1.2 规范校验。接手时的纪律是:改哪层,先确认哪层的规范版本,别跨层施工。

💡 关键直觉:老站点的语法混杂不是脏,是地层。每一层按它当年生效的规范解读,一半的"灵异故障"会自动消失。

用三问给页面断代

结合 1.1 的翻译机制与本节的时间线,你现在可以对任意一个页面做快速断代。三个问题按顺序问:

  1. 取值用什么写法? 满页 <%= %> 是基岩层居民;出现 ${...} 则至少是 2.0 之后装修过;满页 c:forEach 之类的前缀标签,说明做过 JSTL 改造,观念上已进入视图去脚本化阶段。
  2. 配置靠什么生效? 全局配置都堆在一个部署描述文件里的是老做法;用注解直接标注在类上的至少是 Servlet 3.0 协同之后。这决定了你改配置时的动作半径。
  3. 包名前缀是什么? 引入 javax 命名空间的代码可以直接在传统容器上跑;看到 jakarta 前缀则必须配新一代容器。这一问在下一节搭环境时马上要用——容器选型的第一依据就是它。

断代不是学究趣味。第 7 章补安全课时你会发现,XSS 这类漏洞的典型重灾区恰恰是基岩层页面;第 8 章做性能体检时,连接池缺失、脚本混杂这些病灶也集中在老层。手里有地层图,病灶位置基本可以提前圈出来。

读地层的两个补充判断

断代之外还有两条实用推论。其一,地层决定"哪些写法可以直接抄"。青梧书肆里最可靠的参考代码不是最新的 search.jsp,而是与新改动同层的页面——同层写法依赖同层的规范特性,抄过来不会踩跨层雷;从新层往基岩层抄 EL,就会复现上一节那类沉默失效。其二,升级规范版本是一项要单独立项的工程,不是顺手改个声明数字。版本声明从旧跳到新,容器会按新规则重新校验全部页面,一些当年合法的宽松写法会当场变成编译错误——这也是为什么老站点的版本声明常年停留在旧值:不是没人想升,是升一次等于全站回归一次。把这个代价写进交接文档,下一位维护者就不会误以为那是懒惰。

本节要点回顾

  • 规范是分层沉积的:JSP 1.0 到 2.3 再到 Jakarta 时代,每版都在旧层上加新层,老站点因此呈现多年代语法并存的考古现场样貌;
  • 2.0 是分水岭:EL 与 JSTL 让视图第一次可以完全不写 Java 语句,第 5 章的去脚本化改造以此为地基;
  • 旧层不认新语法且不报错:规范版本声明与忽略 EL 开关会让 ${...} 静默失效,排查时先查工程声明的规范版本;
  • 三问断代法:取值写法、配置方式、包名前缀,三问定年代,顺带圈出安全与性能病灶的高发区。

下一节我们把镜头从历史拉回你的桌面:装容器、摆目录、部署、访问,四步让青梧书肆在你的机器上亮起来——全书所有演练都依赖这一节搭好的环境。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U