JavaWeb 之 Jsp 指南
简介
什么是 Java Server Pages
JSP
全称Java Server Pages
,是一种动态网页开发技术。
它使用 JSP 标签在 HTML 网页中插入 Java 代码。标签通常以 <%
开头以 %>
结束。
JSP 是一种 Java servlet,主要用于实现 Java web 应用程序的用户界面部分。网页开发者们通过结合 HTML 代码、XHTML 代码、XML 元素以及嵌入 JSP 操作和命令来编写 JSP。
JSP 通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。
JSP 标签有多种功能,比如访问数据库、记录用户选择信息、访问 JavaBeans 组件等,还可以在不同的网页中传递控制信息和共享信息。
JSP 工作原理
JSP 是一种 Servlet,但工作方式和 Servlet 有所差别。
Servlet 是先将源代码编译为 class 文件后部署到服务器下的,先编译后部署。
Jsp 是先将源代码部署到服务器再编译,先部署后编译。
Jsp 会在客户端第一次请求 Jsp 文件时被编译为 HttpJspPage 类(Servlet 的一个子类)。该类会被服务器临时存放在服务器工作目录里。所以,第一次请求 Jsp 后,访问速度会变快就是这个道理。
JSP 工作流程
网络服务器需要一个 JSP 引擎,也就是一个容器来处理 JSP 页面。容器负责截获对 JSP 页面的请求。
JSP 容器与 Web 服务器协同合作,为 JSP 的正常运行提供必要的运行环境和其他服务,并且能够正确识别专属于 JSP 网页的特殊元素。
下图显示了 JSP 容器和 JSP 文件在 Web 应用中所处的位置。
工作步骤
以下步骤表明了 Web 服务器是如何使用 JSP 来创建网页的:
- 就像其他普通的网页一样,您的浏览器发送一个 HTTP 请求给服务器。
- Web 服务器识别出这是一个对 JSP 网页的请求,并且将该请求传递给 JSP 引擎。通过使用 URL 或者.jsp 文件来完成。
- JSP 引擎从磁盘中载入 JSP 文件,然后将它们转化为 servlet。这种转化只是简单地将所有模板文本改用 println()语句,并且将所有的 JSP 元素转化成 Java 代码。
- JSP 引擎将 servlet 编译成可执行类,并且将原始请求传递给 servlet 引擎。
- Web 服务器的某组件将会调用 servlet 引擎,然后载入并执行 servlet 类。在执行过程中,servlet 产生 HTML 格式的输出并将其内嵌于 HTTP response 中上交给 Web 服务器。
- Web 服务器以静态 HTML 网页的形式将 HTTP response 返回到您的浏览器中。
- 最终,Web 浏览器处理 HTTP response 中动态产生的 HTML 网页,就好像在处理静态网页一样。
以上提及到的步骤可以用下图来表示:
一般情况下,JSP 引擎会检查 JSP 文件对应的 servlet 是否已经存在,并且检查 JSP 文件的修改日期是否早于 servlet。如果 JSP 文件的修改日期早于对应的 servlet,那么容器就可以确定 JSP 文件没有被修改过并且 servlet 有效。这使得整个流程与其他脚本语言(比如 PHP)相比要高效快捷一些。
JSP 生命周期
理解 JSP 底层功能的关键就是去理解它们所遵守的生命周期。
JSP 生命周期就是从创建到销毁的整个过程,类似于 servlet 生命周期,区别在于 JSP 生命周期还包括将 JSP 文件编译成 servlet。
以下是 JSP 生命周期中所走过的几个阶段:
- 编译阶段: servlet 容器编译 servlet 源文件,生成 servlet 类
- 初始化阶段: 加载与 JSP 对应的 servlet 类,创建其实例,并调用它的初始化方法
- 执行阶段: 调用与 JSP 对应的 servlet 实例的服务方法
- 销毁阶段: 调用与 JSP 对应的 servlet 实例的销毁方法,然后销毁 servlet 实例
很明显,JSP 生命周期的四个主要阶段和 servlet 生命周期非常相似,下面给出图示:
JSP 编译
当浏览器请求 JSP 页面时,JSP 引擎会首先去检查是否需要编译这个文件。如果这个文件没有被编译过,或者在上次编译后被更改过,则编译这个 JSP 文件。
编译的过程包括三个步骤:
- 解析 JSP 文件。
- 将 JSP 文件转为 servlet。
- 编译 servlet。
语法
脚本
脚本程序可以包含任意量的 Java 语句、变量、方法或表达式,只要它们在脚本语言中是有效的。
脚本程序的语法格式:
1 | <% 代码片段 %> |
或者,您也可以编写与其等价的 XML 语句,就像下面这样:
1 | <jsp:scriptlet> |
任何文本、HTML 标签、JSP 元素必须写在脚本程序的外面。
下面给出一个示例,同时也是本教程的第一个 JSP 示例:
1 | <html> |
中文编码问题
如果我们要在页面正常显示中文,我们需要在 JSP 文件头部添加以下代码:<>
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
接下来我们将以上程序修改为:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
这样中文就可以正常显示了。
JSP 声明
一个声明语句可以声明一个或多个变量、方法,供后面的 Java 代码使用。在 JSP 文件中,您必须先声明这些变量和方法然后才能使用它们。
JSP 声明的语法格式:
1 | <%! declaration; [ declaration; ]+ ... %> |
或者,您也可以编写与其等价的 XML 语句,就像下面这样:
1 | <jsp:declaration> |
程序示例:
1 | <%! int i = 0; %> <%! int a, b, c; %> <%! Circle a = new Circle(2.0); %> |
JSP 表达式
一个 JSP 表达式中包含的脚本语言表达式,先被转化成 String,然后插入到表达式出现的地方。
由于表达式的值会被转化成 String,所以您可以在一个文本行中使用表达式而不用去管它是否是 HTML 标签。
表达式元素中可以包含任何符合 Java 语言规范的表达式,但是不能使用分号来结束表达式。
JSP 表达式的语法格式:
1 | <%= 表达式 %> |
同样,您也可以编写与之等价的 XML 语句:
1 | <jsp:expression> |
程序示例:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
运行后得到以下结果:
1 | 今天的日期是: 2016-6-25 13:40:07 |
JSP 注释
JSP 注释主要有两个作用:为代码作注释以及将某段代码注释掉。
JSP 注释的语法格式:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
运行后得到以下结果:
1 | 今天的日期是: 2016-6-25 13:41:26 |
不同情况下使用注释的语法规则:
语法 | 描述 |
---|---|
<%-- 注释 --%> |
JSP 注释,注释内容不会被发送至浏览器甚至不会被编译 |
<!-- 注释 --> |
HTML 注释,通过浏览器查看网页源代码时可以看见注释内容 |
<% |
代表静态 <% 常量 |
%> |
代表静态 %> 常量 |
' |
在属性中使用的单引号 |
" |
在属性中使用的双引号 |
控制语句
JSP 提供对 Java 语言的全面支持。您可以在 JSP 程序中使用 Java API 甚至建立 Java 代码块,包括判断语句和循环语句等等。
if…else 语句
If…else
块,请看下面这个例子:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
运行后得到以下结果:
1 | IF...ELSE 实例 |
switch…case 语句
现在来看看 switch…case 块,与 if…else 块有很大的不同,它使用 out.println(),并且整个都装在脚本程序的标签中,就像下面这样:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
浏览器访问,运行后得出以下结果:
1 | SWITCH...CASE 实例 |
循环语句
在 JSP 程序中可以使用 Java 的三个基本循环类型:for,while,和 do…while。
让我们来看看 for 循环的例子,以下输出的不同字体大小的”菜鸟教程”:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
运行后得到以下结果:
将上例改用 while 循环来写:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
浏览器访问,输出结果为(fontSize 初始化为 0,所以多输出了一行):
JSP 运算符
JSP 支持所有 Java 逻辑和算术运算符。
下表罗列出了 JSP 常见运算符,优先级从高到底:
类别 | 操作符 | 结合性 |
---|---|---|
后缀 | () [] . (点运算符) |
左到右 |
一元 | ++ - - ! ~ |
右到左 |
可乘性 | * / % |
左到右 |
可加性 | + - |
左到右 |
移位 | >> >>> << |
左到右 |
关系 | > >= < <= |
左到右 |
相等/不等 | == != |
左到右 |
位与 | & |
左到右 |
位异或 | ^ |
左到右 |
位或 | ` | ` |
逻辑与 | && |
左到右 |
逻辑或 | ` | |
条件判断 | ?: |
右到左 |
赋值 | `= += -= *= /= %= >>= <<= &= ^= | =` |
逗号 | , |
左到右 |
JSP 字面量
JSP 语言定义了以下几个字面量:
- 布尔值(boolean):true 和 false;
- 整型(int):与 Java 中的一样;
- 浮点型(float):与 Java 中的一样;
- 字符串(string):以单引号或双引号开始和结束;
- Null:null。
指令
JSP 指令用来设置整个 JSP 页面相关的属性,如网页的编码方式和脚本语言。
JSP 指令以开<%@
开始,以%>
结束。
JSP 指令语法格式如下:
1 | <%@ directive attribute="value" %> |
指令可以有很多个属性,它们以键值对的形式存在,并用逗号隔开。
JSP 中的三种指令标签:
指令 | 描述 |
---|---|
<%@ page ... %> |
定义网页依赖属性,比如脚本语言、error 页面、缓存需求等等 |
<%@ include ... %> |
包含其他文件 |
<%@ taglib ... %> |
引入标签库的定义,可以是自定义标签 |
Page 指令
Page 指令为容器提供当前页面的使用说明。一个 JSP 页面可以包含多个page
指令。
Page 指令的语法格式:
1 | <%@ page attribute="value" %> |
等价的 XML 格式:
1 | <jsp:directive.page attribute="value" /> |
例:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
Include 指令
JSP 可以通过include
指令来包含其他文件。
被包含的文件可以是 JSP 文件、HTML 文件或文本文件。包含的文件就好像是该 JSP 文件的一部分,会被同时编译执行。
Include 指令的语法格式如下:
1 | <%@ include file="文件相对 url 地址" %> |
include 指令中的文件名实际上是一个相对的 URL 地址。
如果您没有给文件关联一个路径,JSP 编译器默认在当前路径下寻找。
等价的 XML 语法:
1 | <jsp:directive.include file="文件相对 url 地址" /> |
JSP 动作元素
JSP 动作元素是一组 JSP 内置的标签,只需要书写很少的标记代码就能使用 JSP 提供的丰富功能。JSP 动作元素是对常用的 JSP 功能的抽象与封装,包括两种,自定义 JSP 动作元素与标准 JSP 动作元素。
与 JSP 指令元素不同的是,JSP 动作元素在请求处理阶段起作用。JSP 动作元素是用 XML 语法写成的。
利用 JSP 动作可以动态地插入文件、重用 JavaBean 组件、把用户重定向到另外的页面、为 Java 插件生成 HTML 代码。
动作元素只有一种语法,它符合 XML 标准:
1 | <jsp:action_name attribute="value" /> |
动作元素基本上都是预定义的函数,JSP 规范定义了一系列的标准动作,它用 JSP 作为前缀,可用的标准动作元素如下:
语法 | 描述 |
---|---|
jsp:include | 在页面被请求的时候引入一个文件。 |
jsp:useBean | 寻找或者实例化一个 JavaBean。 |
jsp:setProperty | 设置 JavaBean 的属性。 |
jsp:getProperty | 输出某个 JavaBean 的属性。 |
jsp:forward | 把请求转到一个新的页面。 |
jsp:plugin | 根据浏览器类型为 Java 插件生成 OBJECT 或 EMBED 标记。 |
jsp:element | 定义动态 XML 元素 |
jsp:attribute | 设置动态定义的 XML 元素属性。 |
jsp:body | 设置动态定义的 XML 元素内容。 |
jsp:text | 在 JSP 页面和文档中使用写入文本的模板 |
常见的属性
所有的动作要素都有两个属性:id 属性和 scope 属性。
- id 属性: id 属性是动作元素的唯一标识,可以在 JSP 页面中引用。动作元素创建的 id 值可以通过 PageContext 来调用。
- scope 属性: 该属性用于识别动作元素的生命周期。 id 属性和 scope 属性有直接关系,scope 属性定义了相关联 id 对象的寿命。 scope 属性有四个可能的值: (a) page, (b)request, (c)session, 和 (d) application。
include
<jsp:include>
用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面。
如果被包含的文件为 JSP 程序,则会先执行 JSP 程序,再将执行结果包含进来。
语法格式如下:
1 | <jsp:include page="相对 URL 地址" flush="true" /> |
前面已经介绍过 include 指令,它是在 JSP 文件被转换成 Servlet 的时候引入文件,而这里的 jsp:include 动作不同,插入文件的时间是在页面被请求的时候。
以下是 include 动作相关的属性列表。
属性 | 描述 |
---|---|
page | 包含在页面中的相对 URL 地址。 |
flush | 布尔属性,定义在包含资源前是否刷新缓存区。 |
示例:
以下我们定义了两个文件 date.jsp 和 main.jsp,代码如下所示:
date.jsp 文件代码:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
main.jsp 文件代码:
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
现在将以上两个文件放在服务器的根目录下,访问 main.jsp 文件。显示结果如下:
1 | include 动作实例 |
text
jsp:text动作元素允许在 JSP 页面和文档中使用写入文本的模板,语法格式如下:
1 | <jsp:text>模板数据</jsp:text> |
以上文本模板不能包含其他元素,只能只能包含文本和 EL 表达式(注:EL 表达式将在后续章节中介绍)。请注意,在 XML 文件中,您不能使用表达式如 ${whatever > 0},因为>符号是非法的。 你可以使用 ${whatever gt 0}表达式或者嵌入在一个 CDATA 部分的值。
1 | <jsp:text><![CDATA[<br>]]></jsp:text> |
如果你需要在 XHTML 中声明 DOCTYPE,必须使用到 <jsp:text>
动作元素,实例如下:
1 | <jsp:text><![CDATA[<!DOCTYPE html |
你可以对以上实例尝试使用jsp:text及不使用该动作元素执行结果的区别。
EL 表达式
EL 表达式是用${}
括起来的脚本,用来更方便地读取对象。EL 表达式写在 JSP 的 HTML 代码中,而不能写在<%
与%>
引起的 JSP 脚本中。
JSP 表达式语言(EL)使得访问存储在 JavaBean 中的数据变得非常简单。JSP EL 既可以用来创建算术表达式也可以用来创建逻辑表达式。在 JSP EL 表达式内可以使用整型数,浮点数,字符串,常量 true、false,还有 null。
JSTL
JSP 标准标签库(JSTL)是一个 JSP 标签集合,它封装了 JSP 应用的通用核心功能。
JSTL 支持通用的、结构化的任务,比如迭代,条件判断,XML 文档操作,国际化标签,SQL 标签。 除了这些,它还提供了一个框架来使用集成 JSTL 的自定义标签。
根据 JSTL 标签所提供的功能,可以将其分为 5 个类别。
- 核心标签
- 格式化标签
- SQL 标签
- XML 标签
- JSTL 函数