• 沒有找到結果。

JSP 2.0技术手册

N/A
N/A
Protected

Academic year: 2022

Share "JSP 2.0技术手册"

Copied!
197
0
0

加載中.... (立即查看全文)

全文

(1)

JSP 2.0 技术手册

作者:林上杰、林康司 出版:电子工业出版社

内容简介:

本书图文并茂,以丰富的实例为引导,全面介绍了主流的 Java Web 开发技术——

JSP 2.0,重点介绍 Java 在展示层的两项重要技术:Java Servlet 与 JavaServer Pages。

它们是最重要的 Java 核心技术。对这两项技术的深入了解,将有助于您未来对于 JavaServer Faces(JSF)技术以及 Java Web Services 技术的学习。

注:

本内容仅供学习研究参考,为尊重作者劳动成果及版权,请购买原版

书籍。

(2)

第一章 安装执行环境

1-1 安装 J2SDK 1.4.2

第一步:执行 j2sdk-1_4_2_03-windows-i586-p.exe(见图 1-2);

图 1-2 执行 j2sdk-1_4_2_03-windows-i586-p.exe

先按【Next】,选择【I accept the terms in the license agreement】后,再按 【Next】。

第二步:选择安装路径及安装内容(见图 1-3);

图 1-3 选择安装路径及安装内容

(3)

一般来说,我们通常都默认安装在 C:\j2sdk1.4.2_03 的目录下,假若你要安装在其他路径时,

请按【Change】,改变 J2SDK 安装路径。确认无误后,再按【Next】。

随后开始安装 Java Plug-in 至浏览器上,一般都选择【Microsoft Internet Explorer】。再按 下【Install】,正式开始执行安装程序,假若安装成功后,你会看到如图 1-4。

图 1-4 成功安装 J2SDK 1.4.2_03

第三步:设定 J2SDK 1.4.2_03(见图 1-5);

从【开始】→【设置】→【控制面板】→【系统】→【高级】→【环境变量】→【系统变量】,

然后到【新建】。

JAVA_HOME = C:\j2sdk1.4.2_03 PATH = %JAVA_HOME%\bin

CLASSPATH = C:\j2sdk1.4.2_03\lib\tools.jar;C:\j2sdk1.4.2_03\

lib\dt.jar;

注意

1. CLASSPATH 的设定中,分号(;)用来分开两路径,切勿任意空格;

2. CLASSPATH 的设定中,分号的最后还有一个点“.”。

(4)

图 1-5 设定 J2SDK 之 CLASSPATH 补充

不论 Windows 2000 或 Windows XP 皆可依上述方法设定。

第四步:测试 J2SDK。

撰写一个 HelloWorld.java 程序,放置在 C:\HelloWorld.java 中。

HelloWorld.java

public class HelloWorld {

public static void main(String[] args) {

System.out.println("Hello World");

}

}

(5)

打开命令提示符,在 C:\ 下输入 javac HelloWorld.java,然后再输入 java HelloWorld,执行 HelloWorld 程序,假若顺利成功,则会显示“Hello World”,如图 1-6 所示。

图 1-6 编译且执行 HelloWorld 程序 成功安装 J2SDK 1.4.2_03 之后,紧接下来安装 Tomcat 5.0.16。

1-2 安装 Tomcat 5.0.16

Tomcat 目前版本为 5.0.16,它是由 JavaSoft 和 Apache 开发团队共同提出合作计划( Apache Jakarta Project )下的产品。Tomcat 能支持 Servlet 2.4 和 JSP 2.0 并且是免费使用。

Tomcat 5.0.16 可以从 http://jakarta.apache.org/tomcat/index.html 网站自行免费下载,或 者可以直接使用本书 CD 光盘中的 Tomcat 5.0.16,软件名称为:jakarta-tomcat-5.0.16.exe。

第一步:执行 jakarta-tomcat-5.0.16.exe(见图 1-7);

先按【Next】,选择【I Agree】后,再按【Next】。

第二步:选择安装路径及安装内容(见图 1-8);

通常我们会选择完全安装(Full),即如图 1-8。在图 1-9【Tomcat】的选项中,主要有:Core、Service、

Source Code 和 Documentation,假若选择安装 Service 时,尔后我们可以利用 Windows 的服务(控制 面板 |管理工具 |服务)来设定重新开机启动时,Tomcat 能够自动启动。

(6)

图 1-7 执行 jakarta-tomcat-5.0.16.exe

图 1-8 选择安装内容

(7)

图 1-9 选择安装 Service

选择完全安装后,按【Next】。开始选择安装路径,如图 1-10 所示。

图 1-10 选择安装路径

第三步:设定 Tomcat Port 和 Administrator Login(见图 1-11);

(8)

图 1-11 设定 Tomcat Port 和 Administrator Login 第四步:设定 Tomcat 使用的 JVM(见图 1-12);

图 1-12 选择 Tomcat 使用的 JVM

确认无误后,按下【Install】,正式开始执行安装程序。安装成功后,会看到如图 1-13 的结果。

假若你勾选了【Run Apache Tomcat】,按下【Finish】之后,会直接启动 Tomcat 5.0.16,然后 在你计算机的右下角,会出现绿色箭头的符号,如图 1-14。

(9)

图 1-13 成功安装 Tomcat 5.0.16

图 1-14 Tomcat 图标

第五步:测试 Tomcat。

打开浏览器,如 IE,输入 http://localhost:8080,假若 Tomcat 安装成功,则会看到如图 1-15 的 情形。

图 1-15 连接 http://localhost:8080/,测试 Tomcat 5.0.16

本书“第十二章:JSP 执行环境与开发工具”,对于 Tomcat 的使用及设定有更详细的介绍。

(10)

1-3 安装 JSPBook 站台范例

读者可以在 CD 光盘中找到本书的范例,程序文件名为 JSPBook.war。

第一步:安装 JSPBook.war;

安装的方法很简单,只要将 JSPBook.war 移至{Tomcat_Install}\webapps\目录下(例如:

C:\Program Files\Apache Software Foundation\Tomcat 5.0\webapps\JSPBook.war) , 然 后 JSPBook.war 会自动被 Tomcat 解压缩成 JSPBook 的目录,如图 1-16。

图 1-16 安装 JSPBook.war 第二步:设定 JSPBook 站台;

在 Tomcat 上建立一个 JSPBook 站台时,我们须修改 Tomcat 的 server.xml 文件,server.xml 位 于{Tomcat_Install}\conf\server.xml(例如:C:\Program Files\Apache Software Foundation\

Tomcat 5.0\conf\server.xml)。

server.xml

………

<!-- Tomcat Root Context -->

<!--

<Context path="" docBase="ROOT" debug="0">

-->

(11)

<Context path="/JSPBook" docBase="JSPBook" debug="0"

crosscontext="true" reloadable="true" >

</Context>

</Host>

</Engine>

</Service>

</Server>

这 部 分 主 要 是 设 定 JSPBook 站 台 , 其 中 path="/JSPBook" 代 表 网 域 名 称 , 即 http://IP_DomaninName/JSPBook ; docBase="JSPBook" 代 表 站 台 的 目 录 位 置 , 即 {Tomcat_Install}\webapps\JSPBook;debug 则是设定 debug level,0 表示提供最少的信息,9 表 示提供最多的信息;reloadable 则表示 Tomcat 在执行时,当 class、web.xml 被更新过时,都会自 动重新加载,不需要重新启动 Tomcat。

注意

<Context>…</Context> 的位置必须在 <Host>…</Host> 之间,不可任意更动位置。

第三步:执行 JSPBook 站台(见图 1-17);

(12)

图 1-17 执行 JSPBook 站台

第四步:JSPBook 站台目录结构。

JSPBook 目录下包含:

(1) 各章节的 HTML/JSP 程序;

(2) dist 目 录 : 存 放 在 JSPBook 站 台 压 缩 后 的 JSPBook.war;

