1. 概述
JavaServer Pages (JSP) 允许通过 Java 和 Java Servlet 将动态内容注入到静态内容中。我们可以向 Java Servlet 发送请求,执行相关逻辑,然后在服务端渲染特定视图供客户端消费。本文将基于 Java 8 和 Jakarta EE 7 提供对 JSP 的全面解析。
我们将先探讨几个 JSP 核心概念:动态内容与静态内容的区别、JSP 生命周期、JSP 语法、指令以及编译时创建的隐式对象!
2. JavaServer Pages
JavaServer Pages (JSP) 使 Java 特定数据能被传入或嵌入 .jsp 视图并在客户端消费。
JSP 文件本质上是 .html 文件,但带有一些额外语法和两个初始差异:
- 文件扩展名从 .html 改为 .jsp
- 在 HTML 标记顶部添加以下标签:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
下面我们深入 JSP 的几个关键概念。
2.1. JSP 语法
向 .jsp 添加 Java 代码有两种方式。首先是使用基础 Scriptlet 语法,将 Java 代码块放在两个 Scriptlet 标签内:
<% Java code here %>
第二种方式是 XML 特定语法:
<jsp:scriptlet>
Java code here
</jsp:scriptlet>
✅ 关键技巧:可以通过 JSP 在客户端使用条件逻辑,用 if/then/else
子句包裹相关标记块:
<% if (doodad) {%>
<div>Doodad!</div>
<% } else { %>
<p>Hello!</p>
<% } %>
例如,当 doodad
为 true 时显示 div
元素,否则显示 p
元素!
2.2. 静态与动态内容
静态内容 是独立于 RESTful、SOAP、HTTP/HTTPS 请求或用户提交信息消费的固定资源。
动态内容 则会响应用户操作或信息而改变!
JSP 技术实现了静态内容和动态内容职责的清晰分离:
- 服务器(Servlet)管理动态内容
- 客户端(.jsp 页面)作为静态容器,接收注入的动态内容
下面看看 JSP 创建的隐式对象,它们允许你在服务端访问 JSP 相关数据!
2.3. 隐式对象
隐式对象 由 JSP 引擎在编译时自动生成,包括 HttpRequest
和 HttpResponse
等对象,为 Servlet 和 .jsp 交互提供服务端功能。
以下是创建的隐式对象列表:
request
类型:jakarta.servlet.http.HttpServletRequest
暴露所有用户输入数据供服务端使用。
response
类型:jakarta.servlet.http.HttpServletResponse
决定请求后返回客户端的内容。
⚠️ 重点解析 request
和 response
对象(最常用):
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String message = request.getParameter("message");
response.setContentType("text/html");
. . .
}
request
和response
作为方法参数传入- 通过
getParameter()
获取请求参数(如message
) - 通过
response
设置响应类型(如text/html
)
out
类型:jakarta.servlet.jsp.JspWriter
用于向客户端写入内容。
两种输出方式对比:
// 方式1:JspWriter(缓冲后写入response)
out.print("hello");
out.println("world");
// 方式2:PrintWriter(直接写入response,性能更优)
PrintWriter out = response.getWriter();
out.println("Hello World");
2.4. 其他隐式对象
session
类型:jakarta.servlet.http.HttpSession
在会话期间维护用户数据。
application
类型:jakarta.servlet.ServletContext
存储应用级参数(初始化设置或全局访问)。
exception
类型:jakarta.servlet.jsp.JspException
在错误页面(需声明 <%@ page isErrorPage="true" %>
)显示错误信息。
page
类型:java.lang.Object
访问当前 Servlet 信息。
pageContext
类型:jakarta.servlet.jsp.PageContext
默认页面作用域,可访问 request/application/session 属性。
config
类型:jakarta.servlet.ServletConfig
Servlet 配置对象,获取上下文、名称和配置参数。
2.5. 指令
JSP 提供内置指令指定核心功能,由两部分组成:
- 指令本身
- 赋值的指令属性
三种指令类型:
<%@ page ... %> <!-- 定义依赖和属性(如contentType) -->
<%@ include ... %> <!-- 指定导入文件 -->
<%@ taglib ... %> <!-- 指定标签库 -->
示例(JSP 标签版):
<%@ page attribute="value" %>
XML 版本:
<jsp:directive.page attribute="value" />
2.6. 页面指令属性
以下是常用页面指令属性:
属性 | 示例 | 说明 |
---|---|---|
autoFlush | <%@ page autoFlush="false" %> |
控制缓冲区输出(默认 true) |
buffer | <%@ page buffer="19kb" %> |
设置缓冲区大小(默认 8kb) |
errorPage | <%@ page errorPage="errHandler.jsp" %> |
指定错误处理页面 |
extends | <%@ page extends="org.apache.jasper.runtime.HttpJspBase" %> |
指定 Servlet 超类 |
info | <%@ page info="This is my JSP!" %> |
设置 JSP 文本描述 |
isELIgnored | <%@ page isELIgnored="true" %> |
是否忽略 EL 表达式(默认 false) |
isErrorPage | <%@ page isErrorPage="true" %> |
声明当前为错误页面 |
isThreadSafe | <%@ page isThreadSafe="false" %> |
是否启用多线程(默认 true) |
language | <%@ page language="java" %> |
脚本语言(默认 Java) |
session | <%@ page session="true" %> |
是否维护 HTTP 会话 |
trimDirectiveWhitespaces | <%@ page trimDirectiveWhitespaces="true" %> |
编译时移除空白(默认 false) |
3. 三个实战示例
现在我们通过三个基础示例应用上述概念,帮你快速搭建第一个 JSP 服务!
我们将使用 Java 8 和 Jakarta EE 原生功能,演示三种向 .jsp 注入 Java 的方式:
- 服务端渲染标记
- 直接在 .jsp 嵌入 Java
- 请求转发并绑定数据
3.1. Servlet 渲染 HTML
本示例跳过创建 .jsp 文件!我们在 ExampleOne
Servlet 中直接构建 HTML 字符串并通过 PrintWriter
写入响应:
public class ExampleOne extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println(
"<!DOCTYPE html><html>" +
"<head>" +
"<meta charset=\"UTF-8\" />" +
"<title>HTML Rendered by Servlet</title>" +
"</head>" +
"<body>" +
"<h1>HTML Rendered by Servlet</h1></br>" +
"<p>This page was rendered by the ExampleOne Servlet!</p>" +
"</body>" +
"</html>"
);
}
}
💡 这里我们直接通过 Servlet 处理请求并生成 HTML,完全绕过了 JSP!使用 PrintWriter
直接写入 response
对象,比 JspWriter
性能更优(无缓冲层)。
3.2. JSP 静态页面嵌入 Java
创建 ExampleTwo.jsp
,通过 JSP 标签直接嵌入 Java 代码。这里随机显示一个问候语:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<head>
<title>Java in Static Page Example</title>
</head>
<body>
<h1>Java in Static Page Example</h1>
<%
String[] arr = {"What's up?", "Hello", "It's a nice day today!"};
String greetings = arr[(int)(Math.random() * arr.length)];
%>
<p><%= greetings %></p>
</body>
</html>
✅ 关键点:在 JSP 标签内声明变量(String[] arr
)并初始化,完全无需依赖 Servlet。JSP 生命周期会自动处理这些 Java 代码。
3.3. 带转发的 JSP
最完整的示例!使用 @WebServlet
注解(省去 web.xml 配置):
@WebServlet(
name = "ExampleThree",
description = "JSP Servlet With Annotations",
urlPatterns = {"/ExampleThree"}
)
public class ExampleThree extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String message = request.getParameter("message");
request.setAttribute("text", message);
request.getRequestDispatcher("/ExampleThree.jsp").forward(request, response);
}
}
流程解析:
- 获取 URL 参数
message
- 将参数绑定到
request
对象(属性名text
) - 转发请求到
ExampleThree.jsp
对应的 JSP 文件通过 EL 表达式显示绑定数据:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<head>
<title>Java Binding Example</title>
</head>
<body>
<h1>Bound Value</h1>
<p>You said: ${text}</p>
</body>
</html>
⚠️ 注意:这里使用 EL 表达式 ${text}
渲染服务端绑定的数据,实现真正的动态交互!
3.4. 动手试试!
将应用导出为 .war 部署到 Tomcat 8!修改 server.xml
添加 Context:
<Context path="/spring-mvc-xml" docBase="${catalina.home}/webapps/spring-mvc-xml">
</Context>
访问地址:http://localhost:8080/spring-mvc-xml/jsp/index.jsp
完整代码参考:GitHub
4. 总结
我们全面覆盖了 JSP 的核心知识:
- ✅ JSP 的本质与作用
- ✅ 静态/动态内容分离
- ✅ 隐式对象与指令系统
- ✅ 三种实现方式对比
现在你已经掌握了 JSP 的基础用法,可以开始构建自己的动态 Web 应用了!编码愉快!