JSP在Web开发中做什么,和JavaScript分工有何不同

作者:栖木

时间:2026-10-30

浏览:649

深入解析JSP在Web开发中的实际职责与运行原理,对比JSP与JavaScript在运行环境、执行时机、代码可见性及协同工作中的本质不同,帮助开发者理清技术分工与架构认知。

文章目录
Web开发基础 架构与分工 服务端渲染与前端交互

初涉 Web 开发的开发者在维护或阅读旧项目时,经常会看到以 .jsp 结尾的文件。打开之后,里面既有常规的 HTML 标签,又有以 <% ... %> 包裹的 Java 代码,同时在 <script> 中还写着 JavaScript。这常常让人产生困惑:JSP 和 JavaScript 名字如此相似,它们到底谁负责什么?是不是同一种技术的两种形态?实际上,二者不仅技术体系完全独立,且在执行位置、生命周期及职责分工上有着天壤之别。

一、JSP在Web开发中扮演什么角色

JSP(JavaServer Pages)是由 Sun Microsystems 公司于 1999 年推出的一种服务端动态网页技术标准。它的核心使命非常明确:在服务器端动态生成网页内容(HTML、XML 或其他文本格式),并将渲染完毕的结果发送给浏览器。

为了理解 JSP 的作用,我们需要回到没有 JSP 的传统 Java Web 时代。早期的 Java Web 开发主要依赖 Servlet。在 Servlet 中,如果想要向用户展示一个包含动态用户名的网页,开发者必须在 Java 类中使用流输出语句逐行拼接 HTML 字符串:

// 早期纯 Servlet 生成页面的方式
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>欢迎回来," + username + "</h1>");
out.println("<p>您的账户余额为:" + balance + "</p>");
out.println("</body></html>");

这种纯代码硬编码 HTML 的方式极其繁琐,页面结构稍微复杂就会导致代码难以维护,前端工程师更无法参与页面模板的编写。JSP 的诞生正是为了解决这一痛点——它允许开发者反向操作:以 HTML 结构为主体,仅在需要插入动态数据的地方嵌入 Java 表达式与脚本标签。

<!-- index.jsp: 以 HTML 为主体的动态模板 -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
  <h1>欢迎回来,<%= request.getAttribute("username") %></h1>
  <p>您的账户余额为:<%= request.getAttribute("balance") %></p>
</body>
</html>

在整个 Web 体系中,JSP 是部署在 Web 容器(如 Apache Tomcat、Jetty 等)内部的服务端组件。它能够直接访问 Java EE 的上下文对象(如 request、session、application),调用后端的业务逻辑与数据库查询接口,把查询出来的实体数据装配进页面骨架中。当整个装配过程结束后,JSP 输出的是标准的 HTML 文本流,随 HTTP 响应报文输出给访问者。

JSP在Web开发中做什么,和JavaScript分工有何不同
图 1:JSP 与 JavaScript 运行环境与核心架构全景对比

二、JSP的生命周期与底层执行原理

很多初学者以为 JSP 是像 Python 或 PHP 那样直接由解释器逐行读取解释执行的,这种理解并不准确。在 Java EE 规范中,JSP 的本质依然是一个标准的 Servlet 类。从 .jsp 源文件到用户最终看到的网页,内部经历了一套严谨的翻译与编译流程:

  1. 转译阶段(Translation):当客户端第一次向服务器请求某个 .jsp 文件时,容器内部的 JSP 引擎(例如 Tomcat 的 Jasper 模块)会将该文件转译成一个纯正的 Java 源代码文件(即 .java 文件)。在转译过程中,HTML 静态标签被包装进 out.write(...) 方法中,而 <% ... %> 内的 Java 代码则被原封不动地植入服务方法中。
  2. 编译阶段(Compilation):Java 编译器(Javac)立即将生成的 .java 文件编译成字节码 .class 文件。
  3. 类加载与实例化(Class Loading & Instantiation):Servlet 容器把该 .class 文件加载进 JVM 内存,并创建该 Servlet 类的唯一单例实例。
  4. 初始化与服务执行(Execution):容器调用 _jspInit() 进行初始化,随后针对每一个用户 HTTP 请求,分配独立的工作线程调用其 _jspService(HttpServletRequest, HttpServletResponse) 方法。
  5. 输出纯 HTML 并销毁:在 _jspService() 执行完毕后,服务端把组装好的 HTML 内容推入 HTTP 响应缓冲区,整个 JSP 的执行流程结束。当服务器关闭或应用卸载时,调用 _jspDestroy() 释放资源。