(3) build.xml:Ant 文件;

(4) WEB-INF 目录:包含 \classes、\lib、\tags 和 \src;

(5) src 目录:存放范例的源程序,如:JavaBean、Filter、Servlet,等等;

(6) Images 目录:存放范例程序的图片。

图 1-18 为 JSPBook 站台目录结构。

图 1-18 JSPBook

(13)

1-4 安装 Ant 1.6

修改 JSP 程序时,Tomcat 会自动将 JSP 重新转译为 Servlet,并且编译 Servlet。但是,假 若修改 Servlet、JavaBean 或 Filter 时,我们就必须自行先编译它们,然后再将它们重新部署 至 WEB-INF\classes 下。

为了方便编译这些程序,笔者提供 JSPBook 站台的 build.xml 文件,因此,建议读者先安装 Ant 1.6,并且学习使用 Ant。

目前 Ant 的最新版本为 1.6,读者可以自行至 http://ant.apache.org 下载最新版本,如 图 1-19 所 示 , 或 者 直 接 使 用 本 书 CD 光 盘 中 的 Ant 1.6 , 软 件 名 称 为 : apache-ant-1.6.0-bin.zip。

第一步:将 apache-ant-1.6.0-bin.zip 解压缩;

解 压 缩 apache-ant-1.6.0-bin.zip 之 后 , 在 apache-ant-1.6.0-bin 目录下会有一目录 apache-ant-1.6.0,然后将 apache-ant-1.6.0 整个目录搬移至 C:\ 底下。

第二步:设定 Ant 1.6(见图 1-20);

从【开始】→【设定】→【控制面板】→【系统】→【高级】→【环境变量】 →【系统变量】,

然后到【新建】。

ANT_HOME = C:\apache-ant-1.6.0 PATH = %ANT_HOME%\bin

第三步:测试 Ant 1.6;

(14)

图 1-19 http://ant.apache.org

图 1-20 设定 Ant 1.6

打开命令提示符,输入 ant –version,假若执行成功,则会有如图 1-21 所示的结果。

图 1-21 测试 Ant 1.6

(15)

第四步:使用 Ant 1.6 编译 JSPBook\WEB-INF\src 中的程序。

要编译修改过的 JSPBook\WEB-INF\src 中的程序时,首先打开命令提示符,移至 JSPBook 站台 的所在目录,例如:C:\Program Files\Apache Software Foundation\Tomcat 5.0\webapps\JSPBook。

然后执行 ant,它会先自动找到 JSPBook\build.xml 文件,根据 build.xml 的设定,编译 C:\Program Files\Apache Software Foundation\Tomcat 5.0\webapps\JSPBook\WEB-INF\src 目录下所有的 Java 源文件,然后将产生的类文件存放至 C:\Program Files\Apache Software Foundation\Tomcat 5.0\webapps\JSPBook\WEB-INF\classes 目录下。图 1-22 为执行 ant 指令的结果。

图 1-22 执行 ant 指令

(16)

第二章 Servlet 2.4 简介

2-1 Servlet 简介

自 1997 年 3 月 Sun Microsystems 公司所组成的 JavaSoft 部门将 Servlet API 定案以来,推出 了 Servlet API 1.0。就当时功能来说,Servlet 所提供的功能包含了当时的 CGI (Common Gateway Interface)与 Netscape Server API (NSAPI)之类产品的功能。

发展至今,Servlet API 的最新版本为 2.4 版。它依旧是一个具有跨平台特性、100% Pure Java 的 Server-Side 程序,它相对于在 Client 端执行的 Applet。Servlet 不只限定于 HTTP 协议,开发 人员可以利用 Servlet 自定义或延伸任何支持 Java 的 Server —— 包括 Web Server、Mail Server、

Ftp Server、Application Server 或任何自定义的 Server。

Servlet 有以下优点:

● 可移植性(Portability)

Servlet 皆是利用 Java 语言来开发的,因此,延续 Java 在跨平台上的表现,不论 Server 的操 作系统是 Windows、Solaris、Linux、HP-UX、FreeBSD、Compaq Tru 64、AIX 等等,都能够将我们 所写好的 Servlet 程序放在这些操作系统上执行。借助 Servlet 的优势,就可以真正达到 Write Once,

Serve Anywhere 的境界,这正是从事 Java 程序员最感到欣慰也是最骄傲的地方。

当程序员在开发 Applet 时,时常为了“可移植性”(portability)让程序员感到绑手绑脚的,

例如:开发 Applet 时,为了配合 Client 端的平台 ( 即浏览器版本的不同,plug-in 的 JDK 版本也 不尽相同 ),达到满足真正“跨平台”的目的时,需要花费程序员大量时间来修改程序,为的就是 能够让用户皆能够执行。但即使如此,往往也只能满足大部分用户,而其他少数用户,若要执行 Applet,仍须先安装合适的 JRE (Java Runtime Environment)。

但是 Servlet 就不同了,主要原因在于 Servlet 是在 Server 端上执行的,所以,程序员只要专 心开发能在实际应用的平台环境下测试无误即可。除非你是从事做 Servlet Container 的公司,否 则不须担心写出来的 Servlet 是否能在所有的 Java Server 平台上执行。

● 强大的功能

Servlet 能够完全发挥 Java API 的威力,包括网络和 URL 存取、多线程 (Multi-Thread)、影像

(17)

处理、RMI (Remote Method Invocation)、分布式服务器组件 (Enterprise Java Bean)、对象序列 化 (Object Serialization) 等。若想写个网络目录查询程序,则可利用 JNDI API;想连接数据库,

则可利用 JDBC,有这些强大功能的 API 做后盾,相信 Servlet 更能够发挥其优势。

● 性能

Servlet 在加载执行之后,其对象实体(instance)通常会一直停留在 Server 的内存中,若有请 求(request)发生时,服务器再调用 Servlet 来服务,假若收到相同服务的请求时,Servlet 会利用 不同的线程来处理,不像 CGI 程序必须产生许多进程 (process)来处理数据。在性能的表现上,大 大超越以往撰写的 CGI 程序。最后补充一点,那就是 Servlet 在执行时,不是一直停留在内存中,

服务器会自动将停留时间过长一直没有执行的 Servlet 从内存中移除,不过有时候也可以自行写程 序来控制。至于停留时间的长短通常和选用的服务器有关。

● 安全性

Servlet 也有类型检查(Type Checking)的特性,并且利用 Java 的垃圾收集(Garbage Collection) 与没有指针的设计,使得 Servlet 避免内存管理的问题。

由于在 Java 的异常处理(Exception-Handling)机制下,Servlet 能够安全地处理各种错误,不会 因为发生程序上逻辑错误而导致整体服务器系统的毁灭。例如:某个 Servlet 发生除以零或其他不合 法的运算时,它会抛出一个异常(Exception)让服务器处理,如:记录在记录文件中(log file)。

2-2 First Servlet Sample Code

HelloServlet.java

package tw.com.javaworld.CH2;

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

public class HelloServlet extends HttpServlet {

(18)

public void init(ServletConfig config) throws ServletException { super.init(config);

}

//Process the HTTP Get request

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

response.setContentType("text/html;charset=GB2312");

PrintWriter out = response.getWriter();

out.println("<html>");

out.println("<head><title>CH2 - HelloServlet</title></head>");

out.println("<body>");

out.println(" Hello World <br>");

out.println("大家好");

out.println("</body>");

out.println("</html>");

out.close();

}

//Get Servlet information

public String getServletInfo() {

return "tw.com.javaworld.CH2.HelloSerlvet Information";

}

}

(19)

注意:HelloServlet.java 范例程序位于 JSPBook\WEB-INF\src\tw\com\javaworld\CH2,其中 JSPBook 范例程序的安装方法,请参见 1-3 节“安装 JSPBook 站台范例” 和 1-4 节“安装 Ant 1.6”。

