一些相关理解
| 组件 | 核心定位 | 类比(延续汽车模型) |
|---|---|---|
| JDBC | Java 操作数据库的底层标准 / 接口 | 汽车的 "发动机原理"(底层规则) |
| MyBatis | 封装 JDBC 的持久层框架(简化数据库操作) | 汽车的 "自动挡变速箱"(封装底层) |
| Maven | 项目构建 / 依赖管理工具(下载依赖、打包项目) | 汽车的 "配件采购 / 组装系统" |
| Tomcat | 开源的 Java Web 服务器(Servlet/JSP 容器),提供 Web 应用的运行环境 | 汽车的 "底盘 + 驾驶舱"(提供运行载体) |
| Servlet | Jakarta EE 核心 Web 组件规范,定义 HTTP 请求 / 响应的处理标准,是 Java Web 应用的 "交互核心" | 汽车的 "驾驶控制系统(方向盘 + 油门 / 刹车)"(底盘 / 驾驶舱的核心交互部件,承接用户操作并输出行为) |
| JSTL | JSP 标准标签库,简化 JSP 页面的逻辑编写(替代脚本代码),统一页面层操作规范 | 汽车的 "智能仪表盘"(简化驾驶数据展示 / 操作,替代复杂的手动数据读取) |
| EL(表达式语言) | 简化 JSP/JSTL 页面数据绑定的表达式规范,无需编写复杂代码即可获取 / 展示数据 | 汽车仪表盘的 "快捷显示控件"(一键展示车速 / 油量,替代手动查数据) |
Jakara EE Web 官方手册
https://jakarta.ee/specifications/webprofile/
https://jakarta.ee/specifications/webprofile/
Java EE Web11 的 Maven coordinate
API接口聚合包
Snippets部分是一个API接口聚合包 ,使用它就相当于导入Jakarta EE Web Profile(对应版本) 规范定义的所有核心 API 接口, 其中还提供了一些其他的软件项目构建工具对应的API聚合预制配置片段


下面子包部分官方仅以「Maven 坐标(groupId:artifactId:version)」作为包的核心分发标识,所有包都发布到Maven 中央仓库 (Java 生态的通用仓库);其他构建工具的 "预制配置片段"需要开发者自行转换配置语法
Apache Tomcat Versions Apache Tomcat版本
官网如下
https://tomcat.apache.org/whichversion.html
https://tomcat.apache.org/whichversion.html
Apache Tomcat® 是 Jakarta EE(前身为 Java EE)技术子集的开源软件实现
这里是一些对应的规范 
相关报错解决
具体从底层到使用框架的整合流程
| 组件联动逻辑 | 汽车模型类比 | 实际业务场景 |
|---|---|---|
| Servlet(驾驶控制系统)整合 JDBC(发动机原理) | 驾驶员操作方向盘 / 油门(Servlet 接收前端请求)→ 驾驶控制系统触发发动机按 "发动机原理"(JDBC)工作 → 发动机输出动力(数据库返回数据)→ 控制系统反馈给驾驶员(Servlet 返回响应) | 用户在浏览器点击 "查询订单"→ Servlet 接收请求 → 调用 JDBC 查询数据库的订单表 → 把订单数据返回给浏览器展示 |
| Maven(配件采购 / 组装系统)先统一采购适配 Tomcat(底盘)的 Servlet(驾驶控制系统)、MyBatis(自动挡变速箱)、JDBC 驱动(发动机配件)等标准化配件,按版本规范完成编译 / 组装;Servlet(驾驶控制系统)接收前端请求后,调用 MyBatis(自动挡变速箱)→ MyBatis 封装 JDBC(发动机原理)完成数据库操作 → 结果经 MyBatis 简化处理后返回给 Servlet → Servlet 最终返回响应 | 配件采购 / 组装系统(Maven)按底盘(Tomcat)型号,采购原厂适配的方向盘(Servlet)、自动挡变速箱(MyBatis)、发动机适配配件(JDBC 驱动),并按底盘规格完成变速箱与方向盘、发动机的调试匹配;驾驶员操作方向盘(Servlet)→ 自动挡变速箱(MyBatis)自动按发动机原理(JDBC)控制发动机运转(无需手动操作离合 / 换挡)→ 发动机输出动力(数据库返回数据)→ 变速箱简化动力传输逻辑,反馈给方向盘(Servlet)→ 驾驶员收到行驶反馈 | 用户在浏览器点击 "查询订单"→ Maven 已提前整合好 MyBatis、Servlet、MySQL 驱动的依赖并编译项目;Servlet 接收请求后调用 MyBatis 的 Mapper 接口(无需手写 JDBC 连接 / SQL 执行代码)→ MyBatis 自动完成数据库连接、执行订单查询 SQL、将结果映射为 Order 对象 → Servlet 拿到 Order 对象后组装成响应,返回给浏览器展示 |
具体兼容问题
- 因为项目通过Servlet整合JDBC,进而使用Maven软件构建工具来使用Mybatis框架整合Servlet,但是使用的JSTL过低与原项目版本不同,这里发现所有的Servlet中相关Jakara都爆红了