缓存机制提示:JSP 的转译和编译只在“首次访问”或“JSP 源文件被修改后首次访问”时发生一次。后续所有针对该页面的访问,都会直接复用已经驻留在 JVM 内存中的 Servlet 单例,因此无须重复转译和编译。这也是为什么旧系统初次打开某个 JSP 页面时略有迟钝,而再次刷新时响应速度极快的原因。
JSP在Web开发中做什么,和JavaScript分工有何不同
图 2:JSP 的底层生命周期转译机制与代码隔离原理

三、JavaScript在Web开发中的核心分工

明确了 JSP 的服务端定位之后,我们再来看 JavaScript。JavaScript 最初由 Brendan Eich 在 Netscape 浏览器中发明,遵循 ECMAScript 标准。它的传统核心职责是:驻留于用户的浏览器环境中,接管页面呈现之后的动态事件响应、用户输入校验、DOM(文档对象模型)操作以及网络异步交互。

当服务器(无论是通过 JSP 还是其他技术)把 HTML 页面推送给浏览器后,JSP 的工作就已经彻底结束了。接下来整个页面的交互生命周期,完全交由浏览器的 JavaScript 引擎掌控:

  • 即时事件响应:用户在输入框内打字、鼠标移动划过菜单、点击折叠面板或提交表单时,JavaScript 会立即捕获对应的 DOM 事件并触发回调函数。这种响应是在用户本地电脑上毫秒级完成的,不需要向远程服务器发送请求。
  • 动态操作文档对象模型(DOM):通过 document.getElementById()、querySelector() 以及现代框架的响应式机制,JavaScript 可以在页面已经显示的情况下,随意修改节点文本、增删标签、改变 CSS 样式、播放过渡动画。
  • 客户端校验与拦截:在用户提交数据之前,前端 JavaScript 可以率先检查密码强度、手机号格式是否合规。如果格式不合法,直接在界面上提示红字,避免无谓的网络请求耗费服务器算力。
  • 异步通信(Ajax / Fetch):这是现代 Web 交互的核心基石。JavaScript 可以在不重新加载整页的情况下,在后台向服务端 API 发送 HTTP 请求获取新数据,并局部刷新当前视图。

四、二者如何协同工作:从表单提交看时序分工

为了直观展现二者在实际项目中的分工配合,我们以一个经典的用户登录页面为例,对比在整个流程中二者各自在什么时间点工作、负责处理什么事务:

JSP在Web开发中做什么,和JavaScript分工有何不同
图 3:JSP 服务端首屏直出与客户端 JavaScript 异步交互协同全流程

代码层面的协同范例

在实际代码中,开发者经常会在同一个 .jsp 文件中看到二者的配合。以下是一个非常典型的历史代码片段:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 1. 服务端 Java 代码 (JSP 阶段执行)
    // 从 Session 中读取服务端生成的 CSRF 防护令牌
    String csrfToken = (String) session.getAttribute("CSRF_TOKEN");
%>
<!DOCTYPE html>
<html>
<head>
  <title>用户登录</title>
</head>
<body>
  <form id="loginForm">
    <!-- JSP 把服务端的动态数据打印成 HTML 的属性值 -->
    <input type="hidden" id="token" value="<%= csrfToken %>">
    
    <input type="text" id="username" placeholder="请输入用户名">
    <span id="errorTips" style="color:red;"></span>
    <button type="button" id="submitBtn">立即登录</button>
  </form>

  <script>
    // 2. 客户端 JavaScript 代码 (浏览器中执行)
    // 此时 JSP 早已执行完毕离开服务器,浏览器拿到的是组装好的纯文本
    document.getElementById("submitBtn").addEventListener("click", function() {
      var user = document.getElementById("username").value.trim();
      var token = document.getElementById("token").value;
      
      // 前端校验:不需要发起网络请求
      if (!user) {
        document.getElementById("errorTips").innerText = "用户名不能为空!";
        return;
      }
      
      // 发送 Ajax 异步请求与后端控制器通信
      fetch("/api/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ username: user, token: token })
      }).then(res => res.json()).then(data => {
        if(data.success) {
          window.location.href = "/dashboard";
        }
      });
    });
  </script>
</body>
</html>

仔细观察上面的代码结构:<%= csrfToken %> 是在服务器内部被替换为具体的令牌字符串(例如 token-abc123xyz);替换完毕后,生成的整段 HTML 连同底部的 <script> 原封不动传给浏览器。随后浏览器中的 JavaScript 引擎运行脚本,挂载点击事件监听器。这清晰地印证了二者的分工逻辑。

五、为什么名字如此相似?历史渊源与命名内幕

很多开发者会好奇,既然二者从底层规范到运行机制毫无共同点,为什么名字里都有“Java”?