一开始我们必须导入(import) javax.servlet.*、javax.servlet.http.*。

javax.servlet.* :存放与 HTTP 协议无关的一般性 Servlet 类;

javax.servlet.http.* :除了继承 javax.servlet.* 之外,并且还增加与 HTTP 协议有关的功能。

所有 Servlet 都必须实现 javax.servlet.Servlet 接口(Interface),但是通常我们都会从 javax.servlet.GenericServlet 或 javax.servlet.http.HttpServlet 择一来实现。若写的 Servlet 程序和 HTTP 协议无关,那么必须继承 GenericServlet 类;若有关,就必须继承 HttpServlet 类。

javax.servlet.* 里的 ServletRequest 和 ServletResponse 接口提供存取一般的请求和响应;

而 javax.servlet.http.* 里的 HttpServletRequest 和 HttpServletResponse 接口,则提供 HTTP 请求及响应的存取服务。

public void init(ServletConfig config) throws ServletException {

super.init(config);

}

这个例子中,一开始和 Applet 一样,也有 init( )的方法。当 Servlet 被 Container 加载后,

接下来就会先执行 init( )的内容,因此,我们通常利用 init( )来执行一些初始化的工作。

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException,IOException { response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<html>");

out.println("<head><title>CH2 - HelloServlet</title></head>");

out.println("<body>");

out.println("Hello World <br>");

(20)

out.println("大家好");

out.println("</body>");

out.println("</html>");

out.close();

}

Servlet 可以利用 HttpServletResponse 类的 setContentType( )方法来设定内容类型,我们要 显示为 HTML 网页类型,因此,内容类型设为"text/html",这是 HTML 网页的标准 MIME 类型值。之 后,Servlet 用 getWriter( )方法取得 PrintWriter 类型的 out 对象,它与 PrintSteam 类似,但是 它能对 Java 的 Unicode 字符进行编码转换。最后,再利用 out 对象把 "Hello World" 的字符串显 示在网页上。

public void destroy( ){

…………

…………. Servlet 结束时,会自动调用执行的程序 ………….

}

若当 Container 结束 Servlet 时,会自动调用 destroy( ),因此,我们通常利用 destroy( )来 关闭资源或是写入文件,等等。

编译 HelloServlet.java 的方法:

(1) 将 servlet-api.jar 加入至 CLASSPATH 之中,直接使用 javac 来编译 HelloServlet.java。

其中 servlet-api.jar 可以在{Tomcat_Install}\common\lib 找到。

(2) 直接使用 Ant 方式编译 HelloServlet.java,请参见 1-4 节“安装 Ant 1.6”。

编译好 HelloServlet.java 之后,再来设定 web.xml,如下:

<servlet>

<servlet-name>HelloServlet</servlet-name>

(21)

<servlet-class>tw.com.javaworld.CH2.HelloServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>HelloServlet</servlet-name>

<url-pattern>/HelloServlet</url-pattern>

</servlet-mapping>

最后,HelloServlet.java 的执行结果如图 2-1 所示。

图 2-1 HelloServlet.java 的执行结果

顺利完成第一个 Servlet 程序后,不知道读者有没有发现,在 HelloServlet.java 主程序中,

其实大部分都是一些用来显示 HTML 的 out.println("….")程序代码,这就是 Servlet 用在开发 Web-based 系统时最麻烦的地方。假若 Servlet 要显示表格统计图时,我想那时候程序员一定会疯 掉,因为你会发现,其实你所有的时间都在 out.println( ),因此,Servlet 适合在简单的用户接 口(User Interface)系统中。不过,幸好有 JSP 技术来解决这项极为不方便的问题。

2-3 Servlet 的生命周期

当 Servlet 加载 Container 时,Container 可以在同一个 JVM 上执行所有 Servlet,所以 Servlet 之间可以有效地共享数据,但是 Servlet 本身的私有数据亦受 Java 语言机制保护。

Servlet 从产生到结束的流程如图 2-2 所示。

(22)

(2) 以多线程的方式处理来自 Client 的请求。

(3) 调用 destroy( )来销毁 Servlet,进行垃圾收集 (garbage collection)。

Servlet 生命周期的定义,包括如何加载、实例化、初始化、处理客户端请求以及如何被移除。

这个生命周期由 javax.servlet.Servlet 接口的 init ( )、service( )和 destroy( )方法表达。

图 2-2 Servlet 从产生到结束的流程 1. 加载和实例化

当 Container 一开始启动,或是客户端发出请求服务时,Container 会负责加载和实例化一个 Servlet。

2. 初始化

Servlet 加载并实例化后,再来 Container 必须初始化 Servlet。初始化的过程主要是读取配置 信息(例如 JDBC 连接)或其他须执行的任务。我们可以借助 ServletConfig 对象取得 Container 的 配置信息,例如:

<servlet>

<servlet-name>HelloServlet</servlet-name>

<servlet-class>tw.com.javaworld.CH2.HelloServlet</servlet-class>

(23)

<init-param>

<param-name>user</param-name>

<param-value>browser</param-value>

</init-param>

</servlet>

其中 user 为初始化的参数名称;browser 为初始化的值。因此,可以在 HelloServlet 程序中使 用 ServletConfig 对象的 getInitParameter("user")方法来取得 browser。

3. 处理请求

Servlet 被初始化后,就可以开始处理请求。每一个请求由 ServletRequest 对象来接收请求;

而 ServletResponse 对象来响应该请求。

4. 服务结束

当 Container 没有限定一个加载的 Servlet 能保存多长时间,因此,一个 Servlet 实例可能只 在 Container 中存活几毫秒,或是其他更长的任意时间。一旦 destroy( )方法被调用时,Container 将移除该 Servlet,那么它必须释放所有使用中的任何资源,若 Container 需要再使用该 Servlet 时,它必须重新建立新的实例。

2-4 Servlet 范例程序

为了说明 Servlet 和网页是如何沟通的,笔者在此举一个 Sayhi 的范例程序。这个范例程序分 为两部分:Sayhi.html 和 Sayhi.java。

在 Sayhi.html 中,用户可以填入姓名,然后按下【提交】后,将数据传到 Sayhi.java 做处理,

而 Sayhi.java 负责将接收到的数据显示到网页上。

Sayhi.html

<html>

<head>

<title>CH2 - Sayhi.html</title>

(24)

<meta http-equiv="Content-Type" content="text/html; charset=GB2312">

</head>

<body>

<h2>Servlet 范例程序</h2>

<form name="Sayhi" Method="Post" action="/JSPBook/CH2/Sayhi" >

<p>请访问者输入姓名:<input type="text" name="Name" size="30"></p>

<input type="submit" value="提交">

<input type="reset" value="清除">

</form>

</body>

</html>

Sayhi.html 的执行结果如图 2-3 所示。

图 2-3 Sayhi.html 的执行结果

Sayhi.java

package tw.com.javaworld.CH2;

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

(25)

public class Sayhi extends HttpServlet { //Initialize global variables

public void init(ServletConfig config) throws ServletException { super.init(config);

}

//Process the HTTP Get request

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html;charset=GB2312");

PrintWriter out = response.getWriter();

request.setCharacterEncoding("GB2312");

String Name = request.getParameter("Name");

out.println("<html>");

out.println("<head><title>CH2 - Sayhi</title></head>");

out.println("<body>");

out.println("Hi:"+Name);

out.println("</body>");

out.println("</html>");

out.close();

}

//Get Servlet information public String getServletInfo() {

return "tw.com.javaworld.CH2.Sayhi Information";

(26)

}

public void destroy() {

}

}

从 Sayhi.java 的程序当中,可以发现 Servlet 是利用 HttpServletRequest 类的 getParameter( ) 方法来取得由网页传来的数据。不过数据通过 HTTP 协议传输时会被转码,因此在接收时,必须再做转 码的工作,才能够正确地接收到数据。下面这段程序是做转码的动作:

