这七项技术,几乎每个踩过 Web 开发门槛的人都对着它们发过呆。我见过太多新手能把"HTML 是超文本标记语言、CSS 是样式表、JavaScript 是脚本语言"背得滚瓜烂熟,一放进项目就懵——特别是 jQuery、JSP、JSTL、Ajax 这几个带缩写的,听着就像一家子,实际各干各的活儿,分属完全不同的阵营。
这篇文章我打算换个讲法:不按技术列表一项一项背定义,而是把七项技术全部放进一次真实的浏览器请求里,看它们在请求链路上各自站在哪个位置、负责哪个环节。定位清楚了,区别和用途自然就浮出水面。适合刚学完基础语法、正在做第一个完整项目的同学,也适合从纯前端转后端的开发者重新梳理知识版图。
1. 先建立全局视角:七项技术在同一条请求链路上的位置
1.1 用一次浏览器请求,走完七项技术的"站台"
想象你在地址栏输入一个网址,回车。这一瞬间开始,浏览器和服务器之间发生了一次完整的对话,七项技术在这场对话里各司其职:
第一步,浏览器向服务器发起请求。如果请求的是.html这类静态文件,服务器直接把文件原样丢回;如果请求的是.jsp,服务器不会傻乎乎把 JSP 文件给你看,而是先在服务器内部执行 JSP 里的 Java 代码和 JSTL 标签,把动态数据拼进去,生成一份纯 HTML,再送回浏览器。这个阶段,JSP 和 JSTL 在服务器端工作,用户从头到尾看不到它们的存在。
第二步,浏览器收到 HTML 后,开始解析。HTML 负责定义页面的骨架——有哪些标题、表格、文本框;CSS 负责让骨架好看——颜色、间距、圆角、动画;JavaScript 负责让页面"活"起来——点击按钮弹出弹窗、校验表单、操作页面元素。这三项都在浏览器里运行,统称前端三兄弟。
第三步,用户在页面上操作,比如删除一行数据。这时候 Ajax 登场了。它让 JavaScript 在不刷新整个页面的前提下,悄悄给服务器发一条请求,等数据回来后再用 JavaScript 更新页面局部内容。注意,Ajax 请求的目标可以是 Servlet、JSP,也可以是返回 JSON 的 REST 接口。
第四步,回到服务器。如果是传统 JSP 项目,请求打到 Servlet,Servlet 查数据库、拼数据,要么转发给 JSP 让 JSTL 渲染成 HTML 返回,要么直接把 JSON 字符串写回响应,交给浏览器里的 JavaScript 处理。
jQuery 在这条链路里更像一个"工具箱",它本身就是 JavaScript 写的,只是把原生 JavaScript 里繁琐的 DOM 操作、事件绑定、Ajax 请求封装成了更简洁的写法。它不改变任何分工,只是让干活更顺手。
1.2 一张表格看懂七项技术的边界
**| 技术 | 运行位置 | 核心职责 | 最终产物 | | --- | --- | --- | --- | | HTML | 浏览器 | 定义页面结构和内容 | DOM 节点 | | CSS | 浏览器 | 定义视觉表现与布局 | 渲染后的样式 | | JavaScript | 浏览器(也有 Node.js 服务端) | 行为逻辑、动态操作、发送请求 | 操作 DOM、收发数据 | | jQuery | 浏览器 | 封装原生 JS 的工具库 | 简化的 JS 代码 | | JSP | 服务器(Servlet 容器) | 动态生成 HTML 内容 | HTML 片段或完整页面 | | JSTL | 服务器 | JSP 里的标准标签库 | JSP 渲染时的逻辑控制 | | Ajax | 浏览器 | 异步收发数据的技术方式 | 局部页面更新 |
这里有个关键认知:前端技术(HTML/CSS/JS/jQuery/Ajax)跑在浏览器里,服务端技术(JSP/JSTL)跑在服务器里。很多人混淆 JSP 和 JavaScript,就是因为没弄明白这个最基本的运行环境差异。
2. 前端三兄弟:HTML、CSS、JavaScript 的分工与边界
2.1 HTML 管结构、CSS 管表现、JavaScript 管行为
我常用盖房子来比喻这三者的关系。HTML 是房子的框架和户型图——哪里是客厅、哪里是卧室、承重墙在哪,这些决定了页面有什么;CSS 是装修设计方案——墙面刷什么颜色、沙发摆哪个位置、窗帘什么质感,这些决定了页面长什么样;JavaScript 是房子的水电和智能系统——按下开关灯亮、拉开窗帘自动透光、门禁识别来客,这些决定了页面能做什么。
看一段极简的例子就能感受到分工:
<!-- HTML:定义骨架 --> <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <title>用户信息卡</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="card" id="userCard"> <h2 class="card-title">张三</h2> <p class="card-desc">前端工程师,喜欢折腾新技术</p> <button id="followBtn">关注</button> </div> <script src="app.js"></script> </body> </html>/* CSS:负责表现 */ .card { border-radius: 8px; padding: 20px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); } .card-title { font-size: 20px; color: #333; }// JavaScript:负责行为 let btn = document.getElementById('followBtn'); btn.addEventListener('click', function() { btn.textContent = '已关注'; btn.disabled = true; });注意 HTML 里的<link rel="stylesheet" href="style.css">和<script src="app.js"></script>,这就是在 HTML 骨架里挂载 CSS 和 JavaScript 的方式。CSS 和 JS 可以写在一份 HTML 文件内部,也可以拆成独立文件,实际项目中基本都推荐拆文件,方便缓存和维护。
2.2 容易走偏的三个"灰色地带"
新手常在这三个问题上纠结,我直接说结论:
第一,"CSS 能做动画,JavaScript 也能做动画,到底该用谁?"能用 CSS 实现的视觉动画(过渡、旋转、缩放)优先用 CSS,浏览器渲染效率高;需要根据数据或交互状态动态变化的复杂动画才用 JavaScript。比如鼠标移入卡片弹出一个缩放效果,纯 CSS 的transition: transform 0.3s几十行代码;用 JavaScript 去写同样的效果,要维护时间轴、状态和回调,复杂度完全不在一个量级。网上经常有人搜"CSS 3D旋转正负判断核心规则",像transform: rotateY(60deg) translateZ(300px)这种写法,本质还是 CSS 在管视觉,无非是用到了 3D 空间里的坐标系——X 轴向右、Y 轴向下、Z 轴指向屏幕外,rotateY 正角度让元素绕垂直轴旋转,配合 translateZ 把元素拉近或推远。这些能力属于 CSS 的表现层,和 JavaScript 的逻辑层井水不犯河水。
第二,"JavaScript 能操作 HTML 结构,是不是就取代 HTML 了?"取代不了。JavaScript 操作的是 HTML 解析后的 DOM 树,DOM 节点依然有标签、有属性、有层级结构,操作方式完全遵循 HTML 的规则。你可以把它理解成"装修工人可以砸墙、砌墙,但不能凭空造一座不用结构的房子"。
第三,"CSS 能不能写逻辑?"严格说 CSS 有层叠、继承、媒体查询、自定义属性这些机制,看起来有点像条件判断,但它不是编程语言,没有循环、没有函数、没有变量运算,不能根据用户输入动态改变内容。凡是页面内容随数据变化的,必须由 JavaScript 或服务端技术完成。
2.3 工程实践中的引入习惯
我强烈建议你养成这个习惯:CSS 放<head>里通过<link>引入,JavaScript 放<body>末尾或使用defer属性加载。原因很简单——CSS 不阻塞 HTML 解析,但样式没加载完页面会闪一下"裸奔"效果;JavaScript 放在末尾是为了确保执行时 DOM 已经解析完毕,不用额外写DOMContentLoaded监听。另外企业项目通常用打包工具(Webpack/Vite)把多个 CSS、多个 JS 合并压缩,再按页面需求按需加载,这些属于工程化范畴,等你看清前端三兄弟的分工后再进阶不迟。
3. jQuery:当年为什么火,如今为什么"退居二线"
3.1 它解决的根本问题:烦、乱、不一致
jQuery 诞生于 2006 年前后,那个时代前端开发处于"黑暗丛林"——IE6、IE7、Firefox、Chrome 各有各的 DOM API,写着同一段代码,在一个浏览器正常、另一个浏览器直接报错。原生 JavaScript 操作 DOM 还极其啰嗦,查找一个元素要写一长串document.getElementById,给十个按钮绑事件要写十遍。jQuery 的核心价值就三个:选择器让找元素变简单、链式调用让操作变连贯、封装层屏蔽浏览器差异。
看代码最有说服力。同样是把id="msg"的段落文字改成"加载成功"并加上高亮样式:
// 原生 JavaScript var el = document.getElementById('msg'); el.textContent = '加载成功'; el.classList.add('highlight');// jQuery $('#msg').text('加载成功').addClass('highlight');链式写法一句话搞定。再比如给页面上所有.item绑定点击事件:
// 原生 JS var items = document.querySelectorAll('.item'); for (var i = 0; i < items.length; i++) { items[i].addEventListener('click', handler); } // jQuery $('.item').on('click', handler);在当年的浏览器环境下,这个简化不是锦上添花,是实打实的工程量削减。jQuery 还提供了成熟的插件生态,轮播图、日期选择器、弹窗组件随便找一个就能用,写页面效率飞快。
3.2 jQuery 为什么风光不再
核心原因是"对手变强了"。现代浏览器统一了标准,querySelector、querySelectorAll、fetch、classList这些原生 API 覆盖了 jQuery 大部分高频功能;CSS3 也把很多原本依赖 jQuery 插件实现的动画、布局需求吞掉了。更关键的是,Vue、React 这类框架把"操作 DOM"这件事从"手动指挥浏览器"升级成了"声明数据和视图的关系,框架自动帮你更新",jQuery 的"直接改 DOM"思路已经不在同一层面了。
但这不等于 jQuery 应该被拉黑。我这些年维护过的传统 JSP 项目里,jQuery 依然是主力。老系统跑得好好的,没有重构的必要,新需求用 jQuery 加几句$(...)也能快速交付。到 2025 年 jQuery 3.x 仍在维护,官方还在发安全更新。利刃老不老,看它上什么战场。
3.3 给选型一个明确建议
新项目我不会推荐引入 jQuery——现代浏览器原生 API、框架、打包工具已经能给出更好的方案;但接到老项目维护任务时,jQuery 是必须熟练掌握的日常武器。尤其配合 Ajax 操作,$.ajax封装得比原生fetch在某些场景下更好用,代码也更短。这个后面展开讲。
4. JSP 与 JSTL:服务端模板技术的定位与边界
4.1 JSP 的本质:会被翻译成 Servlet 的动态模板
JSP(JavaServer Pages)的定位,简单说就是服务端动态生成 HTML 的模板技术。它长得像 HTML,但里面可以嵌入 Java 代码片段和 JSTL 标签。关键理解在于:JSP 文件不是给浏览器看的,而是给服务器(Tomcat 这类 Servlet 容器)看的。
我第一次接触 JSP 时一直想不通"JSP 里能写 Java 代码,那它算 Java 文件还是 HTML 文件"。后来明白了:JSP 的生命周期里,第一次被访问时,Tomcat 会把它翻译成一个 Java 源文件(对应一个 Servlet 类),编译成 class,然后实例化执行。执行结果是什么?是一个完整的 HTML 响应。也就是说,JSP 的最终产物是 HTML,但它生成 HTML 的过程发生在服务器端。
对比一下静态 HTML 和 JSP 的处理差异:
| 请求资源 | 服务器处理方式 | 浏览器收到什么 |
|---|---|---|
hello.html | 直接原样返回文件内容 | 固定的 HTML |
hello.jsp | 翻译、编译、执行 Java 代码、生成 HTML | 执行后的 HTML(内容可能每次不同) |
这个区别就是"静态页面"和"动态页面"的本质分界。HTML 文件里写什么,用户永远看到什么;JSP 可以根据数据库数据、用户身份、时间日期,生成不同的 HTML 内容。
举个最朴素的最小 JSP 例子:
<%@ page contentType="text/html; charset=utf-8" %> <!DOCTYPE html> <html> <head> <title>当前时间</title> </head> <body> <h1>欢迎回来</h1> <p>服务器时间是:<%= new java.util.Date() %></p> </body> </html><%= new java.util.Date() %>会在服务器端先执行,把当前时间拼进 HTML,再发给浏览器。如果这是静态 HTML,你永远只能看到文件里写死的那串文本。
4.2 JSTL:把 Java 代码从 JSP 里撵出去的标签库
JSP 虽然能写 Java 代码,但真把<% if (...) { %>这种脚本片段到处乱写,页面很快就会变成一团乱麻——HTML 标签和 Java 代码交错,维护的人想骂人。JSTL(JSP Standard Tag Library)就是为此而生的解决方案:用标签代替脚本逻辑。
比如循环输出一个用户列表,脚本写法是:
<% List<User> users = (List<User>) request.getAttribute("users"); for (User u : users) { %> <tr> <td><%= u.getName() %></td> <td><%= u.getEmail() %></td> </tr> <% } %>JSTL 写法是:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:forEach var="u" items="${users}"> <tr> <td>${u.name}</td> <td>${u.email}</td> </tr> </c:forEach>代码干净多了。${u.name}是 EL 表达式(Expression Language),自动调用getName()方法,省的自己拼 Java 代码。JSTL 常用的还有<c:if>、<c:choose>、<c:when>处理条件判断,<fmt:formatDate>格式化日期。
注意 JSTL 不是一门新语言,它是 JSP 生态里的标准标签集合,本质上是 Java 后台渲染模板的辅助工具。它的价值在于把 JSP 的视图层从"HTML+Java 混合脚本"净化成"HTML+标签",让页面更接近模板,让 Java 逻辑回到 Servlet 层。
4.3 部署边界:为什么"nginx 支不支持 JSP"是个伪问题
很多人搜"Nginx 支不支持 JSP",本质上是没搞清 JSP 的部署边界。Nginx 是静态 Web 服务器,它擅长的是高效返回静态资源(HTML/CSS/JS/图片)和做反向代理。JSP 需要 Java Servlet 容器编译执行,Tomcat、Jetty 这类容器才懂 JSP。所以正确答案是:Nginx 直接"不支持"JSP,也不需要支持。常规部署方案是 Nginx 处理静态资源,遇到.jsp的动态请求反向代理转发给 Tomcat,Tomcat 解析执行后把 HTML 返回,再由 Nginx 交给浏览器。
还有一个常见的入门困惑:"IDEA 新建 JSP 项目"到底怎么操作。其实 IDEA 里新建项目时选 Java Enterprise,配置好 Tomcat,然后把.jsp文件放进webapp目录,启动 Tomcat 就能访问。老式项目打包成 WAR 文件丢进 Tomcat 的webapps目录也能部署。说白了 JSP 从开发到部署都绑定在 Java Servlet 容器这条生态链上,跟 Nginx 的职责天然分叉。
5. Ajax:异步交互技术,以及它和前面六项的关系
5.1 "异步"两个字才是重点
Ajax(Asynchronous JavaScript And XML)并不是一门语言,它是一种在浏览器里使用 JavaScript 异步发送请求、局部更新页面的技术方式。拆开理解:
- JavaScript:发请求的脚本语言,Ajax 的技术基础。
- 异步:发请求后不等服务器返回,浏览器继续干别的,数据到达后再通过回调处理。
- XML:早期数据交换格式,现在基本被 JSON 取代,名字里还留着历史的痕迹。
同步和异步的区别,我用点外卖类比:同步就是你在窗口下单,人堵在柜台前干等,厨房做好递给你你才走;异步就是你用 App 下单,然后爱干嘛干嘛,外卖到了骑手打电话通知你取。传统的表单提交是同步的,点提交按钮,浏览器整个刷新,那体验就是"页面白一下再跳转";Ajax 请求是异步的,你点了"删除",页面毫无动静地发请求,数据回来只更新那一行的 DOM,全程不打断你阅读其他内容。
5.2 从原生 XHR 到 $.ajax 再到 fetch
Ajax 的技术内核是浏览器提供的XMLHttpRequest对象。原生写法长这样:
var xhr = new XMLHttpRequest(); xhr.open('POST', '/api/deleteUser', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText); } }; xhr.send('id=101');这个写法有几个痛点:readyState四个状态值要背、回调写法嵌套多了就乱、请求头设置繁琐。jQuery 把这一切封装成了$.ajax,不少老项目的实际代码长这样:
$.ajax({ url: '/deleteUser', type: 'POST', data: { id: 101 }, dataType: 'json', success: function(res) { if (res.code === 0) { $('#row_101').remove(); } else { alert(res.message); } }, error: function() { alert('请求失败,请稍后重试'); } });“给 Ajax 请求参数赋值”这个问题,十有八九就是data字段的键值对怎么填。你传data: { id: 101 },jQuery 会自动编码成id=101放在请求体里,后端用request.getParameter("id")就能拿到,两端字段名保持一致就不会出错。
现代原生 API 里还有一个fetch,写法比 XHR 简洁不少:
fetch('/deleteUser', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'id=101' }).then(res => res.json()).then(data => { if (data.code === 0) $('#row_101').remove(); });这跟 jQuery 的$.ajax是同一件事的两种写法。选哪个取决于项目基础:老项目有 jQuery 就顺手用$.ajax;新项目完全可以只依赖fetch,少引一个库。
5.3 JSP + JSTL + Ajax 的完整配合场景
既然 JSP 能动态生成页面,为什么还需要 Ajax 做局部更新?举个非常典型的功能:用户列表页,展示所有用户记录。首屏渲染完全可以交给 JSP 和 JSTL——服务器从数据库查出用户列表,用<c:forEach>循环输出成一个 HTML 表格。但用户点"删除"这个动作,如果也用 JSP 同步处理,就得让整个页面重新刷新一遍,体验极其割裂。
正确分工是:JSP + JSTL 负责首屏展示,Ajax 负责后续的细粒度交互。这样一套下来,七项技术全部用上了:
- HTML:定义表格、按钮等页面结构。
- CSS:让表格和按钮好看。
- JSP:接收 Servlet 传过来的用户集合,控制整体页面结构。
- JSTL:在 JSP 内循环输出每一行用户数据。
- JavaScript:给每个删除按钮绑定点击事件。
- jQuery:简化事件绑定和 Ajax 提交。
- Ajax:点删除后发异步请求,局部移除那一行。
如果搜"jsp 个人信息展示页面",你搜到的教程大概率也是这个套路:JSP 负责把request里的个人数据渲染成 HTML,CSS 美化卡片,JavaScript/jQuery 处理一些小的交互效果,Ajax 负责异步保存修改。这套老模式直到今天依然大量存在于存量系统里,值得完全搞懂。
6. 按需选型的判断方法:从传统 JSP 项目到前后端分离
6.1 传统 JSP 项目:七项技术各归其位
我前几年接手的某内部管理系统,就是教科书式的七项技术全家桶。技术栈大概是:前端 HTML/CSS/JavaScript 管界面结构样式,jQuery 管 DOM 操作和 Ajax,JSP 加 JSTL 在服务器端渲染最核心的表格页面,Servlet 接收请求查数据,Ajax 处理按钮级别的交互。
这套组合的本质是服务端渲染为主、前端交互为辅。JSP 承担"页面生成主力",这意味着首屏速度快,HTML 到浏览器手里就是最终模样;缺点也很明显,每次页面跳转都要走一遍请求-渲染流程,局部更新只能靠 Ajax 额外打补丁。这种模式下,JSP 是七项技术里的"中枢",其他技术围绕它协作。
6.2 前后端分离:退场的不只是 JSP
前后端分离的架构流行后,变化不是某个单一技术消失,而是一整套分工重划:前端用 HTML/CSS/JavaScript(加上 Vue/React 这类框架)接管全部页面渲染,后端不再返回 HTML 页面,而是只返回数据(通常是 JSON),前端通过 Ajax/fetch 请求数据再自己生成 DOM。JSP 和 JSTL 在这个架构里彻底退场,纯静态 HTML 配 Nginx 就够;jQuery 也基本退役,被框架的响应式数据绑定取代。
这不是说 JSP 被"淘汰"了,而是它解决的问题换了一种解法——页面渲染从"服务端生成 HTML"变成了"客户端生成 DOM",服务端只做数据接口。存量 JSP 系统还在跑,新起项目基本不会再用。选型时看你的场景和团队结构,没有绝对先进,只有是否合适。
6.3 新手最常问的五个边界问题
| 问题 | 答案 |
|---|---|
| JSP 和 JavaScript 谁在前端谁在后端? | JSP 运行在服务器端,生成 HTML 后交给浏览器;JavaScript 运行在浏览器端,操作页面行为和局部更新。两者可以配合,但运行环境完全不同。 |
| jQuery 是 JavaScript 的替代品吗? | 不是。jQuery 本身就是 JavaScript 写的库,它是"封装工具",不是"另一种语言"。 |
| Ajax 是一种语言还是框架? | 都不是。Ajax 是浏览器端使用 JavaScript 实现异步请求与局部更新的技术方式,底层是XMLHttpRequest或fetch。 |
| JSTL 和 jQuery 都有"标签/选择器",功能类似吗? | 完全不在一个层面。JSTL 是服务器端 JSP 的标签库,jQuery 是浏览器端的 JS 库,二者运行环境和服务对象完全不同。 |
| 一个项目必须同时用到七项技术才算完整吗? | 不是。七项技术是历史演进中不同生态层的代表,具体用哪些取决于项目架构和时代背景。传统 JSP 项目可能七项全上,前后端分离项目只用前端三项加 Ajax。 |
第五个问题我想多说一句。我在带新人的时候,发现大家特别喜欢把技术名词按数量往项目里堆——学完一项就往代码里塞一项,生怕自己"用少了"。这是纯学生思维。技术的选取是需求驱动的:页面要动态渲染,才需要 JSP/JSTL;交互要局部刷新,才引入 Ajax;DOM 操作写起来太烦,才考虑 jQuery。没有需求硬上,只会让代码更乱。
关于学习顺序,最后聊两句
如果你正卡在"七项技术到底先学哪个"的岔路口,我的建议是顺着请求链路学,别按字母顺序背。先把 HTML 和 CSS 摸熟,做一个静态页面;然后学 JavaScript,试着用原生代码改这个静态页面的 DOM;接着把 jQuery 当成一个更省力的"改 DOM 帮手"来学;再学 JSP,让页面内容能跟随服务器数据变化;JSTL 是 JSP 的优化刀,写几遍脚本式 JSP 再换成标签式,自然理解它的价值;最后把 Ajax 嵌进来,让页面动起来不刷新。
每个环节都是下一个环节的前置条件。我见过太多人跳过前两步直接啃 JSP,结果就是连"为什么页面里会出现 Java 代码"都想不通。按链路走一遍,这些技术在你心里的坐标就再也不会歪了。