1. 动态网页和静态网页有什么区别?
2. 什么是Web应用程序?
3. 什么是Servlet,和一般Java程序有什么区别?
4. 什么是JSP,和Java是什么关系?
5. JSP和Servlet有哪些异同点?
6. JSP和Servlet的主要用途?
10.1 Servlet的概念、配置与运行
10.1.1 Java Servlet的概念
Java Servlet是一个专门用于编写网络服务器应用程序的Java组件。所有基于Java的服务器端编程都是构建在Servlet之上的。在J2EE中Servlet已经是一个标准的组件。
在J2EE中跟Servlet相关的一个包是javax.servlet,其中最基本的Servlet被声明为一个接口javax.servlet: Interface Servlet,这是Servlet最高层次的一个抽象,它是和网络协议无关的。同样在javax.servlet中,实现了一个类 javax.servlet: class GenericServlet,这个类实现了Servlet接口,也是和协议无关的。而这个类是构建其他和协议相关的Servlet子类型的通用的父类(至少HttpServlet是从它继承而来的,从它的名字也能看出这一点)。
也就是说Servlet所适用的网络协议可以是多种多样的,比如HTTP,FTP,SMTP,TELNET等,但是就目前而言,只有HTTP服务已经形成了标准的Java组件。对应的软件包有两个javax.servlet.http和javax.servlet.jsp,分别对应我们要讲解的Servlet和JSP编程。我们通常所说的Servlet编程主要就是指针对HTTP的Servlet编程,用到的就是javax.servlet.http包中的类(典型的就是HttpServlet类),实际上Java Servlet编程的概念要更广一些,在这里我们也就约定俗成的使用Servlet来指代HTTP Servlet的编程,这点读者是需要了解的。由于JSP最终都是要经过JSP引擎转换成Servlet代码的,而且Servlet编程和一般的Java编程是没有大的区别的,只需要了解一定的规范即可,所以我们在这里先讲解Servlet的编程,这样对以后理解JSP是很大的有好处的,尽管在使用的时候可能JSP更为简单一些。
目前,Servlet引擎一般是第三方的插件,它通过一定的方法连接到Web服务器,Servlet引擎把它识别为Servlet请求的那些HTTP请求截获下来处理,而其他的HTTP请求由Web服务器按照通常的方式来处理,Servlet引擎会装载合适的Servlet到内存中,如果Servlet还没有运行的话,会分配一个可以使用的线程来处理请求,再把Servlet的输出返回到发出请求的Web客户机。
Java Servlet和Java Applet正好是相对应的两种程序类型,Applet运行在客户端,在浏览器内执行,而Servlet在服务器内部运行,通过客户端提交的请求启动运行,读者在学习过程可以作简单的比较。
由于Servlet是用Java编写的,所以它与生俱来就有跨平台的特性,因此Servlet程序的设计完全和平台是无关的,同样的Servlet完全可以在Apache,IIS等不同Web服务器上执行,不管底层的操作系统是Windows,Solaris,Mac,Linux还是其他的能支持Java的操作系统。
Servlet是跟普通的Java程序一样,是被编译成字节码后由JVM执行的。相比传统的CGI,尽管CGI是用本地代码直接执行的,但是由于每次客户端发出请求,服务器必须启动一个新的程序来处理请求,这就把高负载强加给了服务器资源,尤其如果CGI使用脚本语言编写时,如perl,服务器还必须启动语言解释程序,程序越多,占用的内存就越多,消耗CPU也越多,严重影响系统性能。
Servlet运行于Servlet引擎管理的Java虚拟机中,被来自客户机的请求所唤醒,与CGI不同的是,在虚拟机中只要装载一个Servlet就能够处理新的请求,每个新请求使用内存中那个Servlet的相同副本,所以效率比CGI来得高。如果采用服务器端脚本,如ASP,PHP,语言解释程序是内置程序,因此可以加快服务器的运行,但是效率还是比不上准编译的Servlet。实际的使用也已经证明,Servlet是效率很高的服务器端程序,很适合用来开发Web服务器应用程序。
Java Servlet有着十分广泛的应用。不光能简单的处理客户端的请求,借助Java的强大的功能,使用Servlet还可以实现大量的服务器端的管理维护功能,以及各种特殊的任务,比如,并发处理多个请求,转送请求,代理等
10.1.3 Servlet的运行环境
典型的Servlet运行环境有JSWDK,Tomcat,Resin等,这几个都是免费的软件,适合用来学习Servlet和JSP。它们都自带一个简单的HTTP Server,只需简单配置即可投入使用,你也可以把它们绑定到常用的Web服务器上,如Apache,IIS等,提供小规模的Web服务。还有一些商业的大中型的支持Servlet和JSP的Web服务器,如JRun,Web Sphere,Web Logic等等,配置比较复杂,并不适合初学者。但是功能较为强大,有条件的读者可以一试。
10.1.7 Servlet的编译
Servlet的编译和一般的Java程序是完全一样的,在使用javac编译的时候不需要任何特殊的参数。只要Servlet的编写是正确的,编译完后生成的Class文件就可以做为Servlet来运行了。
简单示例:
import java.io.*;
import java.util.*;
import javax.servlet.http.*;
import javax.servlet.*;
//导入必要的包
public class HelloServlet extends HttpServlet {
//所有Servlet必须从HttpServlet派生
public void doGet (HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
//doGet()是这个Servlet的核心,真正处理请求的地方
{
res.setContentType("text/html");
//设置相应的类型为text/html
PrintWriter pw = res.getWriter();
//从HttpServletResponse得到输出流
pw.println("<!DOCTYPE HTML PUBLIC /"-//W3C//DTD HTML 4.0 Transitional//EN/">");
pw.println("<head>");
pw.println("<meta http-equiv=/"Content-Type/" content=/"text/html; charset=ISO-8859-1/">");
pw.println("<!-- The Servlet expression tags interpolate script variables into the HTML -->");
pw.println("<title>Hello, world!</title>");
pw.println("</head>");
pw.println("<body bgcolor=#cc99dd>");
pw.println("<h1>Hello, world!</h1>");
pw.println("</body>");
//上面的语句都是向客户端打印HTML文本
pw.close();
//关闭HttpServletResponse,使Web服务器知道相应结束
}
public HelloServlet() {} //构造函数,可以不要
}
10.2.1 Servlet与表单交互的方法
表单是HTML中使用最广泛的传递信息的手段。搞清楚Servlet与表单的交互,就在客户端与服务器之间架起了一座桥梁。Servlet使用HttpServlet类中的方法与表单进行交互。在HttpServlet类中有几个未完全实现的方法,你可以自己定义方法的内容,但是必须正确使用方法名称以使HTTP Server把客户请求正确的映射到相应的函数上。
doHeader 用于处理HEADER请求
doGet 用于处理GET请求,也可以自动的支持HEADER请求
doPost 用于处理POST请求
doPut 用于处理PUT请求
doDelete 用于处理DELETE请求
HttpServlet的Service方法,当它接收到一个OPTIONS请求时,它会自动调用doOptions方法,当接收到一个TRACE请求时调用doTrace。DoOptions默认执行方式是自动决定什么样的HTTP被选择并返回哪个信息。
在使用这些方法时必须带两个参数。第一个包含来自客户端的数据HttpServletRequest。第二个参数包含客户端的相应HttpServletResponse。
一个HttpServletRequest对象提供请求HTTP头部数据,也允许获取客户端的数据。怎样获取这些数据取决于HTTP请求方法。
不管何种HTTP方式,都可以用getParameterValues方法返回特定名称的参数值。
(HttpServletRequest,HttpServletResponse接口分别继承于ServletRequest和ServletResponse接口,getParameterValues和getWriter方法都是其祖先接口中的方法)
对于HTTP GET请求的方式,getQueryString方法将会返回一个可以用来解剖分析的参数值。
对于用HTTP POST,PUT和DELETE请求的方式,HttpServletRequest有两种方法可以选择:如果是文本数据,你能通过getReader的方法得到BufferedReader获取数据;如果是二进制数据,可以通过getInputStream方法得到ServletInputStream获取数据。
为了相应客户端,一个HttpServletResponse对象提供返回数据给用户的两个方法:一种是用getWriter方法得到一个PrintWriter,用于返回文本数据;另一种方法是用getOutputStream方法得到ServletOutputStream,用于返回二进制数据。在使用Writer或OutputStream之前应先设置头部(HttpServletResponse中有相应的方法),然后用Writer或OutputStream将相应的主体部分发给用户。完成后要关闭Writer或OutputStream以便让服务器知道相应已经结束。
例:PrintWriter out = response.getWriter();
out.println("Request URI: " + request.getRequestURI()+"<br>");
我们知道在同一台机器上,所有的编码方式都是一样的,一般中文平台是gb2312,英文平台是ISO-8859-1,但是网络上的两台机器并不能保证他们的编码方式都是一样的,这时候就有可能出现乱码的问题。在进行HTTP网络传输的时候,统一采用的编码方式是ISO-8859-1,这时候如果还是按照本地编码来传输就会出现问题,这也是Servlet在实现网络传输的时候一个不完美的地方,它不会自动进行本地编码到ISO-8859-1的转换,所以直接打印的话就会出现乱码。原理上讲任何出现打印字符串的地方,都是需要进行编码转换的,但是西文字符在不同字符集下对应相同的编码,以在打印西文字符的时候就不需要转换了。在Servlet后继的规范中可能会改变这种麻烦的状况。不同的是,从网络提交的表单数据,Servlet是自动把它转换成本地编码的,所以程序中得到的name字符串变量是gb2312编码的,同样需要进行转换后才能在客户端正确打印。
字符编码转换常用的方法是
String native_encoded = "中文字符串";
//本地编码的字符串
Byte[] byte_array = native_encoded.getBytes();
//得到本地编码的字节数组
String net_encoded = new String(native_encoded, "ISO-8859-1");
//生成ISO-8859-1编码的字符串
例:out.println(new String(new String("<td>你的姓名:</td>").getBytes(),"ISO-8859-1"));
10.2.3 用Servlet控制会话
会话状态的维持是开发Web应用所必须面对的问题,有多种方法可以来解决这个问题,如使用Cookies,hidden类型的表单域,或直接把状态信息加到URL中等,还有Servlet本身提供了一个HttpSession接口来支持会话状态的维持,在这里我们主要介绍基于这个接口的会话状态的管理。
Session的发明是为了填补HTTP协议的局限。请注意HTTP协议是如何工作的--用户发出请求,服务器作出响应,这种用户端和服务器端的联系就是离散的,非连续的。HTTP协议不能提供允许服务器跟踪用户请求的功能。在服务器端完成响应用户的请求之后,服务器不能继续与该浏览器继续保持连接。从服务器这端来看,每一个请求都是独立的,因此HTTP协议被认为是无状态协议,当用户在多个主页间切换时,服务器无法知道他的身份。Session的出现就是为了弥补这个局限。利用Session,您就可以当一个用户在多个主页间切换的时候也能保存他的信息。这样很多以前根本无法去做的事情就变得简单多了。
在访问者从到达某个特定的主页到离开为止的那段时间,每个访问者都会单独获得一个Session。
Java Servlet定义了一个HttpSession接口,实现的Session的功能,在Servlet中使用Session的过程如下:
(1) 使用HttpServletRequest的getSession方法得到当前存在的session,如果当前没有定义session,则创建一个新的session,还可以使用方法getSession(true)
(2) 写session变量。可以使用方法HttpSession.setAttribute(name,value)来向Session中存储一个信息。也可以使用HttpSession.putValue(name,value),但这个方法已经过时了。
(3) 读Session变量。可以使用方法HttpSession.getAttribute(name)来读取Session中的一个变量值,如果name是一个没有定义的变量,那么返回的是null。需要注意的是,从getAttribute读出的变量类型是Object,必须使用强制类型转换,比如:
String uid = (String) session.getAttribute("uid");
也可以使用HttpSession.getValue(name),但是这个方法也已经过时了。
(4) 关闭session,当时用完session后,可以使用session.invalidate()方法关闭session。但是这并不是严格要求的。因为,Servlet引擎在一段时间之后,自动关闭seesion。
HttpSession session = request.getSession(true);
//参数true是指在没有session时创建一个新的
Date created = new Date(session.getCreationTime());
//得到session对象创建的时间
out.println("ID " + session.getId()+"<br>");
//得到该session的id,并打印
out.println("Created: " + created+"<br>");
//打印session创建时间
session.setAttribute("UID","12345678");
//在session中添加变量UID=12345678
session.setAttribute("Name","Tom");
//在session中添加变量Name=Tom
10.2.4 Servlet的生命周期
跟客户端的Applet相似,Servlet(这里Servlet的概念又回到了最原始的含义)也遵循严格的生命周期。在每个Servlet实例的生命中有三种类型的事件,这三种事件分别对应于由Servlet引擎所唤醒的三个方法:
1.init()。当Servlet第一次被装载时,Servlet引擎调用这个Servlet的init()方法,只调用一次。如果某个Sevlet需要特殊的初始化需要。那么Servlet编写人员可以重写该方法来执行初始化任务。这是一个可选的方法。如果某个Servlet不需要初始化,那么默认情况下将调用它父类的init方法。系统保证,在init方法成功完成以前,是不会调用Servlet去处理任何请求的。
2.service()。这是Servlet最重要的方法,是真正处理请求的地方。对于每个请求,Servlet引擎将调用Servlet的service方法,并把Servlet请求对象和Servlet响应对象最为参数传递给它。
3.destroy()。这是相对于init的可选方法,当Servlet即将被卸载时由Servlet引擎来调用,这个方法用来清除并释放在init方法中所分配的资源。
Servlet的生命周期可以被归纳为以下几步:
(1) 装载Servlet,这一项操作一般是动态执行的。然而,Servlet通常会提供一个管理的选项,用于在Servlet启动时强制装载和初始化特定的Servlet
(2) Server创建一个Servlet实例
(3) Server调用Servlet的init方法
(4) 一个客户端请求到达Server
(5) Server创建一个请求对象
(6) Server创建一个响应对象
(7) Server激活Servlet的service方法,传递请求和响应对象作为参数
(8) service方法获得关于请求对象的信息,处理请求,访问其他资源,获得需要的信息
(9) service方法使用响应对象的方法。将响应传回Server,最终到达客户端。Service方法可能激活其他方法以处理请求。如doGet,doPost或其他程序员自己开发的方法
(10) 对于更多的客户端请求,Server创建新的请求和响应对象,仍然激活此servlet的service方法,将这两个对象作为参数传递给它,如此重复以上的循环,但无需再次调用init方法,Servlet一般只初始化一次
(11) 当Server不再需要Servlet时,比如当Server要关闭时,Server调用Servlet的destroy
10.3 JSP简介
10.3.1 JSP的概念
JSP(Java Server Pages?)是Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。它在HTML代码中,插入JSP标记(tag)及Java程序片段 (Scriptlet), 构成JSP页面,其扩展名为 .jsp。当客户端请求JSP文件时,Web服务器执行该JSP文件,然后以HTML的格式返回给客户。前面已经提到过JSP只是构建在Servlet之上的高层次的动态网页标准,因此,从概念上将,相对Servlet而言,JSP并没有什么新的东西,如果读者对前面的Servlet已经十分的了解,那么JSP的概念可说跟Servlet是完全一样的,只不过在实现方法上稍有不同。
10.3.2 JSP的优点
1. 一次编译,多次、多处运行,代码的执行效率高
JSP的脚本语言是JAVA语言,因此它具有JAVA语言的一切特性。同时,JSP也支持现在大部分平台。 当JSP第一次被请求时,JSP页面转换成servlet,然后被编译成.calss文件,以后(除非页面有改动或Web服务器被重新启动)再有客户请求该JSP页面时,JSP页面不被重新编译,而是直接执行已编译好的.class文件,因此执行效率特别高。
2. 组件的重用性
可重用的、跨平台的JavaBeans和EJB(Enterprise JavaBeans)组件,为JSP程序的开发提供方便,我们可以将复杂的处理程序(如页面中需要显示的动态内容及对数据库的操作)放到组件中。可以多次使用这些组件,极大的减少了在JSP页面中重写重复的代码。
3. 将内容的生成和显示进行分离
使用JSP技术,Web页面开发人员可以使用HTML或者XML标识来设计和格式化最终页面。使用JSP标识或者脚本来生成页面上的动态内容。生成动态内容的语句一般被封装在JavaBean组件、EJB组件或JSP脚本段中。这样,页面的设计人员和页面的编程人员可以同步进行。同时在客户端通过查看源文件,看不到JSP标识的语句,更看不到JavaBean和EJB组件,也可以保护源程序的代码。
10.3.3 JSP的运行方式
JSP一般的运行方式为:当服务器启动后,当Web浏览器端发送过来一个页面请求时,Web服务器先判断是否是JSP页面请求。如果该页面只是一般的HTML/XML页面请求,则直接将HTML/XML页面代码传给Web浏览器端。如果请求的页面是JSP页面,则由JSP引擎检查该JSP页面,如果该页面是第一次被请求、或不是第一次被请求但已被修改,则JSP引擎将此JSP页面代码转换成Servlet代码,然后JSP引擎调用服务器端的Java编译器javac.exe对Servlet代码进行编译,把它变成字节码(.class)文件,然后再调用JAVA虚拟机执行该字节码文件,然后将执行结果传给Web浏览器端。如果该JSP页面不是第一次被请求,且没有被修改过,则直接由JSP引擎调用JAVA虚拟机执行已编译过的字节码.class文件,然后将结果传送Web浏览器端。上面是一张JSP运行的示意图。
(例如:在resin服务器中,将一个add.jsp文件放在doc/目录下,当在浏览器中参看该页面时http://127.0.0.1:8080/add.jsp 。系统会在doc/WEB-INF/work/_jsp目录下生成_add__jsp.class, _add__jsp.java,_add__jsp.java.smap三个文件。)
从这里我们已经不难看出JSP和Servlet的关系,JSP引擎负责把JSP页面翻译成Servlet,因此JSP在底层完全就是Servlet(指原始概念上的Servlet,而不是HttpServlet)。前面我们提到JSP编程对应javax.servlet.jsp,更确切的讲,这个包是供JSP引擎使用的,它在做翻译的时候需要用到这个包,我们在编写JSP页面的时候是不需要涉及这个包的使用的。
为什么有了Servlet还要在高层实现一个JSP呢?这个问题跟Servlet本身编写的烦杂程度有关,如果用Servlet来控制页面外观的话,将是一件十分头疼的事情,使用JSP就把烦杂的打印任务交给了JSP引擎,程序员可以把精力集中到逻辑控制上面。在后面还会有进一步的比较。
10.3.8 JSP指令(1)
下面我们开始讲解JSP的语法。从本质上讲JSP还是Java程序,因为它最终还是会被翻译成Servlet进而编译成class文件执行。但是由于JSP是嵌入式的Java程序,有些特殊的符号还是需要学习的。下面我们一一列举,读者不必深究,多使用之后就会熟悉。
1.HTML注释
该注释在客户端可通过查看源文件的方法看到。
JSP语法:<!--注释[ <%= 表达式%> ] -->
例1
<!-- This file displays the user login screen -->
在客户端页面源程序中显示为:
<!-- This file displays the user login screen -->
例2
<!-页面调用日期为:
<%= (new java.util.Date()).toLocaleString() %> -->
在客户端页面源程序中显示为:
<!--页面调用日期为:January 1, 2000 -->
描述
可以在注释中使用任何有效的JSP表达式。表达式是动态的,当用户第一次调用该页面或该页面后来被重新调用时,该表达式将被赋值。JSP引擎对HTML注释中的表达式执行完后,其执行的结果将直接插入到表达式显示的地方。然后该结果和HTML注释中的其它内容一起输出到客户端。<!-- … -->之间的内容在浏览器上是看不到,但可以在客户端可通过查看源文件的方法看到该注释。
2.JSP注释
JSP注释作为JSP页面的文档资料,但是该注释在客户端通过查看源文件的方法是看不到的。即该注释不发送到客户端。
JSP语法:<%-- 注释 --%>
注意:在JSP注释中,不能使用--%>,但是如果你一定要使用的话,可以通过使用--%/>来避开。
3. 声明
在JSP页面脚本语言中声明变量或方法
JSP语法:<%! 声明;[声明;]+…… %>
例子
<%! int i =8; %>
<%! int n, m, k,j; %>
<%! String s = new String("hello"); %>
描述
在JSP文件中,一次可以声明一个或多个变量和方法,它们之间用分号隔开。在声明时使用JAVA语言时,必须符合JAVA语言规范。
注意:
(i) 变量必须先声明,然后才能使用。
(ii) 声明必须以分号结尾,但是在表达式中则不用。
(iii) 通过page指令导入的包中已声明的变量或方法,可以在主JSP文件中直接使用它们。
(iv) 一般情况下,一个声明的有效范围是本页面。但是,如果JSP源文件用<jsp:include>指令或include指令包含一些静态文件,声明的有效范围将会扩大,也就是说:声明在该静态文件中也有效。但是如果JSP源文件中用<jsp:include>指令包含进来一个动态文件,主JSP文件中的声明在该动态文件中将不起作用。
4. 表达式
在JSP脚本语言中,可以使用任何有效的表达式。
JSP语法:<%= 表达式 %>
例子1:
<%! String s = new String("hello"); %>
<font color="blue"><%=s%></font>
例子2:
随机显示一个数字:
<font color="blue"><%=java.lang.Math.random()%></font>
描述
表达式用于求值,然后其值转化为字符串,而且插入在JSP文件中显示该表达式的地方。而且可以在文本中使用表达式。表达式标签能包含符合JAVA语言规范的任何有效表达式,但是要注意:不能使用分号作为表达式的结尾,然而,在脚本段<%……%>标签中,表达式要求以分号作为结尾。
5. 脚本段
在JSP页面脚本语言中,包含一段有效的代码片段。
JSP语法:<% 代码段 %>
例1:
<%=java.lang.Math.random()%>
<%
for(int i=0;i<8;i++)
{ out.println(i); }
%>
<%
long n=6666;
application.setAttribute("maxNumber",Long.toString(n));
out.println(application.getAttribute("maxNumber"));
%>
描述
在脚本段能声明多个变量和方法。能使用任何有效的表达式。能使用任何JSP隐含的对象或任何用<jsp:useBean>标签声明的对象。能使用页面语言中任何有效的语句,如果使用Java语言,必须符合JAVA语言程序规范。
说明:假如脚本段有输出语句,则输出内容被存储在out对象中,通过out对象输出到JSP页面中。
10.3.8 JSP指令(2)
1.Include指令
该指令用于包含一个文本或代码的文件。
JSP语法:<%@ include file="relativeURL"%>
例子:
<body >
random.jsp中的随机显示的数为:
<%@ include file="random.jsp" %>
</body>
random.jsp文件中内容为:
<%=java.lang.Math.random()*10000%>
在页面中显示为:
random.jsp中的随机显示的数为: 2148.093521070482
描述
Include指令在JSP文件中插入一个包含文本和代码的文件。被包含的文件可以是JSP文件,HTML文件或文本文件。如果被包含的文件是JSP文件,则JSP引擎编译完该JSP文件后,执行的结果将插入到主JSP文件中Include指令所在的位置。如果被包含的文件是HTML文件或文本文件,则JSP引擎不对其进行编译,直接将其内容插入到主JSP文件中Include指令所在的位置。该包含是静态包含,即被包含的文件处理完,而且结果也插入到主JSP文件完毕,主JSP文件将继续执行include指令下面的内容。
注意:
(1)被包含的文件中不能含有<html>,</html>,<body>,或</body>标签。因为被包含的文件的全部内容将被插入到JSP文件中include指令所在的地方,这些标签将会同JSP文件中已有的同样的标签发生冲突。
(2)假如被包含的文件发声变化,主JSP页面将被重新编译。
属性:
file="relativeURL"
file是被包含文件的路径名。 其值是一个URL的一部分,没有协议、端口号或域名. 如:
"error.jsp"
"/templates/onlinestore.html"
"/beans/calendar.jsp"
如果相对URL以"/"开始,这个路径是相对于JSP应用上下文而言的,JSP应用上下文是存储在application对象中的javax.servlet.ServletContext对象。如果相对URL以目录或文件名开始,这个路径是相对于当前JSP文件所在的路径而言的。
2. Page 指令
定义整个JSP页面的全局属性。
JSP语法:
<%@ page
[ language="java"]
[ extends="package.class"]
[ import= "{ package.class | package.* }, ..." ]
[ session="true|false" ]
[ buffer="none|8kb|sizekb" ]
[ autoFlush="true|false" ]
[ isThreadSafe="true|false" ]
[ info="text"]
[ errorPage="relativeURL"]
[ contentType="mimeType [ ;charset=characterSet ]" |
"text/html ; charset=ISO-8859-1" ]
[ isErrorPage="true|false"] %>
例:
<%@ page contentType="text/html;charset=gb2312" %>
<%@ page import="java.sql.*, java.lang.*" %>
<%@ page buffer="8kb" autoFlush="false" %>
<%@ page errorPage="error.jsp" %>
描述:
Page指令的作用范围是整个JSP文件和该JSP文件用include指令或<jsp:include>包含进来的任何静态文件,整个JSP文件和这些静态文件一起叫做一个"平移单元". 注意:Page指令不适用于任何动态的包含文件。你可以在一个"平移单元"使用多个Page指令。但是每一个属性你只能使用一次,除了import(因为import属性和JAVA程序语言的import语句很类似,你能够多次使用它,就象在JAVA语言中你能够多次使用import命令一样)。不论你将Page指令放到JSP文件或被包含的文件的任何一个位置,它的作用范围都是整个"平移单元".然而,一个好的编成风格是常常将它放到文件的顶部.
language="java"
在JSP文件的脚本段、声明和表达式中使用的语言。现只允许用"JAVA"。
extends="package.class"
该属性用于指明JAVA类文件超类全名。使用该属性时要小心,因为,它会限制JSP引擎编译文件的能力。
import= "{ package.class | package.* }, ..."
JSP文件中导入的一个或多个用逗号隔开的包的列表。这些包(和它们的类)可以在JSP文件的脚本段、表达式、声明和标签中使用。你必须将import属性放到调用被到入的类的标签前面。如果你想导入多个包,你可以在import后面用逗号将每个包隔开即可,或你可以在一个JSP文件中使用多个import.
session="true|false"
该属性用于确定JSP页面是否使用HTTP session.假如这个值是true, 则sesssion引用的是当前或新的session. 假如这个值是false,则在JSP文件中,不能使用session对象。默认值是true.
buffer="none|8kb|sizekb"
设置buffer缓冲区的大小,当out对象将被编译的JSP页面向客户Web浏览器端输出时使用。它的默认值是8kb.假如你指定了buffer缓冲区的大小,这个输出量将不低于你指定的大小。
autoFlush="true|false"
该属性指出:当缓冲区充满时,是否自动刷新。如果值为true(默认值为true),则自动刷新。如果值为false,则当缓冲区溢出时,将会产生错误。而且如果buffer属性的值设为none,autoFlush属性的值不能设为false.
isThreadSafe="true|false"
假设这个值设为true,多个线程能同时访问一个JSP页面。假如这个值为false,对一个JSP页面,JSP引擎一次只能响应一个用户的请求。默认值为true。
info="text"
关于作者、版本和著作权等信息,可以通过javax.sevlet.Servlet.getServletInfo()方法查到该信息的详细情况。
errorPage="relativeURL"
该属性用于设置处理例外事件的JSP文件的路径名。假如这个路径名以"/"开始,则这个路径名是JSP应用文档根目录而言的,而且由Web服务器决定。否则,这个路径是相对于当前JSP文件而言的。
isErrorPage="true|false"
JSP文件是否显示错误页面。 如果这个值为true,你可以使用例外exception对象。如果这个值为false(默认值也为false),在JSP文件中,不能使用exception对象。
contentType="mimeType [ ;charset =characterSet ]" |
"text/html;charset=ISO-8859-1"
JSP文件中使用的MIME type和character encoding(字符编码)是用于响应客户端的请求。你可以使用JSP引擎中有效的任何MIME type或character set(字符集).默认的MIME type是text/html,而且默认的字符集合是ISO-8859-1。
3.<jsp:forward>元素
将客户端的请求转交给一个HTML文件、JSP文件或脚本段处理。
JSP语法:<jsp:forward page="{ relativeURL | <%= expression %> }" />
例子:
<jsp:forward page="/dong/hello.jsp" />
描述:
<jsp:forward>标签将请求对象从一个JSP文件转交给另一个文件处理。
特别注意:JSP引擎对主JSP页面<jsp:forward>下面的代码不再执行。
说明:如果JSP文件的输出被设置为缓冲输出(即使用默认的Page指令值或直接设置缓冲区的buffer大小),则在请求被转交之前,缓冲区被清空。如果输出被设置为非缓冲输出(即用Page指令设置buffer=none),而且输出区中已经有内容,则使用<jsp:forward>元素,将会导致非法例外。
属性
page="{ relativeURL | <%= expression %> }"
该属性用于设置将要转交的文件的相关URL.
该URL不能包含协议名、端口号或域名,相对于当前JSP文件来说的。如果它是绝对地址(以"/"开始),该路径由你的Web或应用服务器决定。
4.<jsp:getProperty>
取得Bean属性的值,以便在结果页面中显示。
JSP语法:<jsp:getProperty name="beanInstanceName" property="propertyName"/>
例:
Bean的程序代码为:
package AccessDatabase;
public class Readdate
{
private String username="changcheng";
public String void getUsername(){return username; }
}
JSP文件的内容为:
<html><body>
<jsp:useBean id="init" scope="page" class="AccessDatabase.readdate" />
从Bean中取得属性名为username的值为:
<jsp:getProperty name=" init " property="username" />
</body></html>
执行后显示结果为:
从Bean中取得属性名为user的值为:changcheng
描述:
在使用<jsp:getProperty>前,你必须使<jsp:useBean>元素创建或调用一个Bean实例。<jsp:getProperty>标签是用于取得JavaBeans属性值,相当于调用Bean中的某个属性的getXXX()方法。
属性:
name="beanInstanceName"
在<jsp:useBean>标签中声明的Bean实例的名字。
property="propertyName"
Bean属性的名字。
说明:使用<jsp:getProperty>元素时如上例中:<jsp:getProperty name=" init " property="username" />,username必须是Bean(Readdate)中的属性,且该Bean中要有getUsername()方法,否则编译时会出错。
5.<jsp:include>
在JSP文件中,包含一个静态或动态文件.
JSP语法<jsp:include page="{ relativeURL | <%= expression %>}" flush="true" />
例子:
<jsp:include page="jsp/dadi.jsp" />
<jsp:include page="hello.html" />
<jsp:include page="/index.html" />
属性:
<jsp:include>标签允许你包含一个静态文件或动态文件。一个静态文件被执行后,它的内容插入在主JSP页面中。一个动态文件对请求作出响应,而且将执行结果插入到JSP页面中。
<jsp:include>标签能处理两种文件类型,当你不知道这个文件是静态或动态的文件时,使用该标签是非常方便的。
当include动作执行完毕后,JSP引擎将接着执行JSP文件剩下的文件代码。
page="{ relativeURL | <%= expression %>}"
该属性指出被包含文件相关URL;该URL不能包含协议名、端口号或域名。该URL是绝对或相对于当前JSP文件来说的。如果它是绝对地址(以"/"开始),该路径由你的Web或应用服务器决定
flush="true"
在JSP文件中,常设置flush="true",因为它不是一个默认值。
6. <jsp:plugin>
下载一个plugin插件到客户端以便执行applet或Bean
JSP语法:
<jsp:plugin
type="bean|applet"
code="classFileName"
codebase="classFileDirectoryName"
[ name="instanceName"]
[ archive="URIToArchive, ..." ]
[ align="bottom|top|middle|left|right" ]
[ height="displayPixels"]
[ width="displayPixels"]
[ hspace="leftRightPixels"]
[ vspace="topBottomPixels"]
[ jreversion="JREVersionNumber | 1.1"]
[ nspluginurl="URLToPlugin"]
[ iepluginurl="URLToPlugin"]>
[ <jsp:params>
[ <jsp:param name="parameterName" value="parameterValue"/>]+
</jsp:params> ]
[ <jsp:fallback> text message for user </jsp:fallback> ]
</jsp:plugin>
例子:
<jsp:plugin type=applet code="Molecule.class" codebase="/html">
<jsp:params>
<jsp:param name="molecule" value="molecules/benzene.mol" />
</jsp:params>
<jsp:fallback>
<p>Unable to load applet</p>
</jsp:fallback>
</jsp:plugin>
<jsp:params>
<jsp:params>元素在计算机启动时,给applet或Bean传递参数及其值。如果plugin没有启动,〈jsp:fallback>元素将给使用者提供一条信息。如果plugin启动了但是applet或Bean没有启动,plugin常常弹出一个window窗口,该用户解释出错的原因。
属性:
type="bean|applet"
plugin将执行的对象的类型。你必须指定Bean或applet,因为这个属性没有默认值。
code="classFileName"
plugin将执行的JAVA类文件的名字。在文件名后面必须跟上.class扩展名。文件名是相对于codebase属性中命名的目录。
codebase="classFileDirectoryName"
包含applet代码的目录名的相对或绝对地址。如果没有提供该值,调用<jsp:plugin>的JSP文件的路径将被使用。
name="instanceName"
Bean或applet实例的名字,相同的JSP文件通过它可以相互通信。
archive="URIToArchive, ..."
一个用逗号隔开的路径列表,该路径列表指出用类装载器装载的类文件的位置。类装载器是位于codebase属性中命名的目录。
align="bottom|top|middle|left|right"
applet或Bean中显示的图象的位置是相对于JSP结果页面中的这样的行来说的,该行是JSP文件中包含<jsp:plugin>的行。不同值的显示结果如下:
bottom使图象的底部与下一文本行的基线对齐。
Top使图象的顶部与下一文本行的顶部对齐。
Middle使图象的垂直中心与下一文本行的基线对齐。
Left使图象左对齐.
Right使图象右对齐.
height="displayPixels" width="displayPixels"
applet或Bean以像素为单位显示的初始高度和宽度,不包括applet或Bean弹出的任何窗口和对话框.
hspace="leftRightPixels" vspace="topBottomPixels"
applet或Bean以像素为单位显示的图象的左右(或上下)之间间距的大小。一般是一个非常小的非零值。
jreversion="JREVersionNumber|1.1"
applet或Bean要求的JAVA运行时环境(JRE)的版本。默认的值是1.1
nspluginurl="URLToPlugin"
用户使用Netscape Navigator浏览器时需下载JRE插件的URL。它是完整的URL地址,有协议名、端口号和域名。
iepluginurl="URLToPlugin"
用户使用Internet Explorer浏览器时需下载JRE插件的URL.它是完整的URL地址,有协议名、端口号和域名。
<jsp:params>[ <jsp:param name="parameterName" value="parameterValue"/>]+</jsp:params>
传递给applet或Bean的参数和值。为了传递多个参数和值,你可以在〈jsp:params>元素中使用多个<jsp:param>标签. Applets取得参数是通过java.applet.Applet.getParameter方法。
<jsp:fallback> text message for user </jsp:fallback>
如果plugin插件不能使用时,显示给用户的文本信息
7.<jsp:setProperty>
设置Bean的一个或多个属性值。
JSP语法:
<jsp:setProperty name="beanInstanceName"
{
property= "*" | property="propertyName" [ param="parameterName"] | property="propertyName" value="{ string | <%= expression %> }"
}
/>
例子:
<jsp:setProperty name="init" property="*" />
<jsp:setProperty name="init" property="username" />
<jsp:setProperty name="init" property="username" value="lili" />
属性:
<jsp:setProperty>标签用于设置JavaBean组件中的属性值。在你使用<jsp:setProperty>元素前,你必须使用<jsp:useBean>标签 声明这个Bean.在<jsp:setProperty>中的name的值必须和在〈jsp:useBean>中的id的值一致.
一般设置属性的值有三中方法:
(i)使用<jsp:setProperty name="beanInstanceName" property="*" />方法 ,即可将用户请求中的所有值(这些值一般是客户 表单中的元素的值,且作为参数存储在request对象中)和Bean中的相匹配的属性赋值。此时,Bean中属性的名字必须和客户端表单中元素的名字一样。
(ii)使用<jsp:setProperty name="beanInstanceName" property="propertyName" [ param="parameterName"] />方法, 用请求对象中一个特定的值和Bean中相匹配的属性赋值或不相匹配的属性赋值。
(iii)使用<jsp:setProperty name="init" property="username" value="{ string | <%= expression %> }" />方法,用字符串的值或表达式的值直接设置为Bean的属性
属性和用法: name="beanInstanceName"
在<jsp:useBean>标签中被创建或调用的Bean的实例名. Name的值必须和<jsp:useBean>中的id的值一致。
property="*"
该属性用于一次性设置Bean属性的值。客户端表单中元素的值一次性赋予Bean中相匹配的属性赋值。另外,如果Bean有一个属性没有和它对应的表单元素,则这个属性将不被设置。
property="propertyName" [ param="parameterName"]
当用表单中一个元素的值给Bean中一个属性赋值,而且元素名和属性名不一样时,则必须用param指定一个参数。
8.<jsp:useBean>
调用或创建一个指定名字和使用范围的Bean.
JSP语法:
<jsp:useBean
id="beanInstanceName"
scope="page|request|session|application"
{ class="package.class"| type="package.class"|
class="package.class" type="package.class"|
beanName="{ package.class | <%= expression %> }" type="package.class"
}
{ /> |
> other tags </jsp:useBean>
}
例子:
<jsp:useBean id="init" scope="page" class="chinaa.basket" />
<jsp:setProperty name="init" property="*" />
<jsp:useBean id="hello" scope="session" class="dadi.reg" >
<jsp:setProperty name="hello" property="n" value="45" />
</jsp:useBean>
属性:
<jsp:useBean>标签首先调用一个指定的名字和使用范围的Bean,如果这个Bean不存在,则创建该 Bean。
属性和用法
id="beanInstanceName"
被调用或创建的Bean的名字.你可以在JSP文件的表达式、脚本段中使用该变量名。如果该Bean已经被另一个<jsp:useBean>创建,id值必须同原来的<jsp:useBean>标签中使用的id号相同.
scope="page|request|session|application"
定义Bean存在的范围。默认值是page。Bean的必须在其指定的范围内使用,否则使用它,将会出错。
class="package.class"
指定Bean的存放位置即存在哪个包中的哪个类。该类不能是抽象类,而且有一个公共的、无参数构造函数。包和类名是严格区分大小写的。
class="package.class" type="package.class"
类型type的值可以和类、该类的超类或该类实现的接口的类型一样。
以上就是编写JSP要用到的一些语法,读者不必也不可能一下子掌握,在需要的时候进行查询即可,在使用中会自然而然的熟练起来。
10.3.9 JSP中的隐藏对象(1)
由于JSP是嵌入式的语言,不能显式的把一些必须的参数传递进来,比如Request对象,Response对象等,所以在JSP规范中提供了几个隐含的对象来实现折椅功能。所谓隐含的对象,就是大家约定好使用一个名字来指代某个特定的对象,在编写JSP的时候不用显式的声明就能使用,由JSP引擎负责在解释的时候把隐含对象加入到解释完的.java文件中。常用的隐含对象有application, session, request, response, out, page, exception, pageContext。
1.session对象
前面在Servlet部分已经提到,过当客户第一次访问Web服务器发布目录(一个Web服务器有一个或多个"发布目录")下的网页文件时,Web服务器会自动创建一个session对象,并为其分配唯一的ID号,客户可以将其需要的一些信息保存到该session对象,以便需要时使用。session对象就是指通过getSession法办法得到的对象,在JSP中是隐含对象,关于session对象的使用读者可以参见Servlet API
2.application对象
当Web服务器启动时,Web服务器会自动创建application对象。Application对象一旦创建,它将一直存在,直到Web服务器关闭。因此,application对象可以实现多客户间的数据共享。
一个Web服务器常常有多个发布目录,当Web服务器启动时,它自动为每个发布目录都创建一个application对象,这些application对象各自独立,而且和发布目录一一对应。
application的生命周期:从Web服务器启动到Web服务器关闭。
application在生命周期内的作用范围:在同一个发布目录A下的所有网页文件中,都可以对"和发布目录A对应"的application对象进行操作,而且访问发布目录A的所有客户都共用一个application对象。因此,当在该application中存放数据信息时,所有访问该发布目录A的客户都能够对其进行访问,实现了多客户之间的数据共享。
application对象的基类是:javax.servlet.ServletContext类。可以用该类中的getServletContext()方法取得application。具体的使用方法参见Servlet API。
3.request对象
request对象主要用于取得客户在表单中提交的数据信息及多个网页之间数据信息传递等。同时通过它也可以取得Web服务器的参数。跟Servlet参数中的Request对象是相对应的。
request对象的基类为:javax.servlet.ServletRequest
如果传输协议是http,则是javax.servlet.HttpServletRequest
具体的使用方法参见Servlet API。
4. respose对象
respose对象主要用于向客户端输出信息,响应客户端的请求。跟Servlet参数中的Response对象是相对应的。
respose对象的基类是:javax.servlet.ServletResponse
如果传输协议是http.则为javax.servlet.HttpServletResponse.
具体的使用方法参见Servlet API。
5.out对象
out对象用于向客户端输出数据。
out对象基类是:javax.servlet.JspWriter类,跟Servlet中由HttpServletResponse得到的PrintWriter略有不同,但是都是从
Writer继承而来,所以基本上还是一样的。
具体的使用方法参见Servlet API。
6.page对象
page对象是当前JSP页面本身的一个实例。它的类型是:java.lang.Object。
其方法就是Object类中的方法。如:Class getClass()返回一个对象在运行时所对应的类的表示,从而可以得到相应的信息。String toString()返回当前对象的字符串表示。page对象在当前页面中可以用this代替。
7.exception对象
当JSP页面在执行过程中发生例外或错误时,会自动产生exception对象。
在当前页面用<%@ page isErrorPage="true" %>设置后,就可以使用该exception对象,来查找页面出错信息。
exception对象的类型是:java.lang.Exception类.
exception对象的常用方法为:
String getMessage()
返回页面的出错信息,如果没有则返回null
void printStackTrace()
以标准错误输出流的形式,打印并显示当前exception对象及其执行轨迹.
10.4 JSP和Servlet的结合使用
在使用JSP技术开发网站时,不强调使用Servlet。,这是为什么呢?Servlet的应用是没有问题的,它非常适合服务器端的处理和编程。但是如果用Servlet处理大量的HTML文本,那么将是一件及其繁琐的事情。这种事情更适合机器去做,否则就是浪费程序员的体力。所以Servlet更适合处理后端的事务,前端的效果用JSP来实现更为合适。
早期的JSP标准给出了两种使用JSP的方式。这些方式都可以归纳为JSP模式1和JSP模式2,主要的差别在于处理大量请求的位置不同。在模式1中,JSP页面独自响应请求并将处理结果返回客户。这里仍然有视图和内容的分离,因为所有的数据都依靠bean来处理。尽管模式1可以很好的满足小型应用的需要,但却不能满足大型应用的需要。大量使用模式1,常常会导致页面被嵌入大量的Script和Java代码。特别是当需要处理的商业逻辑很复杂时,情况会变得很严重。也许这对于Java程序员来说,这不是大问题。但是如果开发者是前台界面设计人员,在大型项目中,这是很常见的,则代码的开发和维护将出现困难。在任何项目中,这样的模式多少总是会导致定义不清的响应和项目管理的困难。下图是模式1的示意图:
JSP模式2是一种面向动态内容的实现,结合了Servlet和JSP技术。它利用两种技术原有的优点,采用JSP来表现页面,采用Servlet来完成大量的处理,Servlet扮演一个控制者的角色,并负责响应客户请求。接着,Servlet创建JSP需要的Bean和对象,再根据用户的行为,决定将哪个JSP页面发送给用户。特别要注意的是,JSP页面中没有任何商业处理逻辑,它只是简单的检索Servlet先前创建的Beans或者对象,再将动态内容插入预定义的模板。
从开发的观点来看,这一模式具有更清晰的页面表现,清楚的开发者角色划分,可以充分的利用开发小组中的界面设计人员。事实上,越是复杂的项目,使用模式2的好处就越突出。
使用模式2,JSP和Servlet可以在功能最大幅度的分开。正确的使用模式2,导致一个中心化的控制Servlet,以及只完成显示的JSP页面。另一方面,模式2的实现很复杂,因此,在简单应用中,可以考虑使用模式1。下面是模式2的示意图:
在Web的建设中到底使用哪一种模式是很重要的事前规划,只有积累了大量的经验才能作出正确而有效的选择。总之网站建设不光是技术的问题,总体的规划是很重要的,读者在学习JSP和Servlet的同时更应该注意从中吸取思想的精华,技术是会过时的,而思想却是永远有价值的。