request.setCharacterEncoding("GB2312");

编译 Sayhi.java 之后,再来设定 web.xml:

<servlet>

<servlet-name>Sayhi</servlet-name>

<servlet-class>tw.com.javaworld.CH2.Sayhi</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>Sayhi</servlet-name>

<url-pattern>/CH2/Sayhi</url-pattern>

</servlet-mapping>

执行 http://localhost:8080/JSPBook/CH2/Sayhi,结果如图 2-4 所示。

图 2-4 Sayhi.html 按下【提交】后,经过 Sayhi.java 处理后的结果

(27)

2-5 Servlet 2.4 的新功能

2003 年 11 月底,J2EE 1.4 规范正式发布,Servlet 也从原本的 2.3 版升级至 2.4 版。其中主要 新增的功能有以下三点:

(1) web.xml DTD 改用 XML Schema;

(2) 新增 Filter 四种设定;

(3) 新增 Request Listener、Event 和 Request Attribute Listener、Event。

2-5-1 web.xml 改用 XML Schema

Servlet 在 2.4 版之前,web.xml 都是使用 DTD(Document Type Definition)来定义 XML 文件内 容结构的,因此,Servlet 2.3 版 web.xml 一开始的声明如下:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

…………

</web-app>

到了 Servlet 2.4 版之后,web.xml 改为使用 XML Schema,此时 web.xml 的声明如下:

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

(28)

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"

version="2.4">

…………

</web-app>

由 DTD 改为 Schema,主要加强两项功能:

(1) 元素可不依照顺序设定;

(2) 更强大的验证机制。

下面的范例,在 Servlet 2.3 版是不合规则的 web.xml 文件:

<web-app>

...

<servlet>

<servlet-name>ServletA</servlet-name>

<servlet-class>tw.com.javaworld.servlet.ServletA</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>ServletA</servlet-name>

