JSP 三讲
教 学 活 动 首 页
基 本 内 容 |
第 3 章 JSP 内置对象 |
教学目的与要求:通过本章的学习让学生了解JSP 内置对象的基本关系;理解session对象的方法,application对象的方法;掌握request对象获取信息,request 对象处理汉字信息,response 对象改变HTTP头,response 对象重定向,response 的状态行,out对象的方法;并能够运用所学实现计数器,留言板。 |
教学内容: 3.1 request 对象 3.2 response 对象 3.3 session 对象 3.4 application 对象 3.5 out 对象 |
教学基本要求: 了解:文件类,流的概念 理解:字节流,字符流,回压字符流,数据流,对象流,RandomAccessFile 流 掌握:以上各种流的文件操作方法 应用:文件上传,文件下载 |
教学重点教学难点: 文件类的基本文件操作,字节流的操作方法,字符流的操作方法,回压字符流的操作方法,数据流的操作方法,对象流的操作方法,RandomAccessFile 流的操作方法,文件上传,文件下载 |
教学方法: 教学手段:多媒体教学和计算机程序演示 |
教学小结: (见教学进程) |
作业与思考:见课后习题 |
课后记载:
|
教 学 进 程
第3章 JSP 内置对象 有些对象不用声明就可以在JSP页面的脚本部分使用,这就是JSP的内置对象。 JSP的内置对象有: l resquest l response l session l application l out 以下我们将一一介绍。 response和request对象是JSP的内置对象较重要的两个,这两个对象提供了对服务器和浏览器通信方法的控制。直接讨论这两个对象前,要先对HTTP协议----Word Wide Web底层协议作简单介绍。 Word Wide Web是怎样运行的呢?在浏览器上键入一个正确的网址后,若一切顺利,网页就出现了。例如,在浏览器输入栏中键入 http://www.yahoo.com,Yahoo网站的主页就出现在浏览器窗口。这背后是什么在起作用? 使用浏览器从网站获取HTML页面时,实际在使用Hypertext Transfer Protocol(HTTP)。 HTTP协议规定了信息在Internet上的传输方法,特别规定了浏览器与服务器的交互方法。 从网站获取页面时,浏览器在网站上打开了一个对网络服务器的连接,并发出请求。服务器收到请求后回应,所以HTTP协议被称作“请求和响应”协议。 浏览器请求有某种结构,HTTP请求包括一个请求行、头域和可能的信息体。最普通的请求类型是对页面的一个简单请求,如下例: GET/hello.htm HTTP/1.1 Host:www.sina.com.cn 这是对网站: www.sina.com.cn上页面hello.htm的HTTP请求的例子。首行是请求行,规定了请求的方法、请求的资源及使用的HTTP协议的版本。 上例中,请求的方法是“GET”方法,此方法获取特定的资源。上例中GET方法用来获取名为hello.htm的网页。其它请求方法包括POST,HEAD,DELETE,TRACE及PUT方法等。 此例中的第二行是头(header)。Host头规定了网站上hello.htm文件的Internet地址。此例中,主机是: www.sina.com.cn。 一个典型请求通常包含许多头,称做请求的HTTP头。头提供了关于信息体的附加信息及请求的来源。其中有些头是标准的,有些和特定的浏览器有关。 一个请求还可能包含信息体,例如,信息体可包含HTML表单的内容。在HTML表单上单击Submit键时,该表单使用ACTION=“POST”或ACTION=“GET”特征,输入表单的内容都被发送到服务器上。该表单内容就由POST方法或GET方法在请求的信息体中发送。 服务器在收到请求时,返回HTTP响应。响应也有某种结构,每个响应都由状态行开始,可以包含几个头及可能的信息体,称做响应的HTTP头和响应信息体,这些头和信息体由服务器发送给客户的浏览器,信息体就是客户请求的网页的运行结果,对于JSP页面,就是网页的静态信息。你可能已经熟悉状态行,状态行说明了正在使用的协议、状态代码及文本信息。例如,若服务器请求出错,则状态行返回错误及对错误的描述,比如 “HTTP/1.1 404 Object Not Fond”。若服务器成功地响应了对网页的请求,返回包含“200 OK”的状态行。 3.1 request 对象 HTTP通信协议是客户与服务器之间一种提交(请求)信息与响应信息(request/respone)的通信协议。在JSP中,内置对象request封装了用户提交的信息,那么该对象调用相应的方法可以获取封装的信息,即使用该对象可以获取用户提交的信息。 客户通常使用HTML表单向服务器的某个JSP页面提交信息,表单的一般格式是:
<FORM method= get | post action= “提交信息的目的地页面”> 提交手段 </FORM>…..
其中<Form>是表单标签,method取值get或post。Get方法和post方法的主要区别是:使用get方法提交的信息会在提交的过程中显示在浏览器的地址栏中,而post方法提交的信息不会显示在地址栏中。提交手段包括:通过文本框、列表、文本区等,例如:
<FORM action="tom.jsp" method= “post” > <INPUT type="text" name="boy" value= “ok” > <INPUT TYPE="submit" value="送出" name= “submit”> </FORM>
该表单使用post方法向页面tom.jsp提交信息,提交信息的手段是:在文本框输入信息,其中默认信息是“ok”;然后点击“送出”按钮向服务器的JSP页面tom.jsp提交信息。 request对象可以使用getParameter(String s)方法获取该表单通过text提交的信息,比如: request.getParameter(“boy”); 3.1.1 获取客户提交的信息 request对象获取客户提交信息的最常用的方法是getParameter(String s)。在下面的例子1中,Example3_1.jsp通过表单向tree.jsp提交信息:I am a student。tree.jsp通过request对象获取表单提交的信息:包括text的值以及按钮的值。 在本章中,例子中所涉及到的JSP页面都保存在Web服务目录的根目录:Root中,即D:tomcat/jakarta-tomcat-4.0/webapps/Root中。 例子1(如图3.1所示) Example3_1.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=green><FONT size=1> <FORM action="tree.jsp" method=post name=form> <INPUT type="text" name="boy"> <INPUT TYPE="submit" value="Enter" name="submit"> </FORM> </FONT> </BODY> </HTML>
tree.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=green><FONT size=1> <P>获取文本框提交的信息: <%String textContent=request.getParameter("boy"); %> <BR> <%=textContent%> <P> 获取按钮的名字: <%String buttonName=request.getParameter("submit"); %> <BR> <%=buttonName%> </FONT> </BODY> </HTML>
例子2(如图3.2所示) Example3_2.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><FONT size=1> <FORM action="Example3_2.jsp" method=post name=form> <INPUT type="text" name="girl"> <INPUT TYPE="submit" value="Enter" name="submit"> </FORM> <%String textContent=request.getParameter("girl"); double number=0,r=0; if(textContent==null) {textContent=""; } try{ number=Double.parseDouble(textContent); if(number>=0) {r=Math.sqrt(number) ; out.print("<BR>"+String.valueOf(number)+"的平方根:"); out.print("<BR>"+String.valueOf(r)); } else {out.print("<BR>"+"请输入一个正数"); } } catch(NumberFormatException e) {out.print("<BR>"+"请输入数字字符"); } %> </FONT> </BODY> </HTML>
String textContent =request.getParameter("girl"); 获取提交的字符串信息,并且在下面的代码中使用了这个字符串对象: number=Doule.parseDoubel(textContent); 那么,JSP引擎在运行这个JSP页面生成的字节码文件时,会认为你使用了空对象,因为在这个字节码被执行时(客户请求页面时),客户可能还没有提交数据,textContent还没有被创建。如果你使用了空对象,即还没有创建对象,就使用了该对象,Java解释器就会提示出现了NullPointerException异常,当然如果你不使用空对象就不会出现异常。 因此,我们可以象上述例子那样,为了避免在运行时Java认为我们使用了空对象,使用如下代码: tring textContent=request.getParameter("girl"); if(textContent==null) {textContent=""; } 3.1.2 处理汉字信息 当用request对象获取客户提交的汉字字符时,会出现乱码问题,所以对含有汉字字符的信息必须进行特殊的处理方式。首先,将获取的字符串用ISO-8859-1进行编码,并将编码存放到一个字节数组中,然后再将这个数组转化为字符串对象即可。如下列所示:
String str=request.getParameter("girl"); byte b[]=str.getBytes(“ISO-8859-1”); str=new String(b);
通过上述过程,提交的任何信息(无论是汉字字符或西欧字符)都能正确的显示。 下面的例子3对例子1按上述办法做了改动,并将按钮上的字变成汉语,在文本框里输入:“苹果:apple:12斤5$”,然后提交给tree.jsp。 例子3 (如图3.3所示) Example3_3.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=green><FONT size=1> <FORM action="tree.jsp" method=post name=form> <INPUT type="text" name="boy"> <INPUT TYPE="submit" value="提交" name="submit"> </FORM> </FONT> </BODY> </HTML> tree.jsp: <%@ page contentType="text/html;charset=GB2312" %> <MHML> <BODY> <P>获取文本框提交的信息: <%String textContent=request.getParameter("boy"); byte b[]=textContent.getBytes("ISO-8859-1"); textContent=new String(b); %> <BR> <%=textContent%> <P> 获取按钮的名字: <%String buttonName=request.getParameter("submit"); byte c[]=buttonName.getBytes("ISO-8859-1"); buttonName=new String(c); %> <BR> <%=buttonName%> </BODY> </HTML>
当客户访问一个页面时,会提交一个HTTP请求给服务器的JSP引擎,这个请求包括一个请求行、http头和信息体,如下列:
post/tree2.jsp/HTTP.1.1 host: localhost:8080 accept-encoding:gzip, deflate 其中首行叫请求行,规定了向访问的页面请求提交信息的方式,如,post、 get等方式,以及请求的页面的文件名字和使用的通信协议。 第2、3行分别是两个头(Header),称host、accept-encoding是头名字,而localhost:8080以及gzip,deflate分别是它们的值。这里host的值是tree2.jsp的地址。上面的请求有2个头:host和accept-encoding,一个典型的请求通常包含很多的头,有些头是标准的,有些和特定的浏览器有关。 一个请求还包含信息体,即HTML标记组成的部分,可能包括各式各样用于提交信息的表单等,如: <BODY> <FORM action="tree2.jsp" method=post name=form> <INPUT type="text" name="boy"> <INPUT TYPE="submit" value="" name="submit"> </FORM> </BODY>
我们可以使用JSP引擎的内置对象request对象来获取客户提交的信息,说明如下: 1. getProtocol() 获取客户向服务器提交信息所使用的通信协议,比如http/1.1等。 2. getServletPath() 获取客户请求的JSP页面文件的目录。 3. getContentLength() 获取客户提交的整个信息的长度。 4. getMethod() 获取客户提交信息的方式,比如:post或get. 5. getHeader(String s) 获取HTTP头文件中由参数s指定的头名字的值,一般来说s参数可取的头名有:accept、 referer、 accept-language 、content-type、 accept-encoding、 user-agent、host、 content-length、 connection、cookie 等,比如,s取值user-agent将获取客户的浏览器的版本号等信息。 6. getHeaderNames() 获取头名字的一个枚举 7. getHeaders(String s) 获取头文件中指定头名字的全部值的一个枚举 8. getRemoteAddr() 获取客户的IP地址。 9. getRemoteHost() 获取客户机的名称(如果获取不到,就获取IP地址)。 10. getServerName() 获取服务器的名称。 11. getServerPort() 获取服务器的端口号。 12. getParameterNames() 获取客户提交的信息体部分中name参数值的一个枚举。 下面的例子4使用了request的一些常用方法。 例子4(如图3.4、3.5所示) Example3_4.jsp: <HTML> <BODY bgcolor=cyan><FONT size=1> <%@ page contentType="text/html;charset=GB2312" %> <FORM action="tree2.jsp" method=post name=form> <INPUT type="text" name="boy"> <INPUT TYPE="submit" value="enter" name="submit"> </FORM> </FONT> </BODY> </HTML> tree2.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <MHML> <BODY bgcolor=cyan> <Font size=1 > <BR>客户使用的协议是: <% String protocol=request.getProtocol(); out.println(protocol); %> <BR>获取接受客户提交信息的页面: <% String path=request.getServletPath(); out.println(path); %> <BR>接受客户提交信息的长度: <% int length=request.getContentLength(); out.println(length); %> <BR>客户提交信息的方式: <% String method=request.getMethod(); out.println(method); %> <BR>获取HTTP头文件中User-Agent的值:: <% String header1=request.getHeader("User-Agent"); out.println(header1); %> <BR>获取HTTP头文件中accept的值: <% String header2=request.getHeader("accept"); out.println(header2); %> <BR>获取HTTP头文件中Host的值: <% String header3=request.getHeader("Host"); out.println(header3); %> <BR>获取HTTP头文件中accept-encoding的值: <% String header4=request.getHeader("accept-encoding"); out.println(header4); %> <BR>获取客户的IP地址: <% String IP=request.getRemoteAddr(); out.println(IP); %> <BR>获取客户机的名称: <% String clientName=request.getRemoteHost(); out.println(clientName); %> <BR>获取服务器的名称: <% String serverName=request.getServerName(); out.println(serverName); %> <BR>获取服务器的端口号: <% int serverPort=request.getServerPort(); out.println(serverPort); %> <BR>获取客户端提交的所有参数的名字: <% Enumeration enum=request.getParameterNames(); while(enum.hasMoreElements()) {String s=(String)enum.nextElement(); out.println(s); } %> <BR>获取头名字的一个枚举: <% Enumeration enum_headed=request.getHeaderNames(); while(enum_headed.hasMoreElements()) {String s=(String)enum_headed.nextElement(); out.println(s); } %> <BR>获取头文件中指定头名字的全部值的一个枚举: <% Enumeration enum_headedValues=request.getHeaders("cookie"); while(enum_headedValues.hasMoreElements()) {String s=(String)enum_headedValues.nextElement(); out.println(s); } %> <BR> <P> 文本框text提交的信息: <%String str=request.getParameter("boy"); byte b[]=str.getBytes("ISO-8859-1"); str=new String(b); %> <BR> <%=str%> <BR> 按钮的名字: <%String buttonName=request.getParameter("submit"); byte c[]=buttonName.getBytes("ISO-8859-1"); buttonName=new String(c); %> <BR> <%=buttonName%> </Font> </BODY> </HTML>
在下面的例子5中,用户通过提交姓名和Email地址实现注册。当request对象获取这些信息后,首先检查散列表对象中是否已经存在这个名字,该散列表存储了已经注册的用户的名字。如果目前准备注册的用户提交的名字在散列表中已经存在,就提示客户更换名字,否则将检查客户是否提供了书写正确的Email地址,如果提供了书写正确Email地址将允许注册。 在下面的例子5中,使用了散列表。散列表是使用相关关键字查找被存储的数据项的一种数据结构,关键字不可以发生逻辑冲突,即不要两个数据项使用相同的关键字。散列表在它需要更多的存储空间时会自动增大容量。例如,如果散列表的装载因子是0.75,那么当散列表的容量被使用了75%时,它就把容量增加到原始容量的2倍。对于数组和链表这两种数据结构,如果要查找它们存储的某个特定的元素却不知道它的位置,就需要从头开始访问元素直到找到匹配的为止,如果数据结构中包含很多的元素,就会浪费时间。这时最好使用散列表来存储要查找的数据。 我们将例子5中的login1.jsp和login2.jsp保存在Web服务目录root中,用户首先访问login1.jsp,输入名字和Email提交给login2.jsp实现注册。 例子5(如图3.6所示) Login1.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><Font size=1 > <FORM action="login2.jsp" method=post > <P>输入你的姓名: <INPUT type="text" name="name" value="abc"> <BR> <P>输入你的e-mail地址: <INPUT type="text" name="address" value="ookk@sina.com"> <P>点击送出按钮: <BR> <INPUT TYPE="submit" value="送出" name=submit> </FORM> </FONT> </BODY> </HTML> login2.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <HTML> <BODY bgcolor=cyan><Font size=1 > <%!Hashtable hashtable=new Hashtable(); public synchronized void putString(String s) { hashtable.put(s,s); } %> <% String person_name=request.getParameter("name"), name_found=null; if(person_name==null) {person_name=""; } byte b[]=person_name.getBytes("ISO-8859-1"); person_name=new String(b); name_found=(String)hashtable.get(person_name); if(name_found==null) { String person_email=request.getParameter("address"); if(person_email==null) {person_email=""; } StringTokenizer fenxi=new StringTokenizer(person_email," @"); int n=fenxi.countTokens(); if(n>=3) {out.print("<BR>"+"你输入的Email有不合法字符"); } else { putString(person_name); out.print("<BR>"+"您已经注册成功"); out.print("<BR>"+"您注册的名字是"+person_name);
} } else {out.print("<BR>"+"该名字已经存在,请您换个名字"); } %> </FONT> </BODY> </HTML>
注:在上面的例子中,如果服务器重新启动将会刷新散列表。所以,我们应当将散列表存放到文件中,当客户访问服务器时首先从文件中读出散列表,在这个散列表中查找已经注册的名字,如果文件不存在,那么该客户就是第一个注册的人,就负责将散列表写入到文件。我们将login2.jsp改进如下:
<%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <%@ page import="java.io.*" %> <HTML> <BODY> <%!Hashtable hashtable=new Hashtable(); public synchronized void putString(String s) { hashtable.put(s,s); } %> <% String person_name=request.getParameter("name"),name_found=null; if(person_name==null) {person_name=""; } byte c[]=person_name.getBytes("ISO-8859-1"); person_name=new String(c); %> <%--从文件中读散列表,如果文件不存在,你就是第一个访问本站的人,负责写散列表到文件--%> <%try{File f=new File("name.txt"); FileInputStream in=new FileInputStream(f); ObjectInputStream object_in=new ObjectInputStream(in); hashtable=(Hashtable)object_in.readObject(); object_in.close(); in.close(); name_found=(String)hashtable.get(person_name); if(name_found==null) { String person_email=request.getParameter("address"); if(person_email==null) {person_email=""; } StringTokenizer fenxi=new StringTokenizer(person_email," @"); int n=fenxi.countTokens(); if(n>=3) {out.print("<BR>"+"你输入的Email有不合法字符"); } else { putString(person_name); try{FileOutputStream o=new FileOutputStream(f); ObjectOutputStream object_out=new ObjectOutputStream(o); object_out.writeObject(hashtable); object_out.close(); o.close(); } catch(Exception eee) { } out.print("<BR>"+"您已经注册成功"); out.print("<BR>"+"您注册的名字是"+person_name);
} } else {out.print("<BR>"+"该名字已经存在,请您换个名字"); } } catch(Exception e) { String person_email=request.getParameter("address"); if(person_email==null) {person_email=""; } StringTokenizer fenxi=new StringTokenizer(person_email," @"); int n=fenxi.countTokens(); if(n>=3) {out.print("<BR>"+"你输入的Email有不合法字符"); } else { putString(person_name); try{File f=new File("name.txt"); FileOutputStream o=new FileOutputStream(f); ObjectOutputStream object_out=new ObjectOutputStream(o); object_out.writeObject(hashtable); object_out.close(); o.close(); } catch(Exception eee) { } out.print("<BR>"+"恭喜!,您是第一个注册成功的人"); out.print("<BR>"+"您注册的名字是"+person_name); } } %> </BODY> </HTML> 3.1.5 获取HTML表单提交的数据 由于客户经常需要使用表单提交数据,所以有必要对表单做一个简明的介绍,如果您对HTML语言比较陌生,建议补充这方面的知识。 表单的一般格式是:
<FORM method= get| post action=”提交信息的目的地页面” name=”表单的名字”> 数据提交手段部分 </FORM>…..
其中<Form>是表单标签,method取值get或post。get方法和post方法的主要区别是:使用get方法提交的信息会在提交的过程中显示在浏览器的地址栏中,而post方法提交的信息不会显示在地址栏中。提交手段包括:通过文本框、列表、文本区等,例如:
<FORM action="tom.jsp" method= “post” > <INPUT type="text" name="boy" value= “ok” > <INPUT TYPE="submit" value="送出" name= “submit”> </FORM>
一个表单的数据提交手段部分经常包括如下的标记符号: l <INPUT …..> l <Select … ></Select> l <Option …..> </Option> l <TextArea ….> </TextArea>
1. <Input>的基本格式 在表单中用 Input标记来指定表单中数据的输入方式以及表单的提交键。Input标记中的type属性可以指定输入方式的GUI对象,name属性用来指定这个GUI对象的名称。基本格式:
<input type=”输入对象的GUI类型” name= “名字” >
服务器通过属性name指定的名字来获取“输入对象的GUI类型”中提交的数据。“输入对象的GUI类型”可以是:text(文本框)、checkbox(检查框)、submit(提交键)等。 (1)文本框:text 当输入对象的GUI类型是text时,除了用name为text指定名字外,还可以为text指定其它的一些值。比如:
<input type= “text” name= “me” value= “hi” size= “12 ” algin= “left” maxlength= “30”>
其中,value的值是text的初始值;size是text对象的长度(单位是字符);algin是text在浏览器窗体中的对齐方式;maxlength指定text可输入字符的最大长度。 (2)单选框:radio 当输入对象的GUI类型是radio时,除了用name为radio指定名字外,还可以为radio指定其它的一些值。比如:
<input type= “radio” name= “rad” value= “red” algin= “top” checked= “java” >
其中,value指定radio的值;algin是radio在浏览器窗体中的对齐方式;如果几个单选键的name取值相同,那么同一时刻只能有一个被选中。服务器通过name指定的名字来获取被选中的radio提交的由value指定的值。checked如果取值是一个非空的字符串,那么该单选框的初始状态就是选中状态。 在下面的例子6中,我们用单选框来实现一个网上小测试。客户在radio.jsp页面中选中几个单选框,将选择提交给answer.jsp页面。 例子6(如图3.7所示) radio.jsp: <HTML> <%@ page contentType="text/html;charset=GB2312" %> <BODY bgcolor=cyan><Font size=1 > <P>诗人李白是中国历史上哪个朝代的人: <FORM action="answer.jsp" method=post name=form> <INPUT type="radio" name="R" value="a">宋朝 <INPUT type="radio" name="R" value="b">唐朝 <INPUT type="radio" name="R" value="c">明朝 <INPUT type="radio" name="R" value="d" checked="ok">元朝 <BR> <P>小说红楼梦的作者是: <BR> <INPUT type="radio" name="P" value="a">曹雪芹 <INPUT type="radio" name="P" value="b">罗贯中 <INPUT type="radio" name="P" value="c">李白 <INPUT type="radio" name="P" value="d">司马迁 <BR> <INPUT TYPE="submit" value="提交答案" name="submit"> </FORM> </FONT> </BODY> </HTML>
answer.jsp: <HTML> <%@ page contentType="text/html;charset=GB2312" %> <BODY bgcolor=cyan><Font size=1 > <% int n=0; String s1=request.getParameter("R"); String s2=request.getParameter("P"); if(s1==null) {s1="";} if(s2==null) {s2="";} if(s1.equals("b")) { n++;} if(s2.equals("a")) { n++;} %> <P>您得了<%=n%>分 </FONT> </BODY> </HTML> (3)复选框:checkbox: 当输入对象的GUI类型是checkbox时,除了用name为checkbox指定名字外,还可以为checkbox指定其它的一些值。比如:
<input type= “checkbox” name= “ch” value= “pink” algin= “top” checked= “java” >
其中,value指定checkbox的值;复选框与单选框的区别就是可以多选。服务器通过name指定的名字来获取被选中的checkbox提交的由value指定的值,为了使服务器能获取提交的值,复选框name的值应互不相同。Checked如果取值是一个非空的字符串,那么该复选框的初始状态就是选中状态。 (4)口令框:password 它是输入口令用的特殊文本框,输入的信息用 “*”回显,防止他人偷看口令。
<input type= “passwordt” name= “me” size= “12 ” maxlength= “30”>
服务器通过name指定的字符串获取password提交的值,你在口令框中输入:“bird88_1”,那么bird88_1将被提交给服务器,口令框仅仅起着不让别人偷看的作用,不提供保密措施。 (5)提交键:submit 为了能把表单的数据提交给服务器,一个表单至少要包含一个提交键。
<input type= “submit ” name= “me” value= “ok” size= “12 ” >
点击提交键后,服务器就可以获取表单提交的各个数据。当然服务器也可以获取提交键的值,服务器通过name指定的名字来获取提交键提交的由value指定的值。 (6)重置键:reset 重置键将表单中输入的数据清空,以便重新输入数据。
<input type= “reset” >
2. <Select>、<Option>格式 下拉式列表和滚动列表通过<Select>和<Option>标记来定义,基本格式为:
<Selection> <Option> <Option> … … </Selection>
(1) 下拉列表
<Select name="shulie" > <Option value="cat">你选了小猫 <Option value="dog">你选了小狗 …. …. <Option value="600">n=600 </Select>
服务器通过name获取下拉列表中被选中的option的值(参数value指定的值)。 (2) 滚动列表 在select中增加size属性的值就变成滚动列表,size的值是滚动列表的可见行的个数。 <Select name="shulie" size=2> <Option value="1">计算1到n的连续和 <Option value="2">计算1到n的平方和 <Option value="3">计算1到n的立方和 </Select>
服务器通过name获取滚动列表中被选中的option的值(参数value指定的值)。 在下面的例子7中,客户通过滚动列表选择计算求和的方式,通过下拉列表选择计算求和的项数。 例子7(如图3.8所示) select.jsp: <HTML> <%@ page contentType="text/html;charset=GB2312" %> <BODY bgcolor=cyan><Font size=1 > <P>选择计算和的方式 <FORM action="sum.jsp" method=post name=form> <Select name="sum" size=2> <Option Selected value="1">计算1到n的连续和 <Option value="2">计算1到n的平方和 <Option value="3">计算1到n的立方和 </Select> <P>选择n的值:<BR> <Select name="n" > <Option value="10">n=10 <Option value="20">n=20 <Option value="30">n=30 <Option value="40">n=40 <Option value="50">n=50 <Option value="100">n=100 </Select> <BR><BR> <INPUT TYPE="submit" value="提交你的选择" name="submit"> </FORM> </FONT> </BODY> </HTML>
sum.jsp: <HTML> <%@ page contentType="text/html;charset=GB2312" %> <BODY bgcolor=cyan><Font size=1 > <% long sum=0; String s1=request.getParameter("sum"); String s2=request.getParameter("n"); if(s1==null) {s1="";} if(s2==null) {s2="0";} if(s1.equals("1")) {int n=Integer.parseInt(s2); for(int i=1;i<=n;i++) {sum=sum+i; } } else if(s1.equals("2")) {int n=Integer.parseInt(s2); for(int i=1;i<=n;i++) {sum=sum+i*i; } } else if(s1.equals("3")) {int n=Integer.parseInt(s2); for(int i=1;i<=n;i++) {sum=sum+i*i*i; } } %> <P>您的求和结果是<%=sum%> </FONT> </BODY> </HTML>
3. <TextArea>格式 <TextArea> 标记在表单中指定一个能输入多行文本的文本区域。
<TextArea name= “ilovethisgame” Rows= “4” Cols= “20” > </TextArea> 3.1.6 表格 表格由<Table>、</Table>标记定义,一般格式: <Table > <TR width=“该行的宽度”> <TH width= “单元格的宽度” >单元格中的数据</TH> … <TD width= “单元格的宽度” >单元格中的数据</TD> … </TR> … …. </Table> 其中 <TR> …. </TR> 定义表格的一个行,<TH>和<TD>标记定义这一行中的表格单元,二者的区别是<TH>定义的单元着重显示,<TD>称做普通单元,不着重显示;一行中的着重单元和普通的单元可以交替出现,也可以全是着重单元或普通单元。 <table >中增加选项Border可指明该表格是否带有边框。 在下面的例子8中,用一个4行的表格显示数据。第一行有3个着重显示的单元。第2行有3个单元,其中第一个单元着重显示。第3行有3个普通的单元,如图3.9所示。 例子8(如图3.9所示) table.jsp: <HTML> <%@ page contentType="text/html;charset=GB2312" %> <BODY> <Table align="Center" Border> <TR width=400> <TH Align="Center">中间</TH> <TH Align="Right">右</TH> <TH Align="LEFT">左</TH> <TD></TD> <TD></TD> </TR> <TR > <TH Valign="Top">数据靠向上沿</TH> <TD Valign="Bottom">数据靠向下沿</TD> <TD Valign="Bottom" Align="Center" >数据居中靠向下沿</TD> </TR> <TR > <TD Valign="Top"> 你好</TD> <TD Valign="Bottom">hello</TD> <TD Valign="Bottom" Aligin="Center" >112334</TD> </TR> </Table> </BODY> </HTML>
在下面的例子9中,把一个表单显示在表格的一个单元格中,如图3.10所示。 例子9(如图3.10所示) tableform.jsp: <HTML> <%@ page contentType="text/html;charset=GB2312" %> <BODY bgcolor=cyan> <Table align="left" Border> <TR> <TH width=250><FONT size=1>李白是哪个朝代的人?:</TH> <TD width=220> <FORM action="answer.jsp" method=post name=form> <INPUT type="radio" name="R" value="a" ><FONT size=1>宋朝 <INPUT type="radio" name="R" value="b" ><FONT size=1>唐朝 <INPUT type="submit" name="g" value="送出"> </FORM> </TD> </TR> <TR > <TH><FONT size=1>输入数据:</TH> <FORM action="answer.jsp" method=post name=form> <TD> <INPUT type="text" name="R" value="a" size=20 > </TD> <TD> <INPUT type="submit" name="f" value="送出" > </TD> </Form> </TR> </Table> </BODY> </HTML> 3.2 response 对象 当客户访问一个服务器的页面时,会提交一个HTTP请求,服务器收到请求时,返回HTTP响应。响应和请求类似,也有某种结构,每个响应都由状态行开始,可以包含几个头及可能的信息体(网页的结果输出部分)。 上一节学习了用request对象获取客户请求提交的信息,与request对象相对应的对象是response对象。我们可以用response对象对客户的请求作出动态响应,向客户端发送数据。比如,当一个客户请求访问一个JSP页面时,该页面用page指令设置页面的contentType属性的值是text/html,那么JSP引擎将按着这种属性值响应客户对页面的请求,将页面的静态部分返回给客户。如果想动态地改变contentType的属性值就需要用response对象改变页面的这个属性的值,作出动态的响应。 3.2.1 动态响应contentType属性 当一个客户请求访问一个JSP页面时,如果该页面用page指令设置页面的contentType属性的值是text/html,那么JSP引擎将按着这种属性值作出响应,将页面的静态部分返回给客户。由于page指令只能为contentType指定一个值,来决定响应的MIME类型,如果想动态的改变这个属性的值来响应客户,就需要使用response对象的setContentType(String s)方法来改变contentType的属性值:
public void setContentType(String s);
该方法动态设置响应的MIME类型,参数s可取:text/html、text/plain application/x-msexcel、application/msword等 当服务器用setContentType方法动态改变了contentType的属性值,即响应的MIME类型,并将JSP页面的输出结果按着新的MIME类型返回给客户时,客户端要保证支持这种新的MIME类型。客户如果想知道自己的浏览器能支持哪些MIME类型,可以点击资源管理器→工具→文件夹选项→文件类型。如图3.11所示。 在下面的例子10中,当客户点击按钮,选择将当前页面保存为一个Word文挡时,JSP页面动态地改变contentType的属性值为application/msword。这时,客户的浏览器会提示客户用Ms-Word格式来显示当前页面,如图3.12所示。
Example3_10.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><Font size=1 > <P>我正在学习response对象的 <BR>setContentType方法 <P>将当前页面保存为word文档吗? <FORM action="" method="get" name=form> <INPUT TYPE="submit" value="yes" name="submit"> </FORM> <% String str=request.getParameter("submit"); if(str==null) {str=""; } if(str.equals("yes")) {response.setContentType("application/msword;charset=GB2312"); } %> </FONT> </BODY> </HTML>
在下面的例子中,当客户选择用Excel表格显示JSP页面中的一个A.txt文件时,我们用response对象将contentType的属性值设为"application/x-msexcel"。需要注意的是:在编辑文本文件A.txt时,回车要用<BR>来表示,输入空格时要将输入法切换到全角(因为半角输入的多个空格被浏览器认为是一个空格)。为了能用Excel显示该文件,数据列之间要有4个空格(必须在全角状态下编辑空格)。A.txt和JSP页面保存在同一目录中。 A.txt: 34 79 51 99<BR> 40 89 92 99<BR> 64 99 30 99<BR> 74 56 80 99<BR> 87 97 88 99<BR> 74 65 56 99<BR> 67 75 67 66<BR> 89 77 88 99<BR>
Example3_11.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><Font size=1 > <P>您想使用什么方式查看文本文件A.txt? <FORM action="tree3.jsp" method="post" name=form> <INPUT TYPE="submit" value="word" name="submit1"> <INPUT TYPE="submit" value="excel" name="submit2"> </FORM> </FONT> </BODY> </HTML>
tree3.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <% String str1=request.getParameter("submit1"); String str2=request.getParameter("submit2"); if(str1==null) {str1=""; } if(str2==null) {str2=""; } if(str1.startsWith("word")) {response.setContentType("application/msword;charset=GB2312"); out.print(str1); } if(str2.startsWith("excel")) {response.setContentType("application/x-msexcel;charset=GB2312"); } %> <jsp:include page="A.txt"> </jsp:include> </BODY> </HTML>
注:当把contentType的属性值设为text/plait(纯文本)时,如果客户使用的是Netscape浏览器,那么HTML标记将不被解释,客户以纯文本的形式观看当前网页的输出结果,但Microsoft的Internet Explorer将解释HTML标记。 3.2.2 response的HTTP文件头 我们已经知道,当客户访问一个页面时,会提交一个HTTP头给服务器,这个请求包括一个请求行、http头和信息体,如下列: post/tree3.jsp/HTTP.1.1 host: localhost:8080 accept-encoding:gzip, deflate 第2、3行分别是两个头,称host、accept-encoding是头名字,而localhost:8080以及gzip,deflate分别是它们的值。这里规定了host的值是tree3.jsp的地址。上面的请求有2个头:host和accept-encoding,一个典型的请求通常包含很多的头,有些头是标准的,有些和特定的浏览器有关。 同样,响应也包括一些头。response对象可以使用方法
addHeader(String head,String value);
或方法
setHeader(String head ,String value)
动态添加新的响应头和头的值,将这些头发送给客户的浏览器。如果添加的头已经存在,则先前的头被覆盖。 在下面的例子12中,response对象添加一个响应头:“refresh”,其头值是“5”。那么客户收到这个头之后,5秒钟后将再次刷新该页面,导致该网页每5秒刷新一次,如图3.14所示。
Example3_12.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <HTML> <BODY bgcolor=cyan><Font size=1 > <P>现在的时间是:<BR> <% out.println(""+new Date()); response.setHeader("Refresh","5"); %> </FONT> </BODY> </HTML> 3.2.3 respose重定向 在某些情况下,当响应客户时,需要将客户重新引导至另一个页面。例如,如果客户输入的表单信息不完整,就会再被引导到该表单的输入页面。 可以使用response的sendRedirect(URL url)方法实现客户的重定向。 在下面的例子13中,客户在Eample3_13.jsp页面填写表单提交给tree4.jsp页面,如果填写的表单不完整就会重新定向到Example3_13.jsp页面。
例子13 Example3_13.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <P>填写姓名:<BR> <FORM action="tree4.jsp" method="get" name=form> <INPUT TYPE="text" name="boy"> <INPUT TYPE="submit" value="Enter"> </FORM> </BODY> </HTML>
tree4.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <% String str=null; str=request.getParameter("boy"); if(str==null) {str=""; } byte b[]=str.getBytes("ISO-8859-1"); str=new String(b); if(str.equals("")) {response.sendRedirect("Example3_13.jsp"); } else {out.print("欢迎您来到本网页!"); out.print(str); } %> </BODY> </HTML> 3.2.4 response的状态行 当服务器对客户请求进行响应时,它发送的首行称做状态行。 状态行包括3位数字的状态代码和对状态代码的描述(称做原因短语)。下面列出了对5类状态的代码的大概描述: 1yy(1开头的3位数):主要是实验性质的。 2yy:用来表明请求成功的,例如,状态代码200可以表明已成功取得了请求的页面。 3yy:用来表明在请求满足之前应采取进一步的行动。 4yy:当浏览器作出无法满足的请求时,返回该状态代码,例如404表示请求的页面不存在 5yy:用来表示服务器出现问题。例如,500说明服务器内部发生错误。 我们一般不需要修改状态行,在出现问题时,服务器会自动响应,发送相应的状态代码。我们也可以使用response对象的setStatus(int n)方法来增加状态行的内容。在下面的例子14中,使用setStatus(int n)方法设置响应的状态行。
Example3_14.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><Font size=1> <P>点击下面的超链接:<BR> <A HREF="bird1.jsp"> bird1:欢迎你吗? <BR> <A HREF="bird2.jsp"> bird2:欢迎你吗? <BR> <A HREF="bird3.jsp"> bird3:欢迎你吗? </FONT> </BODY> </HTML>
bird1.jsp: <HTML> <BODY> <% response.setStatus(408); out.print("不显示了"); %> </BODY> </HTML>
bird2.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <% response.setStatus(200); out.println("ok"); %> </BODY> </HTML>
bird3.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <% response.setStatus(500); %> </BODY> </HTML>
下列表3.1是状态代码表 表 3.1 状态代码表 状态代码 代码说明 101 服务器正在升级协议 100 客户可以继续 201 请求成功且在服务器上创建了新的资源 202 请求已被接受但还没有处理完毕 200 请求成功 203 客户端给出的元信息不是发自服务器的 204 请求成功,但没有新信息 205 客户必须重置文档视图 206 服务器执行了部分get请求 300 请求的资源有多种表示法 301 资源已经被永久移动到新位置 302 资源已经被临时移动到新位置 303 应答可以在另外一个URL中找到 304 Get方式请求不可用 305 请求必须通过代理来访问 400 请求有语法错误 401 请求需要HTTP认证 403 取得了请求但拒绝服务 404 请求的资源不可用 405 请求所用的方法是不允许的 406 请求的资源只能用请求不能接受的内容特性来响应 407 客户必须得到认证 408 请求超时 409 发生冲突,请求不能完成 410 请求的资源已经不可用 411 请求需要一个定义的内容长度才能处理 413 请求太大,被拒绝 414 请求的URL太大 415 请求的格式被拒绝 500 服务器发生内部错误,不能服务 501 不支持请求的部分功能 502 从代理和网关接受了不合法的字符 503 HTTP服务暂时不可用 504 服务器在等待代理服务器应答时发生超时 505 不支持请求的HTTP版本
3.3 session对象 HTTP协议是一种无状态协议。一个客户向服务器发出请求(request)然后服务器返回响应(respons),连接就被关闭了。在服务器端不保留连接的有关信息,因此当下一次连接时,服务器已没有以前的连接信息了,无法判断这一次连接和以前的连接是否属于同一客户。因此,必须使用会话记录有关连接的信息。 从一个客户打开浏览器连接到服务器,到客户关闭浏览器离开这个服务器称做一个会话。当一个客户访问一个服务器时,可能会在这个服务器的几个页面反复连接、反复刷新一个页面或不断地向一个页面提交信息等,服务器应当通过某种办法知道这是同一个客户,这就需要session(会话)对象。 3.3.1 session对象的Id 当一个客户首次访问服务器上的一个JSP页面时,JSP引擎产生一个secssion对象,这个session对象调用相应的方法可以存储客户在访问各个页面期间提交的各种信息,比如,姓名、号码等信息。这个session对象被分配了一个String类型的Id号,JSP引擎同时将这个Id号发送到客户端,存放在客户的Cookie中。这样,session对象和客户之间就建立起一一对应的关系,即每个客户都对应着一个session对象(该客户的会话),这些session对象互不相同,具有不同的Id号码。我们已经知道,JSP引擎为每个客户启动一个线程,也就是说,JSP为每个线程分配不同的session对象。当客户再访问连接该服务器的其它页面时,或从该服务器连接到其它服务器再回到该服务器时,JSP引擎不再分配给客户的新session对象,而是使用完全相同的一个,直到客户关闭浏览器后,服务器端该客户的session对象被取消,和客户的会话对应关系消失。当客户重新打开浏览器再连接到该服务器时,服务器为该客户再创建一个新的session对象。 在下面的例子15中,客户在服务器的三个页面之间进行连接,只要不关闭浏览器,三个页面的session对象是完全相同的。客户首先访问session.jsp页面,从这个页面再连接到tom.jsp页面,然后从tom.jsp再连接到jerry.jsp页面。
例子15(如图3.16所示) session.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <P> <% String s=session.getId(); %> <P> 您的session对象的ID是: <BR> <%=s%> <P>输入你的姓名连接到tom.jsp <FORM action="tom.jsp" method=post name=form> <INPUT type="text" name="boy"> <INPUT TYPE="submit" value="送出" name=submit> </FORM> </BODY> </HTML>
tom.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <P>我是Tom页面 <% String s=session.getId(); %> <P> 您的在Tom页面中的session对象的ID是: <%=s%> <P> 点击超链接,连接到Jerry的页面。 <A HREF="jerry.jsp"> <BR> 欢迎到Jerry屋来! </A> </BODY> </HTML>
jerry.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <P>我是Jerry页面 <% String s=session.getId(); %> <P> 您在Jerry页面中的session对象的ID是: <%=s%> <P> 点击超链接,连接到session的页面。 <A HREF="session.jsp"> <BR> 欢迎到session屋来! </A> </BODY> </HTML> 3.3.2 session对象与URL重写 session对象能和客户建立起一一对应关系依赖于客户的浏览器是否支持Cookie。如果客户端不支持Cookie,那么客户在不同网页之间的session对象可能是互不相同的,因为服务器无法将Id存放到客户端,就不能建立session对象和客户的一一对应关系。我们将浏览器的Cookie设置为禁止后(选择浏览器菜单→工具→Internet选项→安全→internet和本地intranet→自定义级别→cooker,将全部选项设置成禁止),运行上述例子会得到不同的结果。也就是说,“同一客户”对应了多个session对象,这样服务器就无法知道在这些页面上访问的实际上是同一个客户。 如果客户的浏览器不支持Cookie,我们可以通过URL重写来实现session对象的唯一性。所谓URL重写,就是当客户从一个页面重新连接到一个页面时,通过向这个新的URL添加参数,把session对象的Id传带过去,这样就可以保障客户在该网站各个页面中的session对象是完全相同的。可以使用response对象调用encodeURL()或encodeRedirectURL()方法实现URL重写,比如,如果从tom.jsp页面连接到jerry页面,首先实现URL重写:
String str=response.encodeRedirectURL("jerry.jsp");
然后将连接目标写成<%=str%>
例子16(如图3.17所示) session.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan> <P> 您的session对象的ID是: <% String s=session.getId(); String str=response.encodeURL("tom.jsp"); %> <P> 您的session对象的ID是: <%=s%> <BR> <P>您向URL:http://localhost:8080/tom.jsp写入的信息是: <%=str%> <FORM action="<%=str%>" method=post name=form> <INPUT type="text" name="boy"> <INPUT TYPE="submit" value="送出" name=submit> </FORM> </BODY> </HTML>
tom.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=pink> <P>我是Tom页面 <% String s=session.getId(); String str=response.encodeRedirectURL("jerry.jsp"); %> <P> 您在Tom页面中的session对象的ID是: <%=s%> <P>您向URL:http://localhost:8080/jerry.jsp写入的信息是: <BR> <%=str%> <P> 点击超链接,连接到Jerry的页面。 <A HREF="<%=str%>"> <BR>欢迎到Jerry屋来! </A> </BODY> </HTML>
jerry.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=pink> <P>我是jerry页面 <% String s=session.getId(); String str=response.encodeRedirectURL("session.jsp"); %> <P> 您的在jerry页面中的session对象的ID是: <%=s%> <P>您向URL:http://localhost:8080/session.jsp写入的信息是: <BR> <%=str%> <P> 点击超链接,连接到session的页面。 <A HREF="<%=str%>"> <BR>欢迎到session屋来! </A> </BODY> </HTML> 3.3.3 session对象的常用方法 (1) public void setAttribute(String key ,Object obj) session对象类似于散列表,session对象可以调用该方法将参数Object指定的对象obj添加到session对象中,并为添加的对象指定了一个索引关键字,如果添加的两个对象的关键字相同,则先前添加的对象被清除。 (2) public Object getAttibue(String key) 获取session对象含有的关键字是key的对象。由于任何对象都可以添加到session对象中,因此用该方法取回对象时,应强制转化为原来的类型。 (3) public Enumeration getAttributeName() session对象调用该方法产生一个枚举对象,该枚举对象使用nextElemets()遍历session对象所含有的全部对象。 (4) public long getCreationTime() session对象调用该方法可以获取该对象创建的时间,单位是毫秒(从1970年7月1日午夜起至该对象创建时刻所走过的毫秒数)。 (5) public long getLastAccessedTime() 获取当前session对象最后一次被操作的时间,单位是毫秒。 (6) public int getMaxInactiveIterval() 获取session对象的生存时间。 (7) public void setMaxInactiveIterval(int n) 设置session对象的生存时间(单位是秒) (8) public void removeAttribue(String key) 从当前session对象中删除关键字是key的对象。 (9) public String getId() 获取session对象的编号。 (10) invalidate 使得session无效。
下面的例子17中涉及3个页面,我们使用session对象存储顾客的姓名和购买的商品。
Example3_17.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><FONT Size=1> <% session.setAttribute("customer","顾客"); %> <P>输入你的姓名连接到第一百货:first.jsp <FORM action="first.jsp" method=post name=form> <INPUT type="text" name="boy"> <INPUT TYPE="submit" value="送出" name=submit> </FORM> <FONT> </BODY> </HTML> first.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><FONT Size=1> <% String s=request.getParameter("boy"); session.setAttribute("name",s); %> <P>这里是第一百货 <P>输入你想购买的商品连接到结帐:account.jsp <FORM action="account.jsp" method=post name=form> <INPUT type="text" name="buy"> <INPUT TYPE="submit" value="送出" name=submit> </FORM> </FONT> </BODY> </HTML>
account.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%! //处理字符串的方法: public String getString(String s) { if(s==null) {s=""; } try {byte b[]=s.getBytes("ISO-8859-1"); s=new String(b); } catch(Exception e) { } return s; } %> <HTML> <BODY bgcolor=cyan><FONT Size=1> <% String s=request.getParameter("buy"); session.setAttribute("goods",s); %> <BR> <% String 顾客=(String)session.getAttribute("customer"); String 姓名=(String)session.getAttribute("name"); String 商品=(String)session.getAttribute("goods"); 姓名=getString(姓名); 商品=getString(商品); %> <P>这里是结帐处 <P><%=顾客%>的姓名是: <%=姓名%> <P>您选择购买的商品是: <%=商品%> </FONT> </BODY> </HTML>
下面的例子18是个猜数字的小游戏。当客户访问服务器上的Example3_18.jsp时,随机分配给客户一个1到100之间的数,然后将这个数字存在客户的session对象中。客户在表单里输入一个数,来猜测分配给自己的那个数字。客户输入一个数字后,提交给result.jsp,该页面负责判断这个数是否和客户的session对象中存放的那个数字相同,如果相同就连接到success.jsp;如果不相同就连接到large.jsp或small.jsp,然后,客户在这些页面再重新提交数字到result页面。
Example3_18.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><FONT Size=1> <P>随机分给了你一个1到100之间的数,请猜! <% int number=(int)(Math.random()*100)+1; session.setAttribute("count",new Integer(0)); session.setAttribute("save",new Integer(number)); %> <BR> <P>输入你的所猜的数 <FORM action="result.jsp" method="post" name=form> <INPUT type="text" name="boy" > <INPUT TYPE="submit" value="送出" name="submit"> </FORM> </FONT> </BODY> </HTML>
result.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><FONT Size=1> <BR> <% String str=request.getParameter("boy"); if(str==null) {str="0"; } int guessNumber=Integer.parseInt(str); Integer integer=(Integer)session.getAttribute("save"); int realnumber=integer.intValue(); if(guessNumber==realnumber) { int n=((Integer)session.getAttribute("count")).intValue(); n=n+1; session.setAttribute("count",new Integer(n)); response.sendRedirect("success.jsp"); } else if(guessNumber>realnumber) { int n=((Integer)session.getAttribute("count")).intValue(); n=n+1; session.setAttribute("count",new Integer(n)); response.sendRedirect("large.jsp"); } else if(guessNumber<realnumber) { int n=((Integer)session.getAttribute("count")).intValue(); n=n+1; session.setAttribute("count",new Integer(n));
response.sendRedirect("small.jsp"); } %> </FONT> </BODY> </HTML>
large.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><FONT Size=1> <BR> <P>所猜的数比实际的数大,请再猜: <FORM action="result.jsp" method="get" name=form > <INPUT type="text" name="boy" > <INPUT TYPE="submit" value="送出" name="submit"> </FORM> </FONT> </BODY> </HTML>
small.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><FONT Size=1> <BR> <P>所猜的数比实际的数小,请再猜: <FORM action="result.jsp" method="post" name=form> <INPUT type="text" name="boy" > <INPUT TYPE="submit" value="送出" name="submit"> </FORM> </FONT> </BODY> </HTML>
success.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY bgcolor=cyan><FONT Size=1> <% int count=((Integer)session.getAttribute("count")).intValue(); int num=((Integer)session.getAttribute("save")).intValue(); long startTime=session.getCreationTime(); long endTime=session.getLastAccessedTime(); %> <P>恭喜你,猜对了 <BR> <P>您共猜了<%=count%>次 <P>用时<%=(endTime-startTime)/1000%>秒。 <P>这个数字就是<%=num%> <P>您必须关掉浏览器才能获得新的数。 </FONT> </BODY> </HTML> 3.3.4 计数器 在第2章讲述过一个计数器的例子,但那个例子并不能限制客户通过不断的刷新页面来增加计数器的计数,在下面的例子19中,用session对象禁止客户通过刷新页面增加计数。当客户刷新页面时,我们可以使用session的public boolean isNew() 方法判断是否是一个新的客户,因为客户刷新页面不会改变服务器分配给该客户的session对象。
例子19 Examle3_19.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.io.*" %> <HTML> <BODY> <%! int number=0; synchronized void countPeople() { if(number==0) { try{File f=new File("D:/tomcat","countPeople.txt"); FileInputStream in=new FileInputStream(f); DataInputStream dataIn=new DataInputStream(in); number=dataIn.readInt(); number++; in.close();dataIn.close(); } catch(FileNotFoundException e) { number++; try {File f=new File("D:/tomcat","countPeople.txt"); FileOutputStream out=new FileOutputStream(f); DataOutputStream dataOut=new DataOutputStream(out); dataOut.writeInt(number); out.close();dataOut.close(); } catch(IOException ee){} } catch(IOException ee) { } } else {number++; try{File f=new File("D:/tomcat","countPeople.txt"); FileOutputStream out=new FileOutputStream(f); DataOutputStream dataOut=new DataOutputStream(out); dataOut.writeInt(number); out.close();dataOut.close(); } catch(FileNotFoundException e){} catch(IOException e){} }
} %> <% if(session.isNew()) {countPeople(); String str=String.valueOf(number); session.setAttribute("count",str); } %> <P>您是第<%=(String)session.getAttribute("count")%>个访问本站的人。 <BODY> <HTML> 3.4 application对象 我们已经知道,当一个客户第一次访问服务器上的一个JSP页面时,JSP引擎创建一个和该客户相对应的session对象,当客户在所访问的网站的各个页面之间浏览时,这个session对象都是同一个,直到客户关闭浏览器,这个session对象才被取消;而且不同客户的session对象是互不相同的。与session对象不同的是application对象。服务器启动后,就产生了这个application对象。当一个客户访问服务器上的一个JSP页面时,JSP引擎为该客户分配这个application对象,当客户在所访问的网站的各个页面之间浏览时,这个application对象都是同一个,直到服务器关闭,这个application对象才被取消。与session对象不同的是,所有客户的application对象是相同的一个,即所有的客户共享这个内置的application对象。我们已经知道,JSP引擎为每个客户启动一个线程,也就是说,这些线程共享这个application对象。 3.4.1 application 对象的常用方法 (1) public void setAttribute(String key ,Object obj) application对象可以调用该方法将参数Object 指定的对象 obj添加到application对象中,并为添加的对象指定了一个索引关键字,如果添加的两个对象的关键字相同,则先前添加对象被清除。 (2) public Object getAttibue(String key) 获取application对象含有的关键字是key的对象。由于任何对象都可以添加到application对象中,因此用该方法取回对象时,应强制转化为原来的类型。 (3) public Enumeration getAttributeNames() application对象调用该方法产生一个枚举对象,该枚举对象使用nextElemets()遍历application对象所含有的全部对象。 (4) public void removeAttribue(String key) 从当前application对象中删除关键字是key的对象。 (5) public String getServletInfo() 获取Servlet编译器的当前版本的信息。 由于application对象对所有的客户都是相同的,任何客户对该对象中存储的数据的改变都会影响到其他客户,因此,在某些情况下,对该对象的操作需要实现同步处理。 在下面的例子中,我们用application对象实现一个计数器,将计数存放在application对象中,每个客户对该对象中“计数”的改变都会影响到其他客户。 注:有些服务器不直接支持使用application对象,必须用ServletContext类声明这个对象,再使用getServletContext()方法对这个application对象进行初始化。
例子20 <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <%! synchronized void countPeople() { ServletContext application=getServletContext(); Integer number=(Integer)application.getAttribute("Count"); if(number==null) { number=new Integer(1); application.setAttribute("Count",number); } else { number=new Integer(number.intValue()+1); application.setAttribute("Count",number); } } %> <% if(session.isNew()) { countPeople(); Integer myNumber=(Integer)application.getAttribute("Count"); session.setAttribute("MyCount",myNumber); } %> <P><P>您是第 <%int a=((Integer)session.getAttribute("MyCount")).intValue(); %> <%=a%> 个访问本站的客户。 </BODY> </HTML>
3.4.2 用application制作留言板 在例子21中,客户通过submit.jsp向messagePane.jsp页面提交姓名、留言标题和留言内容,messagePane.jsp页面获取这些内容后,用同步方法将这些内容添加到一个向量中,然后将这个向量再添加到application对象中。当用户点击查看留言版时,showMessage.jsp负责显示所有客户的留言内容,即从application对象中取出向量,然后遍历向量中存储的信息。 在这里我们使用了向量这种数据结构,Java的java.util包中的Vector类负责创建一个向量对象。如果你已经学会使用数组,那么很容易就会使用向量。当我们创建一个向量时不用象数组那样必须要给出数组的大小。向量创建后,例如,Vector a=new Vector();a可以使用add(Object o)把任何对象添加到向量的末尾,向量的大小会自动的增加。可以使用add(int index ,Object o)把一个对象追加到该向量的指定位置。向量a可以使用elementAt(int index )获取指定索引处的向量的元素(索引初始位置是0);a可以使用方法size()获取向量所含有的元素的个数。另外,与数组不同的是向量的元素类型不要求一致。需要注意的是,虽然你可以把任何一种Java的对象放入一个向量,但是,当从向量中取出一个元素时,必须使用强制类型转化运算符将其转化为原来的类型。 例子21(如图3.20所示) submit.jsp: <%@ page contentType="text/html;charset=GB2312" %> <HTML> <BODY> <FORM action="messagePane.jsp" method="post" name="form"> <P>输入您的名字: <INPUT type="text" name="peopleName"> <BR> <P>输入您的留言标题: <INPUT type="text" name="Title"> <BR> <P>输入您的留言: <BR> <TEXTAREA name="messages" ROWs="10" COLS=36 WRAP="physical"> </TEXTAREA> <BR> <INPUT type="submit" value="提交信息" name="submit"> </FORM> <FORM action="showMessage.jsp" method="post" name="form1"> <INPUT type="submit" value="查看留言板" name="look"> </FORM> </BODY> </HTML>
messagePane.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <HTML> <BODY> <%! Vector v=new Vector(); int i=0; ServletContext application; synchronized void sendMessage(String s) { application=getServletContext();; i++; v.add("No."+i+","+s); application.setAttribute("Mess",v); } %> <% String name=request.getParameter("peopleName"); String title=request.getParameter("Title"); String messages=request.getParameter("messages"); if(name==null) {name="guest"+(int)(Math.random()*10000); } if(title==null) {title="无标题"; } if(messages==null) {messages="无信息"; } String s="Name:"+name+"#"+"Title:"+title+"#"+"Content:"+"<BR>"+messages; sendMessage(s); out.print("您的信息已经提交!"); %> <A HREF="submit.jsp" >返回 </BODY> </HTML>
showMessage.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <HTML> <BODY> <% Vector v=(Vector)application.getAttribute("Mess"); for(int i=0;i<v.size();i++) { String message=(String)v.elementAt(i); StringTokenizer fenxi=new StringTokenizer(message,"#"); while(fenxi.hasMoreTokens()) { String str=fenxi.nextToken(); byte a[]=str.getBytes("ISO-8859-1"); str=new String(a); out.print("<BR>"+str); } } %> </BODY> </HTML> 3.5 out 对象 out对象是一个输出流,用来向客户端输出数据。在前面的许多例子里曾多次使用out对象进行数据的输出。out对象可调用如下的方法用于各种数据的输出,例如: out.print(Boolean),out.println(boolean) :用于输出一个布尔值。 out.print(char),out.println(char) :输出一个字符。 out.print(double),out.println(double) :输出一个双精度的浮点数。 out.print(fload),out.println(float) :用于输出一个单精度的浮点数。 out.print(long),out.println(long) :输出一个长整型数据。 out.print(String),out.println(String) :输出一个字符串对象的内容。 out.newLine() :输出一个换行符 out.flush() :输出缓冲区里的内容 out.close() :关闭流
下面的例子22使用out对象向客户输出包括表格等内容的信息。
例子22(如图3.21所示) Example3_22.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <HTML> <BODY> <% int a=100;long b=300;boolean c=true; out.println("<H1>这是标题1字体的大小</HT1>"); out.println("<H2>这是标题2字体的大小</HT2>"); out.print("<BR>"); out.println(a); out.println(b); out.println(c); %> <Center> <p><Font size=2 >以下是一个表格</Font> <%out.print("<Font face=隶书 size=2 >"); out.println("<Table Border >"); out.println("<TR >"); out.println("<TH width=80>"+"姓名"+"</TH>"); out.println("<TH width=60>"+"性别"+"</TH>"); out.println("<TH width=200>"+"出生日期"+"</TH>"); out.println("</TR>"); out.println("<TR >"); out.println("<TD >"+"刘甲一"+"</TD>"); out.println("<TD >"+"男"+"</TD>"); out.println("<TD >"+"1978年5月"+"</TD>"); out.println("</TR>"); out.println("<TR>"); out.println("<TD >"+"林 霞"+"</TD>"); out.println("<TD >"+"女"+"</TD>"); out.println("<TD >"+"1979年8月"+"</TD>"); out.println("<TD width=100>"+"这是表格"+"</TD>"); out.println("</TR>"); out.println("</Table>"); out.print("</Font>") ; %> </Center> </BODY> </HTML> 下面的例子23根据当前时间向客户发送提示信息,比如,如果是26日,就发送病毒易发作的信息等。 例子23(如图3.22所示) time.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*"%> <%! public String getDayWeek(int n) { String week[]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"}; return week[n]; } %> <HTML> <BODY bgcolor=cyan><Font size=1> <% Calendar calendar=Calendar.getInstance(); //创建一个日历对象。 calendar.setTime(new Date());//用当前时间初始化日历时间。 String 年=String.valueOf(calendar.get(Calendar.YEAR)), 月=String.valueOf(calendar.get(Calendar.MONTH)+1), 日=String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)), 星期=getDayWeek(calendar.get(Calendar.DAY_OF_WEEK)-1); int hour=calendar.get(Calendar.HOUR_OF_DAY), minute=calendar.get(Calendar.MINUTE), second=calendar.get(Calendar.SECOND); %> <P>现在的时间是<BR> <%=年%>年 <%=月%>月 <%=日%>日 <%=星期%> <BR> <%=hour%>点 <%=minute%>分 <%=second%>秒 <% if(日.equals("26")) {out.print("<BR><H2>今天是病毒容易发作的日子!</H2>"); } if(hour>=22) { out.print("<BR><H2>现在时间很晚了注意休息</H2>"); } %> </FONT> </BODY> </HTML>
|