当前位置:文档之家› 第6章 JSP语法基础

第6章 JSP语法基础

第6章 JSP语法基础
第6章 JSP语法基础

第 6 章 JSP 语法基础

主要分为模板元素(Template Data)和 JSP 元素(Elements)两大部分。

在 JSP 网页文件中,

模板元素就是JSP 容器不做处理的部分;JSP 元素是必须经由 JSP 容器进行处理的部分,包 括指令元素、脚本元素、动作元素、EL 元素等四类。本章主要介绍基本的 JSP 语法以及常 用 JSP 元素的使用。

通过本章的学习,读者应掌握如下内容:

¨ JSP 页面元素的基本构成

¨ JSP 指令元素(Directive Elements)

¨ JSP 脚本元素(Scripting Elements)

¨ JSP 动作元素(Action Elements)

¨ 表达式语言EL(Expression Language)元素的概念

¨ JSP 和 Servlet 的关系

6.1 JSP页面元素的基本构成

Sun公司首先发展出 Servlet,其功能非常强大,体系设计也很完善。但是它输出HTML 标记时,必须使用 out.println()一句一句地输出。当网页内容非常复杂时,这无异于一场梦 魇。后来 Sun 公司推出了类似于 ASP 的嵌入型 Scripting Language,并命名为 Java Server Pages,简称为 JSP。JSP 大大减轻了Web 程序员的负担,提高了动态网页的开发效率。

本节主要介绍JSP页面元素的基本构成。

为了让读者对JSP页面能有个比较全面的了解,

后面几节详细讲述JSP 的语法知识,最后深入剖析JSP 和 Servlet 的关系。

6.1.1 Case:应用 Dreamweaver 创建页面开发环境

相信读者对于 Dreamweaver 站点的管理操作(新建、编辑、删除等)已经比较熟悉, 请自行创建一个本地站点 jspBook。为紧密结合已经创建的 Web 项目 jspBook 和 Tomcat 服 务器,这里特以Dreamweaver CS5 的“站点设置对象”对话框为例,说明如下几点需要特别 注意的地方。

(1)本地站点信息:在〖站点〗页将本地站点文件夹指向已建项目 jspBook的 WebRoot 目录,如图 6.1 所示;在〖高级设置 | 本地信息〗页中选择“区分大小写的链接检查”选项, 如图 6.2 所示。

·135·

·136

·

图6.1 指定本地站点jspBook

的“本地站点文件夹”选项

图6.2 指定本地站点jspBook 的“区分大小写的链接检查”选项

(2)服务器信息:在〖服务器〗页中,新建或编辑服务器对话框〖基本〗页中,连接 方法选择“本地/网络” ,服务器文件夹指向%Catalina_Home%\webapps\jspBook ,并指定 Web URL :http://localhost:8090/jspBook/,即与通过浏览器访问部署在 Tomcat 中的 Web 应用 jspBook 的 URL 相同, 如图 6.3 所示;〖高级〗 页中选择 “保存时自动将文件上传到服务器” , 测试服务器模型选择“JSP ” ,如图 6.4所示。

·137

·

6.3 “服务器·基本”选项 图6.4 “服务器·高级”选项

想一想 请读者独立思考,以上四点为什么这样设置?

6.1.2 Case :一个典型的 JSP 文件

在 Dreamweaver 本地站点 jspBook 中创建目录 ch06 及其子目录 pub

在目录 pub 中新建 head.jsp 和 copyright.html 两个页面(内容参照图 6.5) 。不过,请

将、、、

等标记删除,只保留需要显示的内容本身。

在目录 ch06 中新建JSP 文件 sample.jsp ,如清单 6.1 所示。 清单6.1 一个典型的JSP 文件sample.jsp

1: <%@ page contentType="text/html? charset=utf-8" language="java"

import="java.sql.*" errorPage="" %>

2: <%@ page info="一个典型的JSP 文件" %>

3:

"https://www.doczj.com/doc/1a6880772.html,/TR/xhtml1/DTD/xhtml1-transitional.dtd">

4:

5:

6: 7: 一个典型的JSP 文件

8:

9:

10:

11:

12: <%-- @author Wuerlang, 2008-6-26 10:18. --%>

13:

14:

15:

16:

17:

18:

19:

20: <%

21: /*通过循环输出10行“Hello World!”,且奇偶行的背景颜色不同*/

22: String s = "Hello World!"? //声明一个字符串变量

23: int i, count = 6? //声明两个整型变量

·138· 24:

String color1 = "#99ccff",color2 = "#88cc33"? 25:

for(i=1?i<=count?i++){ 26:

String color

= color2? //color 变量表示颜色,通过它来动态控制奇 偶行的颜色 27:

if(i%2==0)color = color1? 28:

out.println("

")? 29: } 30: %> 31:

下面循环输出 6 行“Hello World!”
" + s + "
32:

33:

<% /**下面是使用表达式的例子**/ %> 34:

<%="经过for 循环之后,count 的值为:"+count%>

35:

上面有一行隐藏注释,您“查看源文件”,不过看不到啦^_^

36:

37:

<%@ include file = "pub/copyright.html" %> 38:

39:

40:

保存这个文件,在浏览器中访问 http://localhost:8090/jspBook/ch06/sample.jsp ,结果如图

6.5 所示。对于这个JSP 文件,这里暂且不做任何说明。

小贴士 代码第 1、3~6行是 Dreamweaver CS5 自动生成的,第8~10行和第 39~40 行也是如此。 为节省篇幅, 本章以后所列的代码清单将忽略类似这样一些自动生成的代码 (但 行号保留),请读者特别留意。

图6.5 示例页面sample.jsp

页首Head.jsp 部分

页脚copyright.html 部分

6.1.3 模板元素(Template Data)和 JSP 元素(Elements)

JSP 网页元素主要分为模板元素(Template Data)和JSP 元素(Elements)两大部分。

模板元素是指JSP 的静态 HTML或者 XML内容, 即JSP 服务器不处理的部分, 服务器 会直接送到客户端执行。 这部分内容可以说是网页的框架, 它们影响页面的结构和美观程度, 主要是 Web 页面设计人员和美工的工作,对JSP 程序员来说,并不怎么关心。

在清单 6.1 中,除了“<%”和“%>”之间以及第 14 行代码之外的部分均属于模板元素。

在 JSP 文件的转译期,JSP 容器将把这些模板元素编译到 Servlet 里,表 6.1 列举了第 16、17 行的 HTML代码及其在 Servlet 里的对应代码(第 76、77 行) ;当进入请求期时,JSP 容器会把它们一字不变地发送到客户端。

表6.1 HTML代码及其在Servlet中的对应代码

HTML代码 Servlet中的对应代码

out.write("

\r\n")?

out.write(" \r\n")?

注:

标签前面的三个空格在Servlet的out.write()语句中也是原样输出的。

小贴士要查阅这个JSP 文件对应的 Servlet 代码,请查找下面的这个文件: %Catalina_HOME%\work\Catalina\localhost\jspBook\org\apache\jsp\ch06\sample_jsp.java。

JSP 元素(Elements)是必须经由 JSP 容器处理的部分,主要包括如下四种:

l指令元素:用来从整体上控制 Servlet 的结构;

l脚本元素: 用来嵌入Java 代码, 它们将成为JSP 页面转换得到的 Servlet 的一部分;

l动作元素:用来引入现有的组件或者控制JSP 引擎的行为;

l EL(Expression Language)元素:为简化开发中对于对象的引用和方便存取数据而 自定义的语言,是JSP 2.0 正式纳入的标准规范之一。

下面将用三节的篇幅分别详细介绍前三种类型的 JSP 元素;对于表达式语言(EL)和 标准标签库(JSTL),将在第 12 章《应用JSTL和 EL简化 JSP 开发》中将做较为详细的介 绍。

6.1.4 注释

JSP 页面中的注释可以分成三种:HTML/XML注释、JSP 专用注释和 Scriptlet 注释。

1. HTML/XML注释

这类注释原样发送到客户端,虽然用户浏览时看不到,但是可以通过“查看源文件”看 到这些代码。其语法格式为:

例如清单 6.1第 11 行所示:

在客户端的HTML源文件中可以看到完全一模一样的内容。

另外,这类注释中还可以嵌入一些动态的表达式,例如:

在客户端的HTML源文件中显示为:

·139·

2. JSP 专用注释

这类注释是JSP 程序员专用的注释,它写在JSP 程序中,但不发送给客户端,因而通常 称为隐藏注释。其语法格式为:

<%--comment--%>

或者:

<% /**comment**/ %>

例如清单 6.1第 12、33 行所示:

<%-- @author Wuerlang, 2008-6-26 10:18.--%>

<%

/**下面是使用表达式的例子**/ %>

第 33 行实质上使用的是Java 形式的一种首尾封闭的注释形式。

小贴士

用隐藏注释标记的字符会在JSP 编译时被忽略。 JSP 容器不会对它们中间

的语句进行编译,当然,也谈不上执行,更不会显示在客户端浏览器中。

注意在<%--和--%>之间,可以任意书写注释语句,但注释不能包含“--%>” 。

3. Scriptlet 注释

由于 Scriptlet 包含的是 Java 代码,所以 Java 中的注释规则在 Scriptlet 中同样适用。在 JSP 中,常用的Java 注释语句有表示单行注释的“//”和表示多行注释的“/* */” 。

例如清单 6.1第 21、

23 行所示:

/*通过循环输出 10 行“Hello World!” ,且奇偶行的背景颜色不同*/

//声明两个整型变量

小贴士使用隐藏注释和 Scriptlet 注释是 JSP 程序实用的方法,也是 Java 程序员 通常使用的方法。

6.1.5 Case:转义字符——Quoting和 Escape 规则

Quoting 主要是为了避免与语法产生混淆所使用的转换功能。为了能深刻理解这一点, 先来看例程Quoting-1.jsp及其执行结果。例程 Quoting-1.jsp的程序代码如清单 6.2所示。

清单6.2 转义字符示例Quoting-1.jsp

6: Quoting例程-1

10:

Quoting例程-1

11: <%

12: out.println("在HTML标记中,对于属性的值可以使用定界符双引号""、单引号 '',或者干脆都不用。")?

13: out.println("
JSP以<%作为起始标记,以%>作为结束标记。")?

14: %>

例程 Quoting-1.jsp的执行结果如图 6.6 所示。

·140·

·141

·

图6.6 例程Quoting-1.jsp 的执行结果

为什么会出现这样的结果呢?我们在 Word 、记事本中一直是直接输入双引号""、单引 号''的呀!

这是因为双引号""、单引号''以及<%、%>、\等符号是 JSP 语法规定使用的字符或字符 串,当程序执行到""时,JSP 容器就直接提示程序有错误,如图 6.3 所示。通常,为了避免 产生这样的结果,当需要在浏览器中显示这些符号时,需要做如下适当修改:

l 起始标签(<%)改为:<?%

l 结束标签(%>)改为:%\> 或 %>?,推荐使用%>?

l 双引号(")改为:\"

l 单引号(')改为:\'

l 反斜杠(\)改为:\\ l

尖括号(< 和 >)改为:<?和>?

练一练 请读者将 Quoting-1.jsp 另存为 Quoting-2.jsp ,并独立完成修改工作。

6.1.6 简单认识 JSP 中的 XML

XML 是 eXtensible Markup Language 的缩写,意为可扩展的标记语言。第1 章 1.4节简 要介绍了XML 数据文档的基本结构,并给出了省份城市和高校的 XML 数据片段,1.5 节应 用 JavaScript 操纵这些 XML 数据构造了一个级联菜单。这些都是 XML 在 HTML 中的简单 应用。此外,在JSP 中还广泛使用 XML ,JSP 各个元素普遍都有等价的XML 语法格式,或 直接是 XML 的语法格式。

Java 5.0 自带所有和 XML 协同工作的基本 API ,包括javax.xml 标准扩展包,该包处理 用于 XML 的简单 API (Simple API for XML,SAX ) 和文档对象模型 (Document Object Model ,

·142·

DOM )以及扩展的风格表单语言(eXtensible Stylesheet Language ,XSL )转换。

JSP 的发展无疑将越来越强调XML 的语法格式, 读者可以从JSP 1.2及最新的JSP 2.0/2.1 语法规范中发现这一变化趋势。

为什么要使用 XML 相容的语法格式呢?主要是基于以下几个方面:

l 使用 XML 相容语法来构架 JSP ,当然不是因为 XML 是一个时髦的事物,而是作

为 XML 文档的 JSP 将会得到许多的好处。例如,一个标准的 XML 相容的 JSP 语 法将有助于JSP 的开发。

l JSP 文件的XML 语法使得JSP 文件的内容很容易被组织和管理。

l 可以使用XML 的开发和分析工具来开发和分析JSP , 仅仅需要更换 DTD 文件就可

以升级到最新版本的JSP 。

l XML 格式统一的语法更容易学习和使用。

关于 Web 中的XML 编程,本书第 11 章《利用JSP 技术进行 XML 编程》将重点介绍。

小贴士 关于 XML 的相关知识,读者可以到 https://www.doczj.com/doc/1a6880772.html,/TR/xml-infoset/查 阅详细资料;关于 javax.xml 包的详细信息,请访问:https://www.doczj.com/doc/1a6880772.html,/j2se/1.5.0/docs/api/。

6.2 JSP 指令元素(Directive Elements )

JSP 指令(Directive )是为 JSP 引擎而设计的,用于从JSP 发送一个信息到JSP 容器上。 JSP 指令主要用来提供整个JSP 网页相关的信息,设定 JSP 网页的相关属性,如:网页的编 码方式、语法、信息等。它们并不直接产生任何可见输出,而只是告诉引擎如何处理其余的 JSP 页面。 所有的指令都在JSP 整个文件范围内有效。 指令元素为翻译阶段提供了全局信息。 其语法格式为:

<%@ directiveName attribute="value"[ attribute2="value2" …]%>

JSP 指令元素有三个:page (页面)指令、include

(包含)指令和 taglib (标签)指令。 下面逐一介绍这三种指令元素。 小贴士 JSP 指令始终被括在“<%@”和“%>”标记中。顺便提示,这些标记符 号本身的字符之间,不要有任何空格。

6.2.1 page 指令 回顾例程 sample.jsp (参见清单 6.1)的前两行:

<%@ page contentType="text/html? charset=utf-8" language="java" import="java.sql.*" errorPage="" %>

<%@ page info="一个典型的 JSP 文件" %>

这就是出镜率颇高且通常在 JSP 页面顶部露脸的 page 指令。几乎在所有 JSP 页面顶部 都会看到它的身影,尽管它不是必须的。

page 指令的主要功能是设定整个JSP 网页的属性和相关功能。其语法格式如下:

<%@page attribute="value" attribute2="value2" … %> 如同所有的JSP 标签元素一样, page 指令也支持以XML 为基础的语法格式, 如下所示:

page 指令有 13 个属性,基本含义见表 6.2。

表6.2 JSP 页面指令的属性

·143· 属

描述 示 例 language

定义所使用的脚本语言,目前别无选择,只能使用Java language="java" import 主要定义该网页使用哪些Java API ,用“, ”隔开包或者类列 表 import="java.util.*"

import="java.sql.*, java.util.*"

extends 主要定义该网页产生的Servlet 是继承哪个父类。使用该属性

应当十分小心,因为服务器可能已经在用自定义的父类

session 指定一个Http 会话中本网页是否参与,默认值true session="true" buffer 指定JSP 到客户端输出流的缓存大小。 默认值和服务器有关, 但至少应该是8 KB ;none 表示不缓冲

buffer ="32KB"

autoFlush

默认值true 表明如果缓存已满则刷新它;false 值表示如果缓 存已满则抛出异常,很少使用。如果buffer="none",autoflush

不能取false 值。 autoflush="true"

isThreadSafe 用来设置 JSP 文件是否能多线程使用。默认值 true 表示该网 页能够同时处理多个用户的请求;取值false 表示一个JSP 一

次处理一个请求

isThreadSafe="true"

info

定义一个可以通过getServletInfo 方法提取的字符串 info="一个典型的JSP 文件" errorPage 指定一个 JSP 页面,所有未被当前页面捕获的异常均由该页 面处理

errorPage="error.jsp"

contentType 指定输出的MIME 类型。默认是text/html contentType="text/html?

charset=gb2312"

isErrorPage 指示当前页面是否可以作为另一 JSP 页面的错误处理页面。 默认值false

isErrorPage="false"

pageEncoding

JSP 页面的字符编码 pageEncoding="gb2312" isELIgnored 制定表达式语言EL 是否被忽略,如果为true ,则JSP 容器忽 略“${}”表达式的计算。默认值由web.xml 描述文件的版本

确定,Servlet 2.3以前的版本将忽略

isELIgnored="true"

小贴士

①这些页面指令可以单独使用,也可以同时使用几个。

②在同一个JSP 文件中,import 是唯一允许出现一次以上的属性。

关于 page 指令及 errorPage 、isErrorPage 属性的一个简单例子,请读者参阅第 7 章 7.7 节《exception 对象》。

6.2.2 include 指令

回顾清单 6.1 sample.jsp 第 37 行:

<%@ include file = "pub/copyright.html" %>

这就是一个典型的 include 指令。它通知 JSP 容器将指定位置(如 pub 目录)中的资源 (如 copyright.html 文件)内容内嵌到当前页面。其语法格式如下:

<%@ include file="relativeURL"%>

对应的 XML 相容的语法格式为:

include指令只有 file一个属性。被包含文件的路径名一般来说是指相对路径,不需要什 么端口、协议或域名,如果这个路径以“/”开头,那么这个路径主要是参照 JSP 应用的上 下关系路径;如果路径是以文件名或目录名开头,那么这个路径就是正在使用的JSP 文件的 当前路径。

include指令是静态包含其他文件, 被包含的文件可以是 html 文件、 jsp文件、 文本文件、 inc文件,或者只是一段Java 代码。如果被包含的文件中含有可执行代码,那么这个被包含 的文件中代码将会被执行。一旦被包含文件被执行,那么主JSP 文件的过程将会被恢复,继 续执行下一行。如果这个包含文件被改变,包含此文件的主JSP 文件将被重新编译。被包含 的文件或其执行的结果将会插入到主JSP 文件中 include指令相应的地方。

注意

①包含文件中不能使用、、、等标记,因为这将会影响在 原 JSP 文件中同样的标记,有时会导致错误。

②include 指令是静态包含其他文件。何谓静态包含?首先,参数 file 不能是一个变量 URL, 也不可以在 file所指定的文件名后接任何参数; 其次, 被包含的文件将会被插入到JSP 文件中去。

6.2.3 taglib 指令

taglib 指令是 JSP 1.1 增加的功能,它允许设计者自定义一个标签库及标签的前缀。设计 者首先要开发标签库,为标签库编写.tld配置文件,然后在JSP 页面中使用自定义标签。

在 JSP 规范中, 标签库得到了不断加强。 JSP 2.0 规范中增加了JSP 标准标签库 (JSTL)。

taglib 指令的语法格式如下:

<%@ taglib uri="tagLibraryURI" prefix="tagPrefix" %>

以 XML为基础的语法格式为:

其中, 属性 uri 用来表示标签描述符, 即告诉JSP 容器怎么找到标签描述文件合标签库; 属性 prefix 定义了在 JSP 页面里要引用这个标签时的前缀,但不能使用用 jsp、jspx、java、 javax、servlet、sun、sunw等作为前缀。

对于自定义标签库及标准标签库(JSTL),在第 12 章《应用JSTL和 EL简化 JSP 开发》 中将做进一步的简要介绍。

6.3 JSP脚本元素(Scripting Elements)

JSP脚本元素用来插入Java代码, 这些Java代码将出现在由当前JSP页面生成的Servlet 中。JSP 脚本元素主要包括如下三种:

l表达式(Expression) :计算表达式并输出其结果。

l脚本片段(Scriptlet) :把代码插入到 Servlet 的 service方法。

l声明(Declaration) :把声明加入到 Servlet 类(在任何方法之外)。

下面依次详细介绍这三种脚本元素。

6.3.1 表达式(Expression)

表达式在JSP 请求处理阶段计算它的值,执行之后会被自动转化为字符串,然后显示出

·144·

·145· 来。其语法格式如下:

<%= expression %> 等价的 XML 表达式如下:

expression

例如如示例 sample.jsp (清单 6.1)的第34 行:

<%="经过 for 循环之后,count 的值为:"+count %>

表达式的运算规则就是Java 表达式,其结果必须是一个字符串或者可以转换成字符串。 在编译成 Servlet 后,表达式实际上被转换成 out.print()方法中的内容。如上例在 Servlet 中变 成:

out.print("经过 for 循环之后,count 的值为:"+count )?

关于 out

对象及其功能和应用,将在第 7章 7.3 节详细介绍。 小贴士 上述 Servlet 代码参见下述文件的第 95 行:

%Catalina_HOME%\work\Catalina\localhost\jspBook\org\apache\jsp\ch06\sample_jsp.java 。 因而,可以在一行文本中插入表达式。通过使用表达式,可以使程序变的简洁。 注意

①JSP 表达式只能单独出现,即不能在<%=…%>中间出现多个表达式。

②使用表达式时,在<%=中间不能有任何的空格。例如:< %="abc"%>将原样输出, 而<% ="abc"%>将引发异常。

③不能用一个分号(;)作为表达式的结束符。因为表达式本身是一个式子,而非 Java 语句。

④JSP 表达式的<%=…%>和 expression 只能定义在一行上,而且表达式 expression 必须 能转换成字符串形式。需要的话,可以使用 toString()进行转换。

6.3.2 脚本片段(Scriptlet )

Scriptlet 元素即脚本片段,或称为代码片段,是一段在 Web 服务器响应请求时就会执行 的 Java 代码。这些代码片段,只要合乎Java 本身的标准语法即可。其语法格式为:

<%Java code fragment %>

等价的 XML

语法格式如下:

Java code fragment

一个 Scriptlet 能够包含多条 jsp 语句(并不局限于一行源代码)、方法、变量、表达式, 以及使用任何隐含的对象和任何用声明过的对象。当JSP 收到客户的请求时, Scriptlet 就会被执行,如果 Scriptlet 有显示的内容,这些显示的内容就被保存在 out 对象中。

JSP 脚本元素是 JSP 代码中使用最频繁的元素,特别是 Scriptlet ,在早期的 JSP 代码中 它占有主导地位。

注意

①编写 Scriptlet 时,任何文本、HTML 标记、JSP 元素都必须在 Scriptlet 之外。

②需要特别提醒读者的是,不能在 Scriptlet 中定义方法。

在脚本片段周围可能是原始的HTML 或 XML 语句, 在这些地方, 代码片段可以创建多

·146·

条件执行代码,或要用到另外一段代码。例如,清单 6.3 所示的例程 Scriptlets.jsp 使用表达 式和代码片段,显示 h1、h2、h3 和 h4 格式的的字符串“Hello world!” 。 清单6.3 Scriptlets 应用举例Scriptlets.jsp

6: 页面访问次数</p><p>

10: <% int counter = 4? %>

11: 使用输出循环标题1-标题4格式的字符串“Hello world!” :

12: <% /**

13: 在后一段的Scriptlet 中还要使用前一段Scriptlet 中定义的一个变量 14: */%>

15: <% for (int i=1? i<=counter? i++) { %>

16: >Hello world!>

17: <% } %>

例程 Scriptlets.jsp 的执行结果如图 6.7 所示。

图6.7 例程Scriptlets.jsp 的执行结果

想一想 既然在 Scriptlet 中不能定义方法,那么,方法定义在什么地方呢?

6.3.3 声明(Declaration )

在 JSP 程序中,声明(Declaration )是一段 Java 代码,它用来定义在JSP 程序中用到的 变量和方法。声明可以定义页面级变量以保存信息,或者定义JSP 页面的其余部分可能需要 的支持方法。如果你发现代码太多,通常最好把它们写成一个独立的 Java 类别。声明和 Scriptlet 非常类似,只不过它以“<%!”开头,其格式如下:

<%! V ariable declaration [, declaration? …] %>

或:

<%! Method declaration(paramType param, … ) %>

等价的 XML 表达式如下:

declaration

·147·

例如:

<%! int a, b, c?

%>

<%! int i = 0? Sting s="Hello world!"? %>

<%! Circle a = new Circle(2.0)? %>

说明

声明方法或变量时,请注意以下的一些规则:

①可以一次性声明多个变量和方法,但一定要以分号(;)结束变量声明,因为任何内 容都必须是有效的Java 语句。

②可以直接使用在<%@ page %>中被包含进来的已经声明的变量和方法,无需对其 重新声明。

③一个声明仅在一个页面中有效。如果想在每个页面都用到一些声明,最好把它们写成 一个单独的文件,然后用<%@ include %>或元素把它们包含进来。

6.3.4 Case :脚本元素和页面指令综合实例

由于声明不会有任何输出,因此它们往往和JSP 表达式或 Scriptlet 结合在一起使用。例 如,清单 6.4 所示的例程 accessCount.jsp 输出自从服务器启动(或 Servlet 类被改动并重新装 载以来)当前页面被请求的次数,并输出当前日期和时间。 清单6.4 JSP 脚本元素综合应用accessCount.jsp

6: 页面访问次数

10: <%! private int accessCount = 0? %>

11: 自从服务器启动以来页面访问次数为:

12: <%= ++accessCount /** 使用表达式输出页面访问次数 **/ %>

13:
现在是:

14: <%@ page import = "java.util.Date, java.text.DateFormat" %> 15: <% //输出当前日期和时间

16: Date date = new Date()?

17: DateFormat mediumFormat =

DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM)? 18: out.println(mediumFormat.format(date))?

19: %>

这里需要着重说明的是:使用<%! …%>方式声明的变量为页面级的全局变量,即:如 果同时有多个用户浏览此 JSP 页面,他们将会共享此变量,如清单 6.4 中声明的整型变量 accessCount ,图 6.8 模拟了两个用户同时浏览此页面的状况,当再次刷新后端浏览窗口时, 该窗口显示的访问次数值将是38,如图 6.9 所示。因此,笔者强烈建议:请慎重使用<%! … %>声明变量,通常不要使用该方式。若要使用声明变量,一般直接在<%… %>中声明使用 即可。

试一试 请将第 10 行中的“! private ”删除,对比查看“声明”的功能。

·

148·

图6.8 两个用户同时浏览

accessCount.jsp 页面

图6.9 再次刷新后端的浏览器窗口

注意 因为在JSP 容器中, JSP 会在运行前被转换成Servlet 。 而对于每一个Servlet , 在运行的时候通常只会产生一个实例,如果此时多个客户同时访问某个 Servlet 的全局变量 (实例变量),可能会引发多线程问题。因而,在 JSP 中声明变量或方法的时候,要特别注 意同步问题。

6.4 JSP 动作元素(Action Elements )

JSP 动作元素(Action Elements )是使用 XML 语法写成的,它是在请求处理阶段起作 用的,它影响JSP 运行时的行为和发送给客户的应答。其语法格式为:

或者

……

JSP 规范定义了一系列的标准动作,它用 jsp 作为前缀。这些标准动作由所有的 JSP 容 器提供,而不管它们是如何实现的。从效果上来说,一个标准动作是能够嵌入到JSP 页面之 中的一个标记。在页面被编译成 Servlet 期间,当容器遇到这个标记时,就用相应于请求的 预定义的任务的Java 代码代替它。

目前,JSP 2.0 规范中,主要有 20项标准动作,可以简单地将它们分为 5类:

l用来存取 JavaBean 的 3 个动作元素:

l JSP 1.2 规范的 6 个动作元素:

l主要用于 JSP 文档中的 6 个动作元素:,其中,是 JSP 2.0 新增

的元素。

l主要用来动态产生XML元素标签的值的3个动作元素: ,这三个都是JSP 2.0 新增的元素。

l主要用在 Tag File中 2 个动作元素:

关于JavaBean的 3 个动作元素将在第 9 章《利用 JavaBean增强 JSP》中做详细介绍; 关于 Tag File的 2 个动作元素将在第 12 章 《应用JSTL和 EL简化 JSP 开发》 中做简要介绍; 下面重点讲解第 2 类中几个使用频繁的动作元素,其他的就暂且不再介绍了。

6.4.1 标签

标签和等标签一起使用,以 key/value的形式为它们提供附加信息。其语法格式如下:

其中,name是属性相关联的关键字,value是属性的值,可以是request-time value。

例如:

注意:当一起使用时,被包含的网页或转向 后的网页会先看看 request 对象中除了原来的参数值之外,还有没有再增加的参数值。如果 有新增加参数值,则新的参数值再执行时,有较高的优先权。例如:

一个 request 对象有一个参数DBPassword=12345;另一个参数DBPassword= ssdlh是在 转向时所传递的参数,则网页中的 request 应该为 DBPassword=JSP。

标签只能用在内部,它没有属性(attribute)。

6.4.2 标签

1. include动作概述

回顾清单 6.1 sample.jsp第 14 行:

这就是一个简单的 include 动作。标签表示包含一个静态的或者动态的文 件。其语法格式如下:

或者:

·149·

……

其中:

①page="fileName "为相对路径,或者是代表相对路径的表达式。如果路径以“/”开头, 那么这个路径主要是参照JSP 应用的上下文关系路径;如果路径是以文件名或目录名开头, 那么这个路径就是正在使用的JSP 文件的当前路径。

②flush="true",在 JSP1.2 之前,必须使用 flush为 true,它默认值是 false。如果为 true, 当缓冲区满时,将会被清空。

子句能让你传递一个或多个参数给动态文件,也可在一个页面中使用多

来传递多个参数给动态文件。而 include指令(<%@ include …%>)只有

file

一个属性,无法直接向被包含文件传递参数。

说明

可以包含一个静态文件或者动态文件,但结果是不尽相同的。如果包含 进来的只是静态文件, 那么只是把静态文件的内容加到 JSP 网页中; 如果包含的是动态文件, 那么这个被包含的文件也会被JSP 容器编译执行。

②从名称上不能直接判断一个文件是动态的还是静态的。例如,header.jsp 可能只是单 纯的包含一些信息而已,而不需要执行。能自动判断此文件是动态的还是静态 的。

③被包含的对象只有对 JspWriter 对象的访问权,并且它不能设置头或者 Cookie。如果 页面输出是缓冲的,则缓冲区的刷新要优先于包含的刷新。

④与 include指令(<%@ include …%>)不同的是,是动态包含,即在页 面真正被加载的时候才把指定的文件加进来,如果被包含的页面代码更改,在 包含页面的结果中会随之更新,即被包含的内容在 include 动作执行时才确定;而<%@ include…%>是静态编译,即包含的内容一经编译,就不能改变。

的运行效率比<%@ include…%>的运行效率低,但可以动态增加内容。 如果被包含的文件经常改变,那么建议读者使用

2. Case:include动作和 include指令的区别

下面举一个综合的例子,说明和<%@ include …%>

的应用以及它们的不

同,并深刻理解什么是静态包含什么是动态包含。

创建被包含文件 include-1.jsp,其代码如清单 6.5 所示。

清单6.5 被包含文件

include-1.jsp

1: <%!

2: String var1="China"?

3: %>

创建被包含文件 include-2.jsp,如清单 6.6 所示。

清单6.6 被包含文件

include-2.jsp

1: <%!

2: String var2="America"?

3: String var3="England"?

4: %>

小贴士上述文件 include-1.jsp 和 include-2.jsp 中的变量不要重复声明,因为它们 可能被同时包含进同一个文件。否则,将引发异常。

·150·

·

151·

创建文件 include-3A.jsp ,其代码如清单 6.7 所示。 清单6.7 包含文件

include-3A.jsp

1:

<%@ page language="java"%> 2: <% 3:

int j=1? 4:

if (j==1){ 5:

%>

6:

<%@ include file="include-1.jsp"%> 7:

<% 8:

}else{ 9:

%> 10:

<%@ include file="include-2.jsp"%> 11:

<%}%> 12: <%="
var1 = " + var1%><%="
var2 = " + var2%>

想一想 执行 include-3A.jsp 会出现什么结果?请选择:

a. 编译错误

b. 显示 var1 = China var2 = America

很多人理所当然的觉得肯定是a ,因为 j= =1,条件为“真” ,所以只包含 include-1.jsp , include-2.jsp 不会包含进来,但答案是 b 。include-3A.jsp 的执行结果如图 6.10 所示。

图6.10 include-3A.jsp 的执行结果

为什么会这样呢?因为<%@ include …%>要先于主JSP 文件的其他代码执行,所以两 个文件都会被包含进来!

(4)创建文件 include-3B.jsp ,如清单 6.8 所示。

清单6.8 包含文件include-3B.jsp

1:

<%@ page language="java"%> 2:

<% 3:

int j=1? 4:

String includeFile=""? 5:

if (j==1){ 6:

includeFile = "include-1.jsp"? 7:

}else{ 8:

includeFile = "include-2.jsp"? 9:

} 10:

%> 11:

·152·

12: <%="
var1 = " + var1%> 想一想 执行 include-3B.jsp 会出现什么结果?请选择:

a. 编译错误

b. 显示

var1 = China

选 b 吗?不,是 a. 编译错误!提示 var1 未定义。如图 6.11 所示。

图6.11 include-3B.jsp 的执行结果

为什么呢?因为是动态包含,相当于把包含文件与被包含文件分开编译。 小贴士 include 动作和 include 指令的根本区别在于:

①JSP 页面是把 include 指令元素(<%@ include file="" %>)所指定的页面的实际内容 (也就是代码段)加入到引入它的 JSP 页面中,合成一个文件后被 JSP 容器转化成一个 Servlet ,这只产生一个临时 class 文件和一个 servlet 源文件。

②动作元素()是在请求处理阶段引入的,会被JSP 容器生成两 个临时 class 文件和两个 Servlet 原文件。而引入的只是 Servlet 的输出结果,即 JspWriter 对 象的输出结果,而不是JSP 的源代码。

看一看 include 动作可以使用子元素向被包含的文件传递参数,请查 看本书综合实例“以物易物网”页眉文件 header.jsp 的调用情况。本章 6.7节将演示该示例。

6.4.3 标签

1. forward 动作概述

标签表示将客户端发送来的请求,转发到一个JSP 、Servlet 或者一个静态 html 文件。 请求被转向的资源必须位于与JSP 发送请求相同的上下文环境之中。 所谓上下文, 专业术语即 Context ,一言以蔽之,a Context 就是一个 Web 应用程序。该动作将立即执行, 它后面的代码不会执行。其语法格式如下:

或者:

·153·

……

说明

①page="relativeURL|<%=expression%>"表示 page 的值为一个字符串, 或者一个表达式, 它用于说明将要定向的文件或 URL 。这个文件通常示一个 JSP 文件、脚本片段 Scriptlets , 或者其他能够处理request 对象的文件,如一个 Servlet 。

中,name 、value 为指定参数名及相应的参数值。参数被发送到一个动态 文件,参数可以是一个或多个值,而这个文件却必须是动态文件。要传递多个参数,则可以 在一个JSP 文件中使用多个将多个参数发送到一个动态文件中。

例如:

2. Case :forward

动作应用实例

现在举一个例子,说明的具体应用。

创建文件 forward1st.jsp ,其代码如清单 6.9 所示。 清单6.9 例程forward1st.jsp

6: jsp: forward 应用举例-1

9:

<%out.println("这是forward 动作之前的一句话,在浏览器中能看到吗?")?%> 10:

·154· 器只是执行了对 forward1st.jsp 的请求, forward1st.jsp 到 forward2nd.jsp 的部分是在服务器内 执行的,浏览器并不知道服务器里到底发生了什么,它只知道自己获得的响应是 forward1st.jsp 发回来的,甚至不知道服务器还有个 forward2nd.jsp )

②例程 forward1st.jsp 中的第 9 行和第 12 行正常执行了吗? (没有看到 out 的输出结果! 但第 9、12行代码到底执行没有?第 7章 7.8 节还将深入讨论这个问题。 )

现在还有个新的问题: 如果在 forward1st.jsp 和 forward2nd.jsp 这两个页面之间需要传递 参数怎么办呢?可以使用标签,借助定义几个变量,然后在跳转的 新页面中使用 JSP 的内置对象 request 的 getParameter()方法读取这几个变量。关于 request 对象,将在第 7 章 7.3 节详细介绍。

使用 forward 动作,除了可以转向到普通的 URL (如:一个JSP 或 Servlet )外,它还有 一个特殊的功能:可以转向到WEB-INF 目录下的资源。例如,可以将一个JSP 文件(或者 其他资源)放到WEB-INF 目录下,则该文件无法通过浏览器直接访问。但是,通过 forward 动作,可以转向到 WEB-INF 中的这个 JSP 文件。这样,可以将一些需要保护的资源放在 WEB-INF 目录下,这些资源只有在JSP 中使用 forward 才能访问到。

6.5 JSP 和 Servlet 的关系

JSP 的发展基于Servlet 技术, 它简化了Servlet 的开发, 但JSP 本质上就是Servlet 。

Servlet 拙于页面显示,却善于业务逻辑操作和数据运算。在MVC (Model-View-Controller )开发模 式中,二者扮演着不同的重要角色。

6.5.1 Servlet/JSP 的发展和特点

1997 年 6 月,Sun 公司推出了 Servlet 1.0 规范;1998年 4 月又推出JSP 0.90 规范,年 底发布了 EJB 1.0 标准。从JSP 0.9 公开问世到最新的 JSP 2.1 规范,JSP 技术的发展可谓日 新月异。其中,最具里程碑的是 J2EE 1.4 正式发布以后,Servlet 从 2.3 更新到 2.4,JSP 从 1.2

更新到了2.0;针对J2SE 5.0,2005年 9 月,升级到 Servlet 2.5/JSP 2.1;2007 年 6 月, Sun 向 JCP (Java Community Process )提交了 Servlet 3.0 规范——JSR 315 (Java Specification Request )。

简言之,Sun 公司首先推出了 Servlet ,又推出了 JSP 。之后,将二者并行推进,齐头发 展。

6.5.2 JSP 和 Servlet 关系剖析

想一想 回顾第 2章 2.1 节中的“JSP 技术原理”部分,思考一下JSP 的工作原理。

1. JSP 本质上就是 Servlet

Sun 公司首先推出了 Servlet ,其功能非常强大,体系设计也很完善。但 Servlet 也不是 没有缺点, 和传统的 CGI 等方式相同, Servlet 是利用输出 HTML 语句来实现动态网页的 (看 看清单 6-2 吧)。特别是在 Microsoft 公司的 ASP 技术出现之后,Servlet 的这个特点显得非 常笨拙,对于复杂布局或者显示页面更是如此。如果用 Java Servlet 来开发整个网站,动态 部分和静态页面的整合过程简直就是一场噩梦。为此,Sun 在 Servlet 技术之上推出了 JSP (JavaServer Pages )。

JSP 正式发布于 1999 年 6 月,比 Servlet 的推出晚了两年还多。JSP 在执行时,也是先

相关主题
文本预览