<url-pattern>/ServletA/*</url-pattern>

</servlet-mapping>

<servlet>

<servlet-name>ServletB</servlet-name>

(29)

<servlet-class> tw.com.javaworld.servlet.ServletB</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>ServletB</servlet-name>

<url-pattern>/ServletB /*</url-pattern>

</servlet-mapping>

...

</web-app>

因为<servlet-mapping>元素必须在<servlet>元素之后,因此,上述的范例要改为:

<web-app>

...

<servlet>

<servlet-name>ServletA</servlet-name>

<servlet-class>tw.com.javaworld.servlet.ServletA</servlet-class>

</servlet>

<servlet>

<servlet-name>ServletB</servlet-name>

<servlet-class> tw.com.javaworld.servlet.ServletB</servlet-class>

</servlet>

(30)

<servlet-mapping>

<servlet-name>ServletA</servlet-name>

<url-pattern>/ServletA/*</url-pattern>

</servlet-mapping>

<servlet-mapping>

<servlet-name>ServletB</servlet-name>

<url-pattern>/ServletB /*</url-pattern>

</servlet-mapping>

...

</web-app>

不过在 Servlet 2.4 版之后,原来的范例也算是一个合法的 web.xml 文件,不再须注意元素的顺序。

除此之外,Servlet 2.4 版 web.xml 的 Schema 更能提供强大的验证机制,例如:

(1) 可检查元素的值是否为合法的值。例如:<filter-mapping>的<dispatcher>元素,其值只 能为 REQUEST、FORWARD、INCLUDE 和 ERROR,如下所示:

<filter-mapping>

<filter-name>Hello</filter-name>

<url-pattern>/CH11/*</url-pattern>

<dispatcher>REQUEST</dispatcher>

<dispatcher>FORWARD</dispatcher>

</filter-mapping>

若<dispatcher>元素的值不为上述四种时,此 web.xml 将会发生错误。

(2) 可检查如 Servlet、Filter 或 EJB-ref 等等元素的名称是否惟一。例如:

(31)

<servlet>

<servlet-name>ServletA</servlet-name>

<servlet-class>tw.com.javaworld.servlet.ServletA</servlet-class>

</servlet>

<servlet>

<servlet-name>ServletA</servlet-name>

<servlet-class>tw.com.javaworld.servlet.ServletB</servlet-class>

</servlet>

(3) 可检查元素值是否为合法文字字符或数字字符。例如:

<filter-mapping>

<filter-name>Hello</filter-name>

<url-pattern>/CH11/*</url-pattern>

</filter-mapping>

2-5-2 新增 Filter 四种设定

Servlet 2.3 版新增了 Filter 的功能,不过它只能由客户端发出请求来调用 Filter,但若使用 RequestDispatcher.forward( )或 RequestDispatcher.include( )的方法调用 Filter 时,Filter 却不会执行。因此,在 Servlet 2.4 版中,新增 Filter 的设定<dispatcher>来解决这个问题。有关 Filter 的部分在本书“第十一章:Filter 与 Listener”有更详细的介绍。

Servlet 2.4 版新增的 Filter 四种设定为:REQUEST、FORWARD、INCLUDE 和 ERROR。假若你有 一个 SimpleFilter,它只允许由客户端发出请求或由 RequestDispatcher.include( )的方式来调用 执行 SimpleFilter,此时 SimpleFilter 的设定如下:

(32)

<filter>

<filter-name>SimpleFilter</filter-name>

<filter-class>tw.com.javaworld.CH11.SimpleFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>SimpleFilter</filter-name>

<url-pattern>/CH11/*</url-pattern>

<dispatcher>REQUEST</dispatcher>

<dispatcher>INCLUDE</dispatcher>

</filter-mapping>

2-5-3 新 增 Request Listener、 Event 和 Request Attribute Listener、 Event

在 Servlet 2.3 版中,新增许多的 Listener 接口和 Event 类(见表 2-1): 表 2-1

Listener 接口 Event 类

ServletContextListener ServletContextEvent

ServletContextAttributeListener ServletContextAttributeEvent HttpSessionListener HttpSessionEvent

HttpSessionActivationListener HttpSessionAttributeListener

在 Servlet 2.4 版陆续又多新增 Request Listener、Event 和 Request Attribute Listener、Event

(见表 2-2):

表 2-2

Listener 接口 Event 类

ServletRequestListener ServletRequestEvent

ServletRequestAttributeListener ServletRequestAttributeEvent

这部分在“第十一章:Filter 与 Listener”中有更详细的介绍。

(33)

2-5-4 Servlet 2.4 的其他变更

Servlet 2.4 其他较显著的变更如:

(1) 取消 SingleThreadModel 接口。当 Servlet 实现 SingleThreadModel 接口时,它能确保同时间 内,只能有一个 thread 执行此 Servlet。

(2) <welcome-file-list>可以为 Servlet。例如:

<servlet>

<servlet-name>Index</servlet-name>

<servlet-class>tw.com.javaworld.IndexServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>Index</servlet-name>

<url-pattern>/*</url-pattern>

</servlet-mapping>

<welcome-file-list>

<welcome-file>Index</welcome-file>

</welcome-file-list>

(3) ServletRequest 接口新增一些方法,如:

public String getLocalName( );

public String getLocalAddr( );

public int getLocalPort( );

public int getRemotePort( );

(34)

第三章 JSP 2.0 简介

3-1 JavaServer Pages 技术

JavaServer Pages 技术是一个纯 Java 平台的技术,它主要用来产生动态网页内容,包括:HTML、

DHTML、XHTML 和 XML。JavaServer Pages 技术能够让网页人员轻易建立起功能强大、有弹性的动态 内容。

JavaServer Pages 技术有下列优点:

● Write Once, Run Anywhere 特性

作为 Java 平台的一部分,JavaServer Pages 技术拥有 Java 语言“一次编写,各处执行”的特 点。随着越来越多的供货商将 JavaServer Pages 技术添加到他们的产品中,您可以针对自己公司 的需求,做出审慎评估后,选择符合公司成本及规模的服务器,假若未来的需求有所变更时,更换 服务器平台并不影响之前所投下的成本、人力所开发的应用程序。

● 搭配可重复使用的组件

JavaServer Pages 技术可依赖于重复使用跨平台的组件(如:JavaBean 或 Enterprise JavaBean 组件)来执行更复杂的运算、数据处理。开发人员能够共享开发完成的组件,或者能够加强这些组 件的功能,让更多用户或是客户团体使用。基于善加利用组件的方法,可以加快整体开发过程,也 大大降低公司的开发成本和人力。

● 采用标签化页面开发

Web 网页开发人员不一定都是熟悉 Java 语言的程序员。因此,JSP 技术能够将许多功能封装起 来,成为一个自定义的标签,这些功能是完全根据 XML 的标准来制订的,即 JSP 技术中的标签库(Tag Library)。因此,Web 页面开发人员可以运用自定义好的标签来达成工作需求,而无须再写复杂的 Java 语法,让 Web 页面开发人员亦能快速开发出一动态内容网页。

今后,第三方开发人员和其他人员可以为常用功能建立自己的标签库,让 Web 网页开发人员能 够使用熟悉的开发工具,如同 HTML 一样的标签语法来执行特定功能的工作。本书将在“第十五章:

JSP Tag Library”和“第十六章:Simple Tag 与 Tag File”中详细地为各位介绍如何制作标签。

● N-tier 企业应用架构的支持

有鉴于网际网络的发展,为因应未来服务越来越繁杂的要求,且不再受地域的限制,因此,

必须放弃以往 Client-Server 的 Two-tier 架构,进而转向更具威力、弹性的分散性对象系统。由于

(35)

JavaServer Page 技术是 Java 2 Platform Enterprise Edition (J2EE) (相关信息请参阅

www.javasoft.com/products/j2ee)集成中的一部分,它主要是负责前端显示经过复杂运算后之结果 内容,而分散性的对象系统则是主要依赖 EJB ( Enterprise JavaBean )和 JNDI ( Java Naming and Directory Interface )构建[1]而成。

3-2 What is JSP

JSP( JavaServer Pages )是由 Sun 公司倡导、许多别的公司参与一起建立的一种新动态网页 技术标准,类似其他技术标准,如 ASP、PHP 或是 ColdFusion,等等。

在传统的网页 HTML 文件( *.htm,*.html )中加入 Java 程序片段( Scriptlet )和 JSP 标签,构 成了 JSP 网页(*.jsp)。Servlet/JSP Container 收到客户端发出的请求时,首先执行其中的程序片 段,然后将执行结果以 HTML 格式响应给客户端。其中程序片段可以是:操作数据库、重新定向网页 以及发送 E-Mail 等等,这些都是建立动态网站所需要的功能。所有程序操作都在服务器端执行,

网络上传送给客户端的仅是得到的结果,与客户端的浏览器无关,因此,JSP 称为 Server-Side Language。

3-3 JSP 与 Servlet 的比较

Sun 公司首先发展出 Servlet,其功能非常强大,且体系设计也很完善,但是它输出 HTML 语法 时,必须使用 out.println( )一句一句地输出,例如下面一段简单的程序:

out.println("<html>");

out.println("<head><title>demo1</title></head>");

out.println(" Hello World <br>");

out.println("<body>");

out.println("大家好");

out.println("</body>");

(36)

由于这是一段简单的 Hello World 程序,还看不出来其复杂性,但是当整个网页内容非常复杂 时,那么你的 Servlet 程序可能大部分都是用 out.println( )输出 HTML 的标签了!

后来 Sun 公司推出类似于 ASP 的嵌入型 Scripting Language,并且给它一个新的名称:

JavaServer Pages,简称为 JSP。于是上面那段程序改为:

<html>

<head><title>www.javaworld.com.tw – 台湾 Java 论坛</title></head>

<body>

<%

out.println(" Hello World <br>");

out.println("大家好");

%>

</body>

</html>

这样就简化了 Web 网页程序员的负担,不用为了网页内容编排的更动,又需要由程序员来做修 改。

3-4 JSP 的执行过程

在介绍 JSP 语法之前,先向读者说明一下 JSP 的执行过程(见图 3-1)。 (1) 客户端发出 Request (请求);

(2) JSP Container 将 JSP 转译成 Servlet 的源代码;

(3) 将产生的 Servlet 的源代码经过编译后,并加载到内存执行;

(4) 把结果 Response (响应)至客户端。

(37)

图 3-1 JSP 的执行过程

一般人都会以为 JSP 的执行性能会和 Servlet 相差很多,其实执行性能上的差别只在第一次的 执行。因为 JSP 在执行第一次后,会被编译成 Servlet 的类文件[玉玉 2],即为 XXX.class,当再重

复调用执行时,就直接执行第一次所产生的 Servlet,而不用再重新把 JSP 编译成 Servlet。因此,

除了第一次的编译会花较久的时间之外,之后 JSP 和 Servlet 的执行速度就几乎相同了。

在执行 JSP 网页时,通常可分为两个时期:转译时期(Translation Time)和请求时期(Request Time)(见图 3-2)。

转译时期:JSP 网页转译成 Servlet 类。

请求时期:Servlet 类执行后,响应结果至客户端。

补充

转译期间主要做了两件事情:将 JSP 网页转译为 Servlet 源代码(.java),此段称为转译时 期(Translation time);将 Servlet 源代码(.java)编译成 Servlet 类(.class),此段称为 编译时期(Compilation time)。

(38)

当 JSP 网页在执行时,JSP Container 会做检查的工作,若发现 JSP 网页有更新修改时,JSP Container 才会再次编译 JSP 成 Servlet;JSP 没有更新时,就直接执行前面所产生的 Servlet。

笔者在这里以 Tomcat 为例,看看 Tomcat 如何将 JSP 转译成 Servlet。首先笔者写一个简单的 JSP 网页 —— HelloJSP.jsp:

HelloJSP.jsp

<%@ page contentType="text/html;charset=GB2312" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>

<head>

<title>CH3 - HelloJSP.jsp</title>

</head>

<body>

<h2>JSP 将会被转译为 Servlet</h2>

<%!

int k = 0;

%>

<c:out value="Hi" />

<%

String name = "browser";

out.println("大家好 !!");

%>

<%= name %>

</body>

</html>

(39)

当 执行 HelloJSP.jsp 时, Tomcat 会将 它先 转译为 Servlet 。这个 Servlet 程序 是放 在 {Tomcat_Install}\Apache Software Foundation\Tomcat 5.0\ work\Catalina\localhost\JSPBook\

org\apache\jsp\CH3 目录下的 HelloJSP_jsp.java 和 HelloJSP_jsp.class。其中 HelloJSP_jsp.java 就是 HelloJSP.jsp 所转译的 Servlet 源代码,它的程序如下:

HelloJSP_jsp.java

package org.apache.jsp.CH3;

import javax.servlet.*;

import javax.servlet.http.*;

import javax.servlet.jsp.*;

public final class HelloJSP_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent {

int k = 0;

private static java.util.Vector _jspx_dependants;

private org.apache.jasper.runtime.TagHandlerPool _ jspx_tagPool_c_out_value;

public java.util.List getDependants() { return _jspx_dependants;

}

public void _jspInit() { _jspx_tagPool_c_out_value =

org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(

getServletConfig());

}

public void _jspDestroy() {

_jspx_tagPool_c_out_value.release();

}

public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException {

JspFactory _jspxFactory = null;

(40)

HttpSession session = null;

ServletContext application = null;

ServletConfig config = null;

JspWriter out = null;

Object page = this;

JspWriter _jspx_out = null;

try {

_jspxFactory = JspFactory.getDefaultFactory();

response.setContentType("text/html;charset=GB2312");

pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true);

application = pageContext.getServletContext();

config = pageContext.getServletConfig();

session = pageContext.getSession();

out = pageContext.getOut();

_jspx_out = out;

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

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

out.write("<html>\r\n");

out.write("<head>\r\n ");

out.write("<title>CH3 - HelloJSP.jsp");

out.write("</title>\r\n");

out.write("</head>\r\n");

out.write("<body>\r\n\r\n");

out.write("<h2>JSP 将会被转译为 Servlet");

out.write("</h2>\r\n\r\n");

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

if (_jspx_meth_c_out_0(pageContext)) return;

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

String name = "browser";

out.println("大家好 !!");

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

out.print( name );

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

out.write("</body>\r\n");

out.write("</html>");

} catch (Throwable t) {

(41)

if (!(t instanceof SkipPageException)){

out = _jspx_out;

if (out != null && out.getBufferSize() != 0) out.clearBuffer();

if (pageContext != null) pageContext.handlePageException(t);

}

} finally {

if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);

} }

private boolean _jspx_meth_c_out_0(PageContext pageContext) throws Throwable {

JspWriter out = pageContext.getOut();

// c:out

org.apache.taglibs.standard.tag.rt.core.OutTag _jspx_th_c_out_0 = (org.apache.taglibs.standard.tag.rt.core.OutTag) _jspx_tagPool_c_out_value.

get( org.apache.taglibs.standard.tag.rt.core.OutTag.class);

_jspx_th_c_out_0.setPageContext(pageContext);

_jspx_th_c_out_0.setParent(null);

_jspx_th_c_out_0.setValue(new String("Hi"));

int _jspx_eval_c_out_0 = _jspx_th_c_out_0.doStartTag();

if (_jspx_th_c_out_0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) return true;

_jspx_tagPool_c_out_value.reuse(_jspx_th_c_out_0);

return false;

} }

当 JSP 被转译成 Servlet 时,内容主要包含三部分:

public void _jspInit() {

…. 略 }

public void _jspDestroy() { …. 略

(42)

}

public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException {

…. 略 }

_jspInit( ):当 JSP 网页一开始执行时,最先执行此方法。因此,我们通常会把初始化的工作写在 此方法中。

_jspDestroy( ):JSP 网页最后执行的方法。

_jspService( ):JSP 网页最主要的程序都是在此方法中。

接下来笔者将 HelloJSP.jsp 和 HelloJSP_jsp.java 做一个简单的对照:

<%@ page contentType="text/html;charset=GB2312" %>

response.setContentType("text/html;charset=GB2312");

<%! int k = 0; %>

int k = 0; // 此为全局变量

<html>

<head>

(43)

<title>CH3 - HelloJSP.jsp</title>

</head>

<body>

<h2>JSP 将会被转译为 Servlet</h2>

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

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

out.write("<html>\r\n");

out.write("<head>\r\n ");

out.write("<title>CH3 - HelloJSP.jsp");

out.write("</title>\r\n");

out.write("</head>\r\n");

out.write("<body>\r\n\r\n");

out.write("<h2>JSP 将会被转译为 Servlet");

out.write("</h2>\r\n\r\n");

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

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:out value="Hi" />

if (_jspx_meth_c_out_0(pageContext))

return;

…. 略

private boolean _jspx_meth_c_out_0(PageContext pageContext)

(44)

JspWriter out = pageContext.getOut();

// c:out

org.apache.taglibs.standard.tag.rt.core.OutTag _jspx_th_c_out_0 = (org.apache.taglibs.standard.tag.rt.core.OutTag) _jspx_tagPool_c_out_value.

get(org.apache.taglibs.standard.tag.rt.core.OutTag.class);

_jspx_th_c_out_0.setPageContext(pageContext);

_jspx_th_c_out_0.setParent(null);

_jspx_th_c_out_0.setValue(new String("Hi"));

int _jspx_eval_c_out_0 = _jspx_th_c_out_0.doStartTag();

if (_jspx_th_c_out_0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) return true;

_jspx_tagPool_c_out_value.reuse(_jspx_th_c_out_0);

return false;

}

<%

String name = "browser";

out.println("大家好 !!");

%>

<%= name %>

String name = "browser";

out.println("大家好 !!");

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

out.print( name );

3-5 JSP 与 ASP 和 ASP+的比较

JSP 与 ASP 的比较

一般说来,Sun 公司的 JavaServer Pages(JSP)和 Microsoft 的 Active Server Pages(ASP)

(45)

在技术方面有许多相似之处。两者都为动态网页的技术,并且双方都能够替代 CGI 技术,使网站的 开发时程能够大大缩短,在性能上也有较高的表现,更重要的一点是,两者都能够为程序员提供组 件设计的功能,通过组件设计,将网页中逻辑处理部分交由组件负责处理(ASP 使用 COM 组件、JSP 则有 JavaBean 组件),而和网页上的排版、美工分离。

尽管 JavaServer Pages 技术和 Active Server Pages(ASP)在许多方面都很相似,但仍然存 在很多不同之处,其中本质上的区别在于:两者是来源于不同的技术规范组织。以下就来比较两大 技术有哪些不同点,而又为各自带来哪些优势。

平台和服务器的弹性

ASP (Active Server Pages)技术主要在微软(Microsoft)公司的 Windows 平台上运行,其中包括 Windows 2000、Windows XP 和 Windows 2003,并且搭配其 WEB 服务器 IIS (Internet Information Services)。但是,在其他的平台运行时,不是性能低落,就是根本不支持,因此,当在开发网站系 统时,选择 NT+IIS+ASP 的体系结构时,未来当系统无法负荷时,也只能继续选择 Windows 平台的 服务器,无法改写在性能表现相当优异的 UNIX 平台上。

JSP (JavaServer Pages)技术主要运行在操作系统上的一个 Java Virtual Machine (JVM)虚拟机器上,

因此,它能够跨越所有的平台,例如:NT、Windows 2000、Solaris、Linux、OS/390、AIX、HP-UX , 等等,除了能在各式各样的操作系统上执行,并且能搭配现有的 WEB 服务器:Apache、IIS、Netscape Enterprise Server ,等等,将静态的 HTML 网页交由执行速度较快的 Web Server 处理,而动态产生 网页的部分,就交由 JSP Container 来执行。由上述可知,JSP (JavaServer Pages)技术在跨平台的表现 比 ASP 来得更有弹性。

WEB 网页程序员未来在开发电子商务平台时,就不需要再考虑客户厂商的操作系统平台,可更专 心于系统功能的开发。相应地,厂商在使用 JavaServer Pages 技术开发的系统平台时,不再需要担 心未来在扩充软、硬件时,是否产生不兼容的问题。光这一点,就能为企业省下一大笔的费用,这 是 JSP 的主要优点。

语法结构

ASP 语法结构上,是以"<%"和"%>"作为标记符号,而 JSP 也是使用相同标记符号作为程序的区

(46)

段范围的。但不同的是,标记符号之间所使用的语言:ASP 为 JavaScript 或 VBScript;而 JSP 为 Java。

Java 是有严格规划、强大且易扩充的语言,远优于 VBScript 语言。

Java 使程序员的工作在其他方面也变得一样容易、简单。例如:当 ASP 应用程序在 Windows NT 系统可能会造成系统 Crash (当机)时,由于 JSP 是在 JVM 上执行程序,且提供强大的异常事件处理 机制,因此,不会因为程序撰写的疏忽,而导致服务器操作系统的损毁。

并且 Java 语言提供防止直接存取内存的功能,存取内存产生的错误,通常也正是造成服务器损 毁的最主要原因之一。最后,最重要的原因,Java 语言是一个有严谨规范、有系统组织的语言,对 一个专业的 Java 程序员来说,也真正达到 Learn Once,Write Anywhere(学一次,皆可开发)的境 界。

开放的开发环境

自从 1995 年,Sun 公司已经开放技术与国际 Java 组织合作开发和修改 Java 技术与规范。针对 JSP 的新技术,Sun 公司授权工具供货商(如 Macromedia)、同盟公司(如 Apache、Netscape)、协 力厂商及其他公司。最近,Sun 公司将最新版本的 Servlet 2.4 和 JSP 2.0 的源代码发放给 Apache,以 求 JSP 与 Apache 紧密地相互发展。Apache、Sun 和许多其他的公司及个人公开成立一个咨询机构,

以便任何公司和个人都能免费取得信息。(详见:http://jakarta.apache.org)

JSP 应用程序接口(API)毫无疑问已经取得成功,并随着 Java 组织不断扩大其应用的范围,目 前全力发展 Java 技术的厂商不胜枚举,例如:最近 IBM 公司强力推广的 WebSphere 家族,正是完 全支持 J2EE 标准而开发。数据库厂商 Oracle 也发展自己的 Application Server 来和自己公司本身数 据库产品 Oracle 9i 做一紧密的结合。那也更不用提 Amazon 系统的供货商 BEA 公司,它的产品 WebLogic 也是完全支持 JavaServer Pages 技术和 J2EE 规范的。

相反,ASP 技术仅依靠微软本身的推动,其发展建立在独占、封闭的基础之上,并且微软本 身的技术又只允许在微软相关平台的服务器上执行,因此,在标准方面显得有点力不从心。

语法的延展性

ASP 和 JSP 都使用标签与 Scripting Language 来制作动态 WEB 网页,JavaServer Pages 2.0 新 规范中,能够让程序员自由扩展 JSP 标签来应用。JSP 开发者能自定义标签库( Tag Library ),所

(47)

以网页制作者能充分利用与 XML 兼容的标签技术强大的功能,大大减低对 Java 语法的依赖,并且也 可以利用 XML 强大的功能,做到数据、文件格式的标准化。相关标签库请参考“第十五章:JSP Tag Library”,其中有更加完整的说明。

执行性能表现

ASP 和 JSP 在执行性能的表现上,有一段显著的差距,JSP 除了在一开始加载的时间会比较久 外,之后的表现就远远比 ASP 的表现来得好。原因在于:JSP 在一开始接受到请求时,会产生一份 Servlet 实体( instance ),它会先被暂存在内存中,我们称之为持续( Persistence ),当再有 相同请求时,这实体会产生一个线程(thread)来服务它。如果过了一段时间都不再用到此实体时,

Container 会自动将其释放,至于时间的长短,通常都是可以在 Container 上自行设定的。

而 ASP 在每次接收到请求时,都必须要重新编译,因此,JSP 的执行比每次都要编译执行的 ASP 要快,尤其是程序中存在循环操作时,JSP 的速度要快上 1 到 2 倍。不过,ASP 在这部分的缺陷,将 随 ASP+的出现有所改观,在新版的 ASP+技术中,性能表现上有很大的突破。

JSP 与 ASP+的比较 1. [玉玉 3]面向对象性

C#为一种面向对象语言,从很多方面来看,C#将给 ASP+带来类似于 Java 的功能,并且它和 Windows 环境紧密结合,因此,具备更快的性能。笔者认为,C#是微软在市场上击败 Java 的主要工 具。

2. 数据库连接

ASP 最大的优点是它使用 ADO 对象,因此,ASP Web 数据库应用开发特别简单。ASP+发展了更多 的功能,因为有了 ADO+,ADO+带来了更强大更快速的功能。JSP 和 JDBC 目前在易用性和性能上和 ASP/ADO 相比已有些落后,当新版本 ASP+/ADO+出现后这样的差别会更明显,这部分希望 Sun 尽快追 赶 ASP+/ADO+的组合。

3. 大型网站应用

ASP+将对大型网站有更好的支持。事实上,微软在这方面付出了巨大的努力, ASP+可以让你考 虑到多服务器(multiple servers)的场合,当你需要更强大的功能时,仅仅只需要增加一台服务器。

ASP+现在可以在大型项目方面与 JSP 一样具有等同的能力,而且 ASP+还有价格方面的优势,因为所

(48)

结论:

除了上述 ASP、ASP+和 JSP 之外,笔者再提供一篇在网络上 ASP 和 JSP 比较的文章:

http://www.indiawebdevelopers.com/technology/Java/jsp.asp,希望能带给读者更客观的评论。

除了 ASP 之外,PHP 和 ColdFusion 皆为近年来常用来开发 WEB 动态网页内容的工具,各开发工 具皆有其优、缺点。ASP 和 PHP 最大的好处就是开发中、小型网站非常快速,市面上的书籍也较多,

学习起来能较快上手。尤其因为 PHP 的环境大都为 UNIX 的环境,因此,在规划、构建时,所花需的 成本为最低,但 PHP 并未将 Presentation Layer 和 Business Layer 做一个适当的处理,因此,往 往一个系统越来越庞大、越来越复杂时,维护起来就会越来越吃力,并且本身并没有一个强而有力 的技术在支持它,当开发系统要求为分布式的体系结构时,那么 PHP 可能就英雄无用武之地了。

3-6 JSP 2.0 新功能

J2EE 1.4 正式发布之后,Servlet 和 JSP 同时也做了一些变动,Servlet 从 2.3 更新至 2.4;而 JSP 从 1.2 更新至 2.0。两者平心而论,JSP 的变动较 Servlet 来得多,其中 JSP 2.0 较 JSP 1.2 新增的功能 如下:

(1) Expression Language;

(2) 新增 Simple Tag 和 Tag File;

(3) web.xml 新增<jsp-config>元素。

3-6-1 Expression Language

JSP 2.0 之后,正式将 EL 纳入 JSP 的标准语法。EL 主要的功用在于简化 JSP 的语法,方便 Web 开发人员的使用。例如:

使用 JSP 传统语法:

<%

String str_count = request.getParameter("count");

int count = Integer.parseInt(str_count);

(49)

count = count + 5;

out.println("count:" + count);

%>

使用 EL 语法:

count:${param.count + 5}

对于 EL 的部分,本书的“第六章:Expression Language”有详尽的介绍。

3-6-2 新增 Simple Tag 和 Tag File

JSP 2.0 提供一些较为简单的方法,让开发人员来撰写自定义标签。JSP 2.0 提供两种新的机制,

分别为 Simple Tag 和 Tag File。

Simple Tag Handler 和其他 Tag Handler(如:Body Tag Handler、Tag Handler 和 Iteration Tag Handler) 不同之处在于:Simple Tag Handler 并无 doStartTag( )和 doEndTag( ),它只有 doTag( ),因此,实现 标签能比以往更为方便。

Tag File 就更为简单,你可以把它当做直接使用 JSP 的语法来制作标签。例如:

Hello.tag

<%

out.println("Hello from tag file.");

%>

我们先制作一个名为 Hello.tag 的 Tag File,然后将它放置在 WEB-INF/tags/ 目录下。在 JSP 网页使用 Hello.tag 的方法如下:

<%@ taglib prefix="myTag" tagdir="/WEB-INF/tags" %>

<myTag:Hello />

(50)

最后执行的结果如下:

Hello from tag file.

有关 Simple Tag Handler 和 Tag File 的部分,在“第十六章:Simple Tag 与 Tag File”有更 详细的说明。

3-6-3 web.xml 新增<jsp-config>元素

<jsp-config> 元 素 主 要 用 来 设 定 JSP 相 关 配 置 , <jsp-config> 包 括 <taglib> 和

<jsp-property-group> 两 个 子 元 素 。 其 中 <taglib> 元 素 在 JSP 1.2 时 就 已 经 存 在 ; 而

<jsp-property-group>是 JSP 2.0 新增的元素。

<jsp-property-group>元素主要有八个子元素,它们分别为:

<description>:设定的说明;

<display-name>:设定名称;

<url-pattern>:设定值所影响的范围,如:/CH2 或 /*.jsp;

<el-ignored>:若为 true,表示不支持 EL 语法;

<scripting-invalid>:若为 true,表示不支持<% scripting %>语法;

<page-encoding>:设定 JSP 网页的编码;

<include-prelude>:设置 JSP 网页的抬头,扩展名为.jspf;

<include-coda>:设置 JSP 网页的结尾,扩展名为.jspf。

图 3-3 所示的所谓 JSP 网页的抬头为网页最上方的 This banner included with <include-prelude>;

结尾为网页最下方的 This banner included with <include-coda>。

(51)

图 3-3 Tomcat 上的<include-prelude>范例程序 其中抬头的源程序为:

prelude.jspf

<hr>

<center>

This banner included with &lt;include-prelude&gt;

</center>

<hr>

结尾的源程序为:

coda.jspf

<hr>

(52)

<center>

This banner included with &lt;include-coda&gt;

</center>

<hr>

下面是一个简单的<jsp-config>元素完整配置:

<jsp-config>

<taglib>

<taglib-uri>Taglib</taglib-uri>

<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>

</taglib>

<jsp-property-group>

<description>

Special property group for JSP Configuration JSP example.

</description>

<display-name>JSPConfiguration</display-name>

<url-pattern>/jsp/* </url-pattern>

<el-ignored>true</el-ignored>

<page-encoding>GB2312</page-encoding>

<scripting-invalid>true</scripting-invalid>

<include-prelude>/include/prelude.jspf</include-prelude>

<include-coda>/include/coda.jspf</include-coda>

</jsp-property-group>

</jsp-config>

(53)

第四章 JSP 语法

4-1 Elements 和 Template Data

JSP 网页主要分为 Elements 与 Template Data 两部分。

Template Data:JSP Container 不处理的部分,例如:HTML 的内容,会直接送到 Client 端执 行。

Elements:必须经由 JSP Container 处理的部分,而大部分 Elements 都以 XML 作为语法基础,

并且大小写必须要一致。

Elements 有两种表达式,第一种为起始标签(包含 Element 名称、属性),中间为一些内容,最 后为结尾标签。如下所示:

<mytag attr1="attribute value" …..>

body

</mytag>

另一种是标签中只有 Element 的名称、属性,称为 Empty Elements。如下所示:

<mytag attr1="attribute value" …./>

Elements 有四种类型:Directive Elements、Scripting Elements、Action Elements 和 EL Elements,接下来的章节会针对前三种类型的 Elements 加以说明。至于 EL Elements 是 JSP 2.0 新 增的功能,笔者将在“第六章:Expression Language”中详细介绍它。

4-2 批注 (Comments)

一般批注可分为两种:一种为在客户端显示的批注;另外一种就是客户端看不到,只给开发程 序员专用的批注。

● 客户端可以看到的批注:

<!-- comment [ <%= expression %> ] -->

(54)

例如:

<!-- 现在时间为: <%= (new java.util.Date()).toLocaleString() %> -->

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

<!--现在时间为:January 1, 2004 -->

这种批注的方式和 HTML 中很像,它可以使用“查看源代码”来看到这些程序代码,但是惟一有 些不同的是,你可以在批注中加上动态的表达式(如上例所示)。

● 开发程序员专用的批注:

<%-- comment --%>

或者

<% /** this is a comment **/ %>