- 理论上任何构建工具都能整合任何框架,但需满足 "构建工具能适配框架的依赖 / 打包要求"(如 Gradle 也能整合 MyBatis+Servlet,只是配置语法不同)
所以需要修改Maven专属且核心配置文件pom.xml中的

以下是修改后的格式,修改后就没有问题了,问了豆包后发现太有意思了,从1.2版本发展到3.00版本这个++全球唯一的组织ID++居然改变了,而且还要引入两个,仅导入规范或实现都会出现错误,且添加这个避免打包重复的<scope>标签,这就不得不看一下它的背景了
仅导入api规范jar包
仅导入实现jar包

dependency中依赖的具体属性
| 属性标签 | 通用作用 | 本例中值的具体作用 | 汽车模型类比 |
|---|---|---|---|
<groupId> |
全球唯一标识依赖的所属组织 / 厂商 / 项目组,避免不同组织的依赖重名 | 第一个依赖:jakarta.servlet.jsp.jstl → 归属「Jakarta EE 官方」(定义 JSTL 规范的组织);第二个依赖:org.glassfish.web → 归属「Eclipse 旗下 GlassFish 项目的 Web 子模块」(Jakarta EE 规范的核心实现方) |
配件的 "生产品牌":第一个 ="汽车行业标准制定机构"(定义定速巡航的规则);第二个 ="博世(Bosch)"(按规则生产定速巡航配件的厂商) |
<artifactId> |
在所属 groupId 下,唯一标识具体的 JAR 包名称,区分同一组织下的不同依赖 |
第一个依赖:jakarta.servlet.jsp.jstl-api → 后缀 -api 表明是「JSTL 3.0 规范的接口包」(仅定义 <c:forEach> 等标签的规则,无执行逻辑);第二个依赖:jakarta.servlet.jsp.jstl → 无 -api 后缀,表明是「JSTL 3.0 接口的具体实现包」(包含标签的实际执行代码) |
配件的 "具体型号":第一个 ="定速巡航设计图纸(仅规则)";第二个 ="定速巡航实际零件(可执行)" |
<version> |
指定依赖的具体版本号,Maven 下载对应版本的 JAR 包,避免版本兼容问题 | 第一个依赖:3.0.0 → 对应 Jakarta EE 官方定义的 JSTL 3.0 接口版本;第二个依赖:3.0.1 → GlassFish 团队适配 JSTL 3.0 接口的实现版本(小版本差异是实现方的迭代,兼容 3.0 接口) |
配件的 "生产批次 / 版本":第一个 ="设计图纸的 3.0 版本";第二个 ="按 3.0 图纸生产的 3.0.1 版零件" |
<scope> |
控制依赖的生命周期(生效阶段、是否打包、是否冲突) | 第一个依赖:provided → 仅「编译 / 测试阶段」生效,不打包到 WAR 包 (原因:实现包已包含 API,打包会重复冲突);第二个依赖:compile → 「编译 / 测试 / 运行阶段」均生效,必须打包到 WAR 包(原因:Tomcat 不内置 JSTL 实现,需靠这个包运行标签) |
配件的 "使用场景标签":第一个 ="仅工厂调试时用,不装上车";第二个 ="工厂调试 + 上路行驶都要用,必须装上车" |
FAQ
这两个依赖分别是什么?核心区别是什么?
- 第一个依赖(jakarta.servlet.jsp.jstl-api:3.0.0) :Jakarta EE 官方提供的「JSTL 3.0 规范接口包(API)」,仅含
<c:forEach>等标签的规则定义(无执行逻辑),类比 "定速巡航设计图纸"。 - 第二个依赖(org.glassfish.web:jakarta.servlet.jsp.jstl:3.0.1):GlassFish 团队提供的「JSTL 3.0 接口实现包」,含标签的实际执行代码(让 JSTL 功能真正运行),类比 "按图纸造的定速巡航零件"。
- 核心区别:前者是 "规则",后者是 "执行逻辑",二者缺一不可。
什么是WAR包呀?它和JAR包有什么区别?
| 包类型 | 核心定义 | 汽车模型类比 |
|---|---|---|
| JAR 包(Java Archive) | 通用的 Java 打包格式:把编译后的 class 文件、配置文件、依赖库打包成一个压缩包,可独立运行(纯 Java 程序)或作为依赖被其他项目引用 | 汽车的「通用配件盒」:比如 "单独的定速巡航零件盒""方向盘零件盒"------ 可单独存放 / 使用,也能装进更大的汽车模块(如驾驶舱) |
| WAR 包(Web Application Archive) | 专属 Web 项目的打包格式:针对 Java Web 项目(含 Servlet/JSP/JSTL/ 静态资源),必须部署到 Web 容器(Tomcat/Jetty)才能运行,不能独立执行 | 汽车的「完整驾驶舱模块」:包含方向盘(Servlet)、仪表盘(JSTL)、中控屏(静态资源)等所有 Web 相关配件 ------ 必须装到汽车底盘(Tomcat)上才能用,不能单独当 "整车" 跑 |
两个依赖的<scope>为什么分别设为provided和compile?
- 第一个(API 包)设
provided:仅编译 / 测试时用,不打包到 WAR 包。原因是实现包已内置兼容的 API,打包会导致重复冲突(类似图纸只在工厂调试用,不用装上车)。 - 第二个(实现包)设
compile:编译 / 测试 / 运行全阶段生效,必须打包到 WAR 包。原因是 Tomcat 10 + 不内置 Jakarta 命名空间的 JSTL 实现,需靠这个包运行标签(类似零件必须装上车,才能用定速巡航)。
引出核心背景:为什么从1.2到3.00版本需要导入两个jar包还要写scope?
版本 1:JSTL 1.2(2006 年,Java EE 5/6 时代,javax 命名空间)
1. 核心背景
- 生态主导方 :Oracle 主导 Java EE 规范,JSTL 作为 Java EE 核心扩展规范,设计上采用 "API + 实现一体化" 打包逻辑,无强制拆分要求
- 容器适配 :Tomcat 7/8/9(主流容器)内置完整的 JSTL 1.2 实现(包含 API 接口 + 执行逻辑),容器层面兜底所有 JSTL 运行依赖
- 依赖管理 :Java EE 时代开发侧重 "快速可用",Maven 依赖管理以 "极简" 为核心,无需精细化管控依赖范围
2.核心逻辑
- 不用两个 JAR:JSTL 1.2 的官方包是 "一体化包",
javax.servlet:jstl:1.2一个 JAR 既包含<c:forEach>等标签的接口定义,也包含执行逻辑,无需拆分;- 不用配 scope:Tomcat 7/8/9 内置了 JSTL 1.2 实现,即使依赖设为
compile(打包到 WAR 包),Tomcat 运行时会优先使用内置实现,不会出现 "打包重复" 或类冲突;甚至不导入该依赖,Tomcat 也能解析 JSTL 1.2 标签。
版本 2:JSTL 3.0(2020 年,Jakarta EE 9/10 时代,jakarta 命名空间)
1. 核心背景
- 生态重构 :++Oracle 将 Java EE 捐赠给 Eclipse 基金会,重命名为 Jakarta EE,核心调整++
- 命名空间强制切换:从
javax.servlet.jsp.jstl改为jakarta.servlet.jsp.jstl- 规范设计解耦:Jakarta EE 强制 "接口(API)与实现分离"------ 官方仅定义 JSTL 3.0 API(规则),实现交由第三方(如 GlassFish)开发 ,且 API 和实现必须拆分为独立 JAR
- 容器适配调整 :Tomcat 10+(适配 Jakarta EE)仅内置 Servlet/JSP 的 Jakarta API,不再内置任何 JSTL 3.0 实现(JSTL 归为 "扩展规范",非核心)
- 依赖管理升级 :Jakarta EE 适配微服务 / 模块化开发,要求精细化管控依赖生命周期,避免冲突
2.核心逻辑
- 必须两个 JAR:Jakarta EE 规范强制拆分 API 和实现,API 包(
jakarta.servlet.jsp.jstl-api)仅定义标签规则,实现包(org.glassfish.web:jakarta.servlet.jsp.jstl)提供执行逻辑,二者缺一不可(无 API 则编译报错,无实现则运行报错)- 必须配 scope:
- API 包设
provided:实现包内部已依赖 API,若 API 包设为compile(默认),会被打包到 WAR 包,与实现包中的 API 重复,导致类加载冲突(如两个jakarta.servlet.jsp.jstl.core.ForEachTag类)- 实现包设
compile:Tomcat 10 + 不内置 JSTL 3.0 实现,必须将实现包打包到 WAR 包,才能让 JSTL 标签正常运行
到这里已经很明白这部分了,你能看到这里,我也就来做一个总结,可以看到1.2版本的快速可用到3.00的精细可控,这意味着工具随时代的需求而改变,作为开发者来说,应该找到最适合需求的工具去行开发
下面如果你还有兴趣,我们再打深一层,来看看Oracle 为什么将 Java EE(含 JSTL、Servlet 等规范)捐赠给 Eclipse 基金会
Oracle 将 Java EE(含 JSTL、Servlet 等规范)捐赠给 Eclipse 基金会

补充:这里又发现了一个问题,由于我多次试验导入不同的jar包来编译可能导致了残留进而再次报上面那个错误,这里给出解决方案



去配置文件中删掉工件(即war包)重新再部署,运行,就好了