这纯粹是 20 世纪 90 年代的一场商业营销策略所致:

  • Java:由 Sun 公司于 1995 年推出,是一门严格面向对象、运行于 JVM 的强类型编译型编程语言。
  • JavaScript:由 Netscape 公司工程师 Brendan Eich 设计。最初原名叫 Mocha,后来改名为 LiveScript。当时 Sun 公司的 Java 语言在科技界名声大噪、风头正劲。Netscape 为了蹭上 Java 的超高热度,与 Sun 达成营销合作,临时将其改名为 JavaScript。
  • JSP(JavaServer Pages):Sun 公司为了抗衡微软的 ASP(Active Server Pages),在 1999 年基于自身成熟的 Java 技术生态推出的服务端模板规范。由于直接使用 Java 作为后台逻辑语言,因此顺理成章命名为 JavaServer Pages。

行业内有一句经典的幽默比喻:“Java 和 JavaScript 的关系,就像雷锋和雷峰塔、卡车和卡布奇诺一样,名字纯属巧合,内在毫无血缘关系。” 理解了这段历史,就不会再对名字产生先入为主的技术混淆。

六、全维度对比与现代技术演进选型

为了让不同场景下的选型与理解更加清晰,我们将 JSP 与 JavaScript 的关键维度归纳如下:

对比维度 JSP (JavaServer Pages) JavaScript (前端 JS / 浏览器端)
运行物理位置 后端服务器(Tomcat、WebLogic 等 Web 容器内部) 用户本地终端(Chrome、Safari、Edge 等浏览器内)
底层语言与规范 Java 语言标准,依赖 Java EE / Jakarta EE Servlet 规范 ECMAScript 规范标准,解释型/JIT 动态脚本语言
核心工作职责 读取服务端数据,生成并输出初始 HTML 结构模板 处理页面事件交互、DOM 动态刷新、表单校验与异步请求
执行时机与寿命 仅在收到 HTTP 请求时触发,输出 HTML 数据流后立即结束 随页面在浏览器加载而启动,在用户整个浏览期间持续存活
代码对用户可见性 完全不可见。用户浏览器端只能看到生成后的 HTML 完全公开可见。脚本文件直接下载到客户端供浏览器执行
底层资源访问权限 高。可直接操作服务端文件系统、内网 Redis、关系数据库 受沙箱严格限制。无法随意读写用户本地磁盘,只能通过网络接口通信
现代开发流行度 逐渐淡出主流,主要存在于政企传统系统及老旧 Spring MVC 维护 极其繁荣。现代 Web 绝对核心,覆盖全平台与跨端开发
JSP在Web开发中做什么,和JavaScript分工有何不同
图 4:Web 架构演进全景与现代开发选型决策指南

七、常见混淆点与避坑排查清单

在日常开发与维护中,许多初学者经常会陷入以下几个常见误区:

误区 1:在 JavaScript 函数中直接调用 JSP 的 Java 方法

<script>
  function handleClick() {
    // 错误写法示范:误以为前端点击能够动态执行后端的 Java 方法
    <%
        // 这是在服务端转译时执行的,而不是点击按钮时执行!
        userService.deleteUser(1001);
    %>
    alert("删除完成");
  }
</script>

原因剖析:JSP 的 <% ... %> 标签是在页面还没有发送给用户之前就在服务器运行完毕的。当用户在浏览器中看到页面并点击按钮时,服务器上的 Java 进程早就执行完了!如果需要点击按钮后删除用户,唯一正确的路径是让 JavaScript 发送 Ajax 请求调用服务器暴露的 HTTP 接口。

误区 2:在 JSP 脚本块中试图读取 JavaScript 的变量值

<script>
  var clientWidth = window.innerWidth;
</script>
<%
  // 错误写法示范:此时页面在服务器端,浏览器还没运行,更没有 window 对象
  // int width = clientWidth; // 编译报错:找不到符号
%>

原因剖析:时序完全颠倒。JSP 执行在先,JavaScript 执行在后。在服务器端组装 HTML 文本的时候,用户的浏览器甚至都还没有建立网络连接,根本不存在 window、document 或任何客户端变量。

误区 3:Node.js 让 JavaScript 也能跑在服务端,是否等于 JSP?

随着 Node.js 的普及,JavaScript 确实具备了在服务端运行的能力,甚至也能编写 SSR(服务端渲染)程序。但从架构设计来看,Node.js 依然遵循 ECMAScript 标准与事件循环模型,而 JSP 则是严格基于 Java EE / Jakarta EE 标准构建的 Servlet 体系。二者的技术底座、生态库与并发模型依旧完全不同。

结语

总而言之,JSP 做的是服务端的事情,负责在请求到达时查询数据、渲染骨架,交付一个成型的 HTML 网页;而 JavaScript 做的是客户端的事情,负责在用户浏览器中赋予页面生命力,处理每一次点击、输入与无刷新异步通信。认清两者的运行位置与时序顺序,便能轻松解开历史遗留代码中的技术交织,并在现代 Web 开发中做出清晰严谨的技术决策。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章