一、JSP简介
JSP
(JavaServer Pages
) 是与 PHP
、ASP
、ASP.NET
等类似的脚本语言,JSP
是为了简化Servlet
的处理流程而出现的替代品,早期的Java EE
因为只能使用Servlet
来处理客户端请求而显得非常的繁琐和不便,使用JSP可以快速的完成后端逻辑请求。
正因为在JSP
中可以直接调用Java代码来实现后端逻辑的这一特性,黑客通常会编写带有恶意攻击的JSP文件(俗称WebShell
)来实现对服务器资源的恶意请求和控制。
现代的MVC框架(如:Spring MVC 5.x
)已经完全抛弃了JSP
技术,采用了模板引擎(如:Freemark)
或者RESTful
的方式来实现与客户端的交互工作,或许某一天JSP
技术也将会随着产品研发的迭代而彻底消失。
1.1 JSP 语法基础
JSP (JavaServer Pages) 的基础语法主要是在 HTML (或 XML) 页面中嵌入 Java 代码片段和特定的 JSP 标签,以实现动态内容生成。
- 一、JSP 指令 (
<%@ ... %>
)作用:为整个 JSP 页面提供全局信息和设置,影响页面的整体结构和行为。它们在 JSP 被编译成 Servlet 时生效。
常用指令:
1)
page
:定义页面属性。<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ page import="java.util.Date, com.example.MyClass" %> <!-- 导入Java包 --> <%@ page session="true" %> <!-- 是否启用session对象 --> <%@ page errorPage="error.jsp" %> <!-- 指定错误处理页面 --> <%@ page isErrorPage="true" %> <!-- 声明当前页为错误处理页 -->
2)
include
:在 JSP 页面被编译时(编译时包含),静态地包含另一个文件(如另一个 JSP、HTML 或文本文件)的内容。<%@ include file="header.jsp" %>
3)
taglib
:声明页面中使用的标签库(如 JSTL)。<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- 二、JSP 声明 (
<%! ... %>
)**作用:在 JSP 页面中声明成员变量和方法。这些变量和方法会成为生成的 Servlet 类的成员变量和方法。
<%! // 成员变量 private int counter = 0; // 成员方法 public String greetUser(String name) { return "Hello, " + name + "!"; } %>
- 三、JSP 脚本片段 (
<% ... %>
)作用:包含一段 Java 代码片段。这段代码会被插入到生成的 Servlet 的
_jspService()
方法中(相当于 Servlet 的service()
方法)。这是处理请求逻辑的主要地方。<% // Java 代码 String username = request.getParameter("username"); if (username != null && !username.isEmpty()) { out.println("Welcome, " + username); } else { out.println("Please enter your name."); } %>
- 四、JSP 表达式 (
<%= ... %>
)作用:计算一个 Java 表达式,并将结果转换为字符串后直接输出到页面上。表达式结尾**不需要分号 (
;
)**。<p>The current time is: <%= new java.util.Date() %></p> <p>Your username is: <%= request.getParameter("username") %></p> <p>Counter value: <%= counter %></p> <!-- 使用声明中定义的counter -->
- 五、JSP 注释 (
<%-- ... --%>
)作用:添加注释,这些注释不会出现在最终发送给浏览器的 HTML 源代码中。
<%-- This is a JSP comment. It won't be visible in the browser. --%> <!-- This is an HTML comment. It WILL be visible in the browser source. -->
- 六、隐含对象 (Implicit Objects)
作用:JSP 容器(如 Tomcat)在将 JSP 转换为 Servlet 时,会自动声明和初始化一些对象,供你在脚本片段和表达式中直接使用。这些对象代表与请求、响应、会话等相关的信息。
常用隐含对象:
request:HttpServletRequest 对象,代表客户端的 HTTP 请求。 response:HttpServletResponse 对象,代表发送给客户端的 HTTP 响应。 out:JspWriter 对象,用于向客户端输出内容(类似于 PrintWriter,但有缓冲区)。 session:HttpSession 对象,代表与用户关联的会话(如果 page 指令的 session="true")。 application:ServletContext 对象,代表整个 Web 应用程序。 pageContext:PageContext 对象,提供对页面所有作用域(page, request, session, application)和隐含对象的访问。 config:ServletConfig 对象,包含 Servlet 初始化参数。 page:相当于 Java 中的 this,指当前 JSP 页面实例(很少直接使用)。 exception:Throwable 对象,仅在错误处理页面(isErrorPage="true")中可用,代表抛出的异常。
- 七、EL (Expression Language)
作用:虽然严格来说不是原始 JSP 语法的一部分,但它是现代 JSP 开发中极其重要且推荐的补充,用于简化对隐含对象、JavaBean 属性、集合等的访问。语法:
${expression}
<p>Welcome, ${param.username}</p> <!-- 相当于 <%= request.getParameter("username") %> --> <p>User Agent: ${header['User-Agent']}</p> <p>Session ID: ${sessionScope.sessionId}</p> <p>Customer Name: ${customer.name}</p> <!-- 访问JavaBean属性 -->
- 八、JSTL (JSP Standard Tag Library)
作用:同样不是基础语法,但强烈推荐使用。它提供了一组标准标签(如循环、条件判断、格式化、数据库访问等),用于替换 JSP 脚本片段 (
<% ... %>
),使页面更易读、易维护。需要先使用taglib
指令引入。<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:if test="${not empty param.username}"> <p>Welcome, <c:out value="${param.username}"/></p> </c:if> <c:forEach var="item" items="${shoppingCart.items}"> <li><c:out value="${item.name}"/> - $<c:out value="${item.price}"/></li> </c:forEach>
1.2 JSP 表达式(EL)
EL表达式
(Expression Language
)语言,常用于在jsp页面中获取请求中的值,如获取在Servlet中设置的Attribute
:${名称}
。使用EL表达式可以实现命令执行,我们将会在后续EL表达式章节中详细讲解。
1.3 JSP 标准标签库(JSTL)
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。
1.4 JSP 九大对象
从本质上说 JSP 就是一个Servlet,JSP 引擎在调用 JSP 对应的 jspServlet 时,会传递或创建 9 个与 web 开发相关的对象供 jspServlet 使用。 JSP 技术的设计者为便于开发人员在编写 JSP 页面时获得这些 web 对象的引用,特意定义了 9 个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这 9 大对象的引用。
如下:
变量名 | 类型 | 作用 |
---|---|---|
pageContext | PageContext | 当前页面共享数据,还可以获取其他8个内置对象 |
request | HttpServletRequest | 客户端请求对象,包含了所有客户端请求信息 |
session | HttpSession | 请求会话 |
application | ServletContext | 全局对象,所有用户间共享数据 |
response | HttpServletResponse | 响应对象,主要用于服务器端设置响应信息 |
page | Object | 当前Servlet对象,this |
out | JspWriter | 输出对象,数据输出到页面上 |
config | ServletConfig | Servlet的配置对象 |
exception | Throwable | 异常对象 |
总结
- 基础核心:
<%@ %>
(指令),<%! %>
(声明),<% %>
(脚本片段),<%= %>
(表达式),<%-- --%>
(注释) 以及隐含对象构成了 JSP 最原始的基础。 - 现代开发: 强烈建议优先使用 EL (
${}
) 和 JSTL 标签 来访问数据和实现逻辑控制。它们使 JSP 页面更清晰、更接近纯 HTML/XML,更易于维护,并有助于分离表示层逻辑(视图)和业务逻辑(通常在 Servlet 或 JavaBean 中)。 - 避免过度使用脚本片段: 直接在 JSP 中嵌入大量 Java 代码 (
<% %>
) 会使页面难以阅读和维护(通常称为“Spaghetti Code”)。应遵循 MVC 模式,将业务逻辑放在 Servlet 或 JavaBean 中,JSP 主要负责显示。 - JSP 生命周期: 理解 JSP 页面会被容器(如 Tomcat)翻译成一个 Servlet 类(
.java
文件),然后编译成.class
文件并加载执行,有助于理解其工作原理。
二、JSP和Servlet之间的关系
JSP、JSPX 文件是可以直接被 Java 容器直接解析的动态脚本, jsp 和其他脚本语言无异,不但可以用于页面数据展示,也可以用来处理后端业务逻辑。
从本质上说 JSP 就是一个Servlet
,因为 jsp 文件最终会被编译成 class 文件,而这个 class 文件实际上就是一个特殊的Servlet
。
JSP文件会被编译成一个java类文件,如index.jsp
在Tomcat中Jasper
编译后会生成index_jsp.java
和index_jsp.class
两个文件。而index_jsp.java
继承于HttpJspBase
类,HttpJspBase
是一个实现了HttpJspPage
接口并继承了HttpServlet
的标准的Servlet
,__jspService
方法其实是HttpJspPage
接口方法,类似于Servlet
中的service
方法,这里的__jspService
方法其实就是HttpJspBase
的service
方法调用。
参考
- https://www.javasec.org/ 【java安全】