接下来看下面这个范例:

<%@ page language="java" %>

<html>

<head><title>A Comment Test</title></head>

<body>

<h2>A Test of Comments</h2>

<%-- 这个批注不会显示在客户端 --%>

</body>

</html>

从用户的浏览器中,看到的源代码如下:

<html>

<head><title>A Comment Test</title></head>

<body>

(55)

<h2>A Test of Comments</h2>

</body>

</html>

之前加上去的批注在客户端的浏览器上看不出来,并且用此批注的方式,在 JSP 编译时会被忽 略掉。这对隐藏或批注 JSP 程序是实用的方法,通常程序员也会利用它来调试(Debug)程序。

JSP Container 不会对 <%--和--%>之间的语句进行编译,它不会显示在客户端的浏览器上,也 无法从源文件中看到。接下来介绍 Quoting 和 Escape 的规则。

4-3 Quoting 和 Escape 规则

Quoting 主要是为了避免与语法产生混淆所使用的转换功能,和 HTML 的标签语法类似,JSP 是 以<%标签作为程序的起始、%>标签作为程序的结束,所以当你在 JSP 程序中要加上 <%或是%>这 些符号时,应该这么做:

Quoting.jsp

<%@ page contentType="text/html;charset=GB2312 " %>

<html>

<head>

<title>CH4 - Quoting.jsp</title>

</head>

<body>

<h2>Quoting 范例程序</h2>

(56)

<%

out.println("JSP 以%>作为结束符号");

%>

</body>

</html>

程序执行时,JSP 在执行到 %>时,JSP Container 就直接告诉你程序有错误,如图 4-1 所示:

图 4-1 Quoting.jsp 的执行结果

通常为了避免产生这样的结果,因此程序中遇到显示%>时,要改写为%\>,所以上面的程序代码 应改写为:

Quoting1.jsp

<%@ page contentType="text/html;charset=GB2312" %>

(57)

<html>

<head>

<title>CH4 - Quoting1.jsp</title>

</head>

<body>

<h2>Quoting 范例程序 2</h2>

<%

out.println("JSP 以%\>作为结束符号");

%>

</body>

</html>

Quoting1.jsp 的执行结果如图 4-2 所示:

图 4-2 Quoting1.jsp 的执行结果

(58)

单引号 ' 改为 \' 双引号 " 改为 \"

斜线 \ 改为 \\

起始标签 <% 改为 &lt;%

结束标签 %> 改为 %\>

最后再举个例子,如下:

Quoting2.jsp

<%@ page contentType="text/html;charset=GB2312" %>

<html>

<head>

<title>CH4 - Quoting2.jsp</title>

</head>

<body>

<h2>Quoting 范例程序 3</h2>

<%

out.println("JSP 遇到 \'、\"、\\、&lt;%、%\> 时需要做适当的修改");

%>

(59)

</body>

</html>

执行的结果如图 4-3 所示:

图 4-3 Quoting2.jsp 的执行结果

4-4 Directives Elements(1)

指令(Directives)主要用来提供整个 JSP 网页相关的信息,并且用来设定 JSP 网页的相关属性,

例如:网页的编码方式、语法、信息等。

起始符号为: <%@

终止符号为: %>

内文部分就是一些指令和一连串的属性设定,如下所示:

<%@ directive { attribute ="value" } * %>

什么叫做一连串的属性设定?举例来说,当我们设定两个属性时,可以将之合二为一,如下:

<%@ directive attribute1 = "value1" %>

<%@ directive attribute2 = "value2" %>

亦可以写成:

數據

表 5-3 列出了一般储存和取得属性的方法,以下 pageContext、request、session 和 application 皆可使用。
表 5-8  设定响应状态码的方法
表 5-10  HTTP/1.1 Cache-Control 标头的设定参数
表 5-13  javax.servlet.ServletContext 接口容器相关信息的方法
+4

參考文獻

相關文件

請問下列的

有關於 Java 程式語言,下列何者敘述不正確?(A)Java 程式語言透過 extends 提供多重繼承 (Multiple

JRE (Java Runtime Environment): for users, JVM + basic libraries JDK (Java Development Kit): JRE + compilers + ... —jdk-6u12-windows-i586-p.exe or other platform

• Instead, static nested classes do not have access to other instance members of the enclosing class. • We use nested classes when it

• Instead, static nested classes do not have access to other instance members of the enclosing class. • We use nested classes when it

• Non-static nested classes, aka inner classes, have access to other members of the enclosing class, even if they are declared private. • Instead, static nested classes do not

The client’s web browser sends a request to the server for a web page that runs a Java servlet.

Windows/ Linux/ Mac 各種平台的開發套件,使我們能夠透過各種平台來開發 Android 軟體,所有的 Android 應用程式都是使用 Java