第3章 JSP隐含对象 前一章主要介绍了JSP页面的组成元素及其使用。本章主要介绍如何简化页面开发的复杂性,JSP提供了一些由容器实现和管理的隐含对象,也就是说,用户不需要实例化就可以直接使用的对象,通过存取这些隐含对象实现与JSP页面的Servlet环境的相互访问,因此要求用户必须熟悉这些对象,并掌握其主要方法的使用。 对象的4种有效范围 JSP有9个隐含对象 JSP容器提供了以下几个隐含对象,它们是: request、response、out、session、application、config、page、pageContext和exception。由于JSP是构建在Servlet上的,从本质上来讲,JSP的每个隐含对象都与Java Servlet API包中的类相对应,在服务器运行时自动生成。本章对它们进行详细的介绍。 3.1对象的属性与有效范围 1. 对象的属性 JSP技术提供给开发人员一种传递数据的机制,就是利用setAttribute()和getAttribute()方法。 1) setAttribute()方法 setAtrribute是应用服务器把对象放在该页面对应的一块内存中,当页面服务器重定向到另一个页面中时,应用服务器会把这块内存拷贝到另一个页面所对应的内存中。这种方式可以传对象,对于不同的隐含对象,这个传递的对象在内存中的生命周期不同。 方法的声明格式: void setAttribute(String name,Object object) 说明: 将对象object绑定到Servlet上下文中提供的属性名称name中,如果指定的名称已经使用,则方法setAttribute()将该属性值替换为新的属性值。 2) getAttribute()方法 getAttribute用于获取容器中的数据。但它只能接收setAttribute传过来的数据值。方法的声明格式: Object getAttribute(String name) 说明: 返回指定名称的属性值,如果属性不存在,则返回null。与setAttribute方法配合使用可实现两个JSP文件之间的参数传递。 例如,定义类User(带参数的构造方法及getName()方法)的对象curruser: User curruser = new User("susan", 20, "女"); 则request.setAttribute("curruser", curruser)方法就是将curruser这个对象保存在request作用域中,然后在转发进入的页面就可以获取值,可以在JSP页面编写Java小脚本来获取: <% User myuser = (User)request.getAttribute("curruser")%>,在JSP页面显示值: <%=myuser.getName()%>。 2. 对象的有效范围 有时会将pageContext、request、session和application归为一类,原因在于它们都借助以上setAttribute()和getAttribute()方法来设定和取得其属性。而这4个隐含对象最大的区别在于其范围不同。 1) 页内有效 具有页内有效范围的对象被绑定到javax.servlet.jsp.PageContext对象中。在这个范围内的对象,只能在创建对象的页面中访问。可以调用pageContext这个隐含对象的getAttribute()方法来访问具有这种范围类型的对象(pageContext对象还提供了访问其他范围对象的getAttribute方法),pageContext对象本身也属于page范围。page范围内的对象,在客户端每次请求JSP页面时创建,在页面向客户端发送回响应或请求被转发(forward)到其他的资源后被删除。 例3.1在同一JSP页面pageSetGet.jsp中利用pageContext对象、利用setAttribute()和getAttribute()两个方法实现对参数的设值和取值。代码如下: <!-- pageSetGet.jsp --> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>页内有效范围</title> </head> <body> 页内有效 - 使用页面上下文对象pageContext.setAttribute()和pageContext.getAttribute() <p/> <% pageContext.setAttribute("歌曲名称","爸爸去哪儿"); %> <em> <% String Name = (String)pageContext.getAttribute("歌曲名称"); out.print(" 歌曲名称 = "+ Name); %> </em> </body> </html> 将该文件放在FirstJSP项目下,运行界面如图3.1所示。 图3.1同一页面的pageContext对象的执行结果 在同一个页面内,参数的设值和取值均能实现。 如果现在将设值和取值分别放在两个不同的页面,结果会是如何呢? 例3.2修改例3.1,参数的设置放在pageSet.jsp中,代码如下: <!-- pageSet.jsp --> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>页内有效范围</title> </head> <body> < 页内有效 - 使用页面上下文对象pageContext.setAttribute() <% pageContext.setAttribute("歌曲名称","爸爸去哪儿"); %> <jsp:forward page="pageGet.jsp"/> </body> </html> 参数的取值放在pageGet.jsp中,代码如下: <!-- pageGet.jsp --> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>页内有效范围</title> </head> <body> <h3>页内有效 - 使用页面上下文对象pageContext.getAttribute()</h3> <em> <% String Name = (String) pageContext.getAttribute("歌曲名称"); out.print(" 歌曲名称 = "+Name); %> </em> </body> </html> 将两个文件放在FirstJSP项目下,执行http://localhost: 8080/FirstJSP/pageSet.jsp后运行界面如图3.2所示。 图3.2不同页面的pageContext对象的执行结果 2) 请求有效 请求有效的对象在同一请求不同JSP页面内都可以访问。如果请求转向到同一运行时(Runtime)的其他资源,那么这些对象依然有效。请求有效的对象在请求处理结束时就会失效。所有的请求有效的对象都存储在JSP页面的request对象中。 request对象在服务器启动时自动创建,是javax.servlet.HttpServletRequest接口的一个实例。request对象的作用是与客户端交互,收集客户端的Form、Cookies、超链接或收集服务器端的环境变量。 例3.3修改例3.2中的pageSet.jsp和pageGet.jsp,将pageContext对象修改为request对象。 requestSet.jsp代码如下: <!-- requestSet.jsp --> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>请求有效范围</title> </head> <body> < 请求有效 - 使用request对象request.setAttribute() <% request.setAttribute("歌曲名称","爸爸去哪儿"); %> <jsp:forward page="requestGet.jsp"/> </body> </html> requestGet.jsp代码如下: <!-- requestGet.jsp --> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>请求有效范围</title> </head> <body> <h3>请求有效 - 使用request对象request.getAttribute()</h3> <em> <% String Name = (String)request.getAttribute("歌曲名称"); out.print(" 歌曲名称 = "+Name); %> </em> </body> </html> 运行结果如图3.3所示。 图3.3请求有效 从两个运行结果可以看出,request对象在不同的页面进行设值和取值显示正常,也就是说,两个页面之间的请求有效。如果在第三个页面中再获取参数将会失败。除了利用转向(forward)的方法可以存取request对象的数据外,还能使用包含(include)的方法,观察两者的异同。 3) 会话有效 会话是指客户端和服务器之间持续连接的一段时间。在这段时间内,当需要多次和服务器交互信息时,可以将有关信息存入session对象中,这些信息是会话有效的。在与服务器断线后,就会失效。可以说,session的作用范围就是一段用户持续和服务器连接的时间。 会话有效的所有对象都存储在JSP页面的session对象中。 例3.4修改例3.3,修改requestSet.jsp为seesionSet.jsp,requestGet.jsp修改为sessionGet1.jsp,并在该代码中添加<jsp: include>,包含sessionGet2.jsp页面,重新获取参数并显示。 seesionSet.jsp代码如下: <!-- sessionSet.jsp --> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>会话有效范围</title> </head> <body> 会话有效 - 使用session对象session.setAttribute() <% session.setAttribute("歌曲名称","爸爸去哪儿"); %> <jsp:forward page="sessionGet1.jsp"/> </body> </html> sessionGet1.jsp代码如下: <!-- sessionGet1.jsp --> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>会话有效范围</title> </head> <body> <h3>会话有效 - 使用session对象session.getAttribute()</h3> <em> <% String Name = (String)session.getAttribute("歌曲名称"); out.print(" 歌曲名称 = "+Name); %> <jsp:include page="sessionGet2.jsp"/> </em> </body> </html> sessionGet2.jsp代码如下: <!-- sessionGet2.jsp --> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>会话有效范围</title> </head> <body> <h3>会话有效2 - 使用session对象session.getAttribute()</h3> <em> <% String Name = (String)session.getAttribute("歌曲名称"); out.print(" 歌曲名称重新显示 = "+Name); %> </em> </body> </html> 运行效果如图3.4所示。 图3.4session对象 由该例可以看出,只要在一个会话中,多个页面都可以获取参数。但是如果是在多个会话之间,则不能获取参数。 4) 应用有效 应用有效的作用范围是从Web应用服务器一开始执行服务直到结束服务为止。应用有效范围最大、影响最长。应用有效的对象都存储在JSP页面的application对象中,其实就是服务端Servlet上下文信息对象(ServletContext)。在实际使用时注意不要使用过多,以免造成服务器负载过大。 例3.5修改例2.4中的登录页面content.jsp,在代码最后添加如下脚本: <% application.setAttribute("manager", request.getParameter("manager")); application.setAttribute("pwd", request.getParameter("pwd")); %> 另创建一个TestApplication.jsp页面,与content.jsp表面上没有关系,代码如下: <!-- TestApplication.jsp --> <%@ page language="java" contentType="text/html; charset=GBK"%> <% request.setCharacterEncoding("GBK"); %> <html> <body> 用户名:<%=application.getAttribute("manager") %><br> 密 码:<%=application.getAttribute("pwd") %><br> </body> </html> 运行content.jsp,如图3.5所示,并在“管理员”文本框中输入application,在“密码”文本框中输入test,然后单击“确定”按钮。 图3.5有关application的登录界面 再运行TestApplication.jsp页面,显示效果如图3.6所示。 图3.6利用application对象获取信息 可以看出,访问同一个网站的客户都共享一个application对象,因此,application对象可以实现多客户间的数据共享。 3.2JSP的隐含对象 JSP 2.0中有9个隐含对象,其名称、实现类及说明如表3.1所示。 表3.19个隐含对象 JSP隐含对象 实现类 对 象 说 明 out JspWriter HTML标准输出 request HttpServletRequest 请求信息 response HttpServletResponse 响应信息 application ServletContext 服务端Servlet上下文信息 session HttpSession HTTP联机会话信息 config ServletConfig JSP页面的Servlet配置信息,由Web应用配置描述文件(web.xml)指定 exception Throwable 异常处理信息 page Object 如同Java中的this pageContext PageContext 当前JSP页面的上下文信息 3.2.1案例1: 使用out隐含对象 第2章介绍过表达式可以完成输出,但是表达式在求值之后的结果转换成了String对象,该对象被发送到out对象中,也就是说,客户端浏览器中显示的信息,就是服务器端通过out对象实现的。 out对象的常用方法如表3.2所示。 表3.2out常用方法 方 法 名 称 方 法 说 明 public abstract void clear() 清除缓冲区中的内容,不将数据发送至客户端 public abstract void clearBuffer() 将数据发送至客户端后,清除缓冲区中的内容 public abstarct void close() 关闭输出流 public abstract void flush() 输出缓冲区中的数据 public int getBufferSize() 获取缓冲区的大小。缓冲区的大小可用<%@ page buffer="size" %>设置 public abstract int getRemainning() 获取缓冲区剩余空间的大小 public boolean isAutoFlush() 获取用<%@ page is AutoFlush="true/false"%>设置的AutoFlush值 public abstract void newLine() 输出一个换行字符,换一行 public abstract void print() 显示各种数据类型的内容 public abstract void println() 分行显示各种数据类型的内容 在JSP中,out对象主要用来管理响应缓冲和向客户端输出内容。 例3.6利用out.print和表达式两种方式进行输出。 out1.jsp采用out.print方式输出,代码如下: <!-- out1.jsp --> <%@ page language="java" buffer="1kb" autoFlush="true" contentType="text/html;charset=GB2312"%> <html> <head> <title>out对象</title> </head> <body> <% out.println("<h2>Hello!</h2>"); out.println("BufferSize of the Out Object is:"+out.getBufferSize()+"<br>"); out.println("Remain of BufferSize is:"+out.getRemaining()+"<br>"); %> <% for(int i=0;i<5;i++) out.println("<h3>Test </h3>") ; %> <%out.println("autoFlush:"+out.isAutoFlush()); %> </body> </html> out2.jsp采用表达式方式输出,代码如下: <!-- out2.jsp --> <%@ page language="java" buffer="1kb" autoFlush="true" contentType="text/html;charset=GB2312"%> <html> <head> <title>out对象</title> </head> <body> <h2>Hello!</h2> BufferSize of the Out Object is:<%=out.getBufferSize() %><br> Remain of BufferSize is:<%=out.getRemaining() %><br> <% for(int i=0;i<5;i++) out.println("<h3>Test </h3>") ; %> autoFlush:<%=out.isAutoFlush() %> </body> </html> 两个页面的运行结果都如图3.7所示。 图3.7out对象 值得注意的是,程序实际在处理时是先将数据放在缓冲区,等JSP容器解析完整个程序后才把缓冲区的数据输出到客户端浏览器上。在page指令中buffer="1kb"代表缓冲区为1kb,autoFlush属性为false时,当数据超过1kb时,则出现错误,所以这里设autoFlush="true"。 3.2.2案例2: 使用request隐含对象 request对象是从客户端向服务器发出请求,包括用户提交的信息以及客户端的一些信息。客户端可通过HTML表单或在网页地址后面提供参数的方法提交数据,然后通过request对象的相关方法来获取这些数据。request的各种方法主要用来处理客户端浏览器提交的请求中的各项参数和选项。常见的方法如表3.3所示。 表3.3request常用方法 方 法 名 称 方 法 说 明 public java.lang.Object getAttribute(java.lang.String name) 返回以name为名字的属性的值。如果该属性不存在,这个方法将返回null public java.util.Enumeration getAttributeNames() 返回请求中所有可用的属性的名字。如果在请求中没有属性,这个方法将返回一个空的枚举集合 public void removeAttribute(java.lang.String name) 移除请求中名字为name的属性 public void setAttribute(java.lang.String name, java.lang.Object o) 在请求中保存名字为name的属性。如果第二个参数o为null,那么相当于调用removeAttribute(name) public java.lang.String getCharacterEncoding() 返回请求正文使用的字符编码的名字。如果请求没有指定字符编码,这个方法将返回null public int getContentLength() 以字节为单位,返回请求正文的长度。如果长度不可知,这个方法将返回1 public java.lang.String getContentType() 返回请求正文的MIME类型。如果类型不可知,这个方法将返回null public ServletInputStream getInputStream() 返回一个输入流,使用该输入流以二进制方式读取请求正文的内容。javax.servlet.ServletInputStream是一个抽象类,继承自java.io.InputStream public java.lang.String getLocalAddr() 返回接收到请求的网络接口的IP地址,这个方法是在Servlet 2.4规范中新增的 public java.lang.String getLocalName() 返回接收到请求的IP接口的主机名,这个方法是在Servlet 2.4规范中新增的 public int getLocalPort() 返回接收到请求的网络接口的IP端口号,这个方法是在Servlet 2.4规范中新增的 续表 方 法 名 称 方 法 说 明 public java.lang.String getParameter(java.lang.String name) 返回请求中name参数的值。如果name参数有多个值,那么这个方法将返回值列表中的第一个值。如果在请求中没有找到这个参数,这个方法将返回null public java.util.Enumeration getParameterNames() 返回请求中包含的所有参数的名字。如果请求中没有参数,这个方法将返回一个空的枚举集合 public java.lang.String[] getParameterValues(java.lang.String name) 返回请求中name参数所有的值。如果这个参数在请求中并不存在,这个方法将返回null public java.lang.String getProtocol() 返回请求使用的协议的名字和版本,例如: HTTP/1.1 public java.io.BufferedReader getReader()throws java.io.IOException 返回BufferedReader对象,以字符数据方式读取请求正文 public java.lang.String getRemoteAddr() 返回发送请求的客户端或者最后一个代理服务器的IP地址 public java.lang.String getRemoteHost() 返回发送请求的客户端或者最后一个代理服务器的完整限定名 public int getRemotePort() 返回发送请求的客户端或者最后一个代理服务器的IP源端口,这个方法是在Servlet 2.4规范中新增的 public RequestDispatcher getRequestDispatcher(java.lang.String path) 返回RequestDispatcher对象,作为path所定位的资源的封装 public java.lang.String getServerName() 返回请求发送到的服务器的主机名 public int getServerPort() 返回请求发送到的服务器的端口号 public void setCharacterEncoding(java.lang.String env)throws java.io.Unsupported EncodingException 覆盖在请求正文中所使用的字符编码的名字 public HttpSession getSession() 取得与当前请求绑定的session,如果当前session不存在,则为这个请求创建一个新的session 例3.7利用request常见方式,显示客户端发送的HTTP请求包的信息、获取到的客户端和服务器端的信息。 <!-- request.jsp --> <%@ page contentType="text/html;charset=GBk" import="java.util.*"%> <html> <head> <title>request的使用</title> </head> <body> <p>您的客户端发送的HTTP请求头包含如下信息:</p> <% Enumeration enum1 = request.getHeaderNames(); while (enum1.hasMoreElements()) { String headerName = (String) enum1.nextElement(); String headerValue = request.getHeader(headerName); %> <b><%= headerName %></b>:<%= headerValue %><br> <%}%> <p>使用request对象的方法获取如下信息:</p> <% //服务器 String localName=request.getLocalName(); String serverName = request.getServerName(); String localAddr=request.getLocalAddr(); int localPort=request.getLocalPort(); int serverPort = request.getServerPort();%> <b>服务器</b>:<%= localName %><br/> <b>服务器端IP</b>:<%= localAddr %><br/> <b>服务器端口</b>:<%= localPort %><p/> <% //客户端信息 String remoteHost=request.getRemoteHost(); String remoteAddr=request.getRemoteAddr(); int remotePort=request.getRemotePort();%> <b>浏览器端</b>:<%= remoteHost %><br/> <b>浏览器端IP是</b>:<%= remoteAddr %><br/> <b>浏览器端口</b>:<%= remotePort %><p/> <% //协议相关 String pro=request.getProtocol(); String pro1=request.getScheme(); int len=request.getContentLength(); String type=request.getContentType(); String charEncode=request.getCharacterEncoding(); %> <b>协议版本</b>:<%= pro %><br/> <b>协议</b>:<%= pro1 %><br/> <b>数据内容长度</b>:<%= len %><br/> </body> </html> 运行界面如图3.8所示。 图3.8request对象方法的使用 在Web动态网站技术中,重要的一个环节就是获取从客户端发送的请求信息,如客户端表单登录信息、客户查询信息等,并根据提交信息做进一步操作。在JSP程序中,完成从客户端获取数据的方法可以是getParameter()、getParameterName()和getParameterValues(),其中比较常用的为getPatameter()方法。getPatameter()方法与getAttribute()方法不同,二者的区别主要是: getParameter()通过容器的实现来取得类似post、get等方式传入的数据; setAttribute()和getAttribute()只是在Web容器内部流转,仅仅是请求处理阶段。 getParameter()方法传递的数据,会从Web客户端传到Web服务器端,代表HTTP请求数据。getParameter()方法返回String类型的数据。setAttribute()和getAttribute()方法传递的数据只会存在于Web容器内部。 HttpServletRequest类有setAttribute()方法,而没有setParameter()方法。 通常情况下,当一个浏览器向Web站点提出页面请求时,首先向服务器发送连接请求,请求的内容包括服务器地址、请求的页面路径等。服务器会将它们组合成确定所请求的页面,返回到客户端。客户端向服务器发送数据时,通常采用get方法或post方法。二者的区别如下: get是从服务器上获取数据; post是向服务器传送数据。 get是把参数数据队列加到提交表单的action属性所指的URL中,值和表单内各个字段要一一对应,在URL中可以看到; post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到action属性所指的URL地址,用户看不到这个过程。 对于get方式,服务器端用request.QueryString获取变量的值; 对于post方式,服务器端用request.Form获取提交的数据。 get传送的数据量较小,不能大于2KB; post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。 get安全性非常低,但是执行效率却比post方法好; post安全性较高。get方式的安全性较post方式要差些,包含机密信息的话,建议用post数据提交方式; 数据查询时,建议用get方式; 而数据添加、修改或删除时,建议用post方式。 3.2.3案例3: 使用response隐含对象 response对象是javax.servlet.ServletResponse接口中的一个针对HTTP协议和实现的子类的实例。Response对象是表示服务器对请求的响应的HttpServletResponse对象,用于动态响应客户端请示,控制发送给用户的信息,并将动态生成响应。 response对象和request对象功能恰好相反,request对象封装的是客户端提交的信息,而对象封装的是返回客户端的信息。response对象和request对象的作用域相同。response对象也由容器生成,作为jspService()方法的参数被传入JSP。 response方法可以分为三类: 设定表头方法、设定响应状态码和重定向方法。具体如表3.4所示。 表3.4response方法 方 法 名 称 方 法 说 明 String getCharacterEncoding() 返回在响应中发送的正文所使用的字符编码(MIME字符集) ServletOutputStream getOutputStream() 返回ServletOutputStream对象,用于在响应中写入二进制数据 public java.lang.String getContentType() 返回在响应中发送的正文所使用的MIME类型 PrintWriter getWriter() 返回PrintWriter对象,用于发送字符文本到客户端 void setContentLength(int len) 对于HTTP Servlet,在响应中,设置内容正文的长度 void setBufferSize(int size) 设置响应正文的缓存大小 void setDateHeader(String name,long date) 指定long类型的值到name标头 void setHeader(String name,String value) 指定String类型的值到name标头 void setIntHeader(String name,int value) 指定int类型的值到name标头 void sendError(int sc, String msg) 传送状态码和错误信息 void setStatus(int sc) 设定状态码 String encodeRedirectURL(String url) 对使用sendRedirect( )方法的URL予以编码 abstract void sendRedirect(String url ) 将客户端的响应重定向到指定的URL(JSP页面、HTML页面或Servlet等)上 在动态网站的操作中,经常需要从一个页面转向到另一个页面,如登录成功与否,可能需要转向不同的页面。要达到页面重定向的效果,可以采用第2章的动作指令jsp: forward,也可以采用response对象的sendRedirect方法。该方法的具体格式为: public abstract void sendRedirect(String url) 例3.8将前面请求有效的例子进行修改,将requestSet.jsp中转向页面的<jsp: forward>语句修改为: <%response.sendRedirect("requestGet.jsp"); %>,requestGet.jsp保持不变,则运行界面如图3.9所示。 图3.9response对象的应用 从执行效果可以看出,动作指令jsp: forward与sendRedirect(String url)方法的不同在于以下几点: 1. 地址栏显示不同 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器。浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址,即仍为http://localhost:8080/FirstJSP/requestSet.jsp,但显示的内容却是requestGet.jsp的结果。 redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的URL,即为http://localhost: 8080/FirstJSP/requestGet.jsp。redirect等于客户端向服务器端发出两次request,同时也接受两次response。 2. 数据共享不同 forward转发页面和转发到的页面可以共享request中的数据,所以提取出来的歌曲名能正确显示,而redirect不能共享数据,提取出来的数据为null。 3. 重定向范围不同 redirect不仅可以重定向到当前应用程序的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。forward只能在同一个Web应用程序内的资源之间转发请求。 3.2.4案例4: 使用application隐含对象 一个Web服务器通常有多个Web服务目录(网站),当Web服务器启动时,它自动为每个Web服务目录都创建一个application对象,这些application对象各自独立,而且和Web服务目录一一对应。访问同一个网站的客户都共享一个application对象,因此,application对象可以实现多客户间的数据共享。 一个Web应用程序启动后,将会自动创建一个application对象,而且在整个应用程序的运行过程中只有一个application对象,就是说所有访问该网站的客户都共享一个application对象。不管哪个客户来访问网站A,也不管客户访问网站A下的哪个页面文件,都可以对网站A的application对象进行操作,因为所有访问网站A的客户都共用一个application对象。访问不同网站的客户,对应的application对象不同。 application对象的基类是javax.servlet.ServletContext类,有些Web服务器不直接支持使用application对象,必须用ServletContext类(用于表示应用程序的上下文)来声明application对象,再调用getServletContext()方法来获取当前页面的application对象。application常用方法见表3.5。 表3.5application常用方法 方 法 名 称 方 法 说 明 String getAttribute(String name) 根据属性名称获取属性值 Enumeration getAttributeNames() 获取所有的属性名称 void setAttribute(String name, Object object) 设置属性,指定属性名称和属性值 void removeAttribute(String name) 根据属性名称删除对应的属性 ServletContext getContext(String uripath) 获取指定URL的ServletContext对象 String getContextPath() 获取当前Web应用程序的根目录 String getInitParameter(String name) 根据初始化参数名称,获取初始化参数值 int getMajorVersion() 获取Servlet API的主版本号 int getMinorVersion() 获取Servlet API的次版本号 String getMimeType(String file) 获取指定文件的MIME 类型 String getServletInfo() 获取当前Web服务器的版本信息 String getServletContextName() 获取当前Web应用程序的名称 void log(String message) 将信息写入日志文件中例3.9利用application对象设计一个所有用户对某网页的访问次数,并显示当前服务器的版本号。counter.jsp代码如下: <!-- counter.jsp --> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% //判断application对象中有没有保存名为count的参数 //如果没有,在application对象中新增一个名为count的参数 if(application.getAttribute("count")==null){ application.setAttribute("count", new Integer(0)); } Integer count = (Integer)application.getAttribute("count"); //使用application对象读取count参数的值,再在原值基础上累加1 application.setAttribute("count",new Integer(count.intValue()+1)); %> <h2> <!-- 输出累加后的count参数对应的值 --> 欢迎您访问,本页面已经被访问过 <font color="#ff0000"><%=application.getAttribute("count") %></font>次。 </h2> 当前服务器的版本为 <%=application.getServerInfo()%> </body> </html> 运行界面如图3.10所示。 图3.10统计网页的访问次数 值得注意的是,本例采用的是application对象,但在服务器重启后计数将重新开始。 3.2.5案例5: 使用session隐含对象 session对象是java.servlet.http.HttpSession子类的对象,表示当前的用户会话信息。在session中保存的对象在当前用户连接的所有页面中都是可以被访问到的,在3.1中已经指出了这一特点。 当用户登录网站时,系统会自动分配给用户一个session ID,用来标识不同的访问客户。JSP容器会将这个ID号发送到客户端,保存在客户的Cookie中,这样session对象和客户之间就建立起一一对应的关系,即每个客户对应一个session对象。 1. Cookie对象 Cookie对象是javax.servlet.http.Cookie的实例,是由Web服务器端产生后被保存到浏览器中的信息。Cookie对象可以用来保存一些信息在浏览器中,当浏览器请求服务器的页面时会自动发送到服务器端。目前主流的浏览器IE、Netscape Navigator都支持Cookie。大多数浏览器允许用户禁止Cookie的使用,因此,如果应用中必须使用Cookie对象,一定要提示用户。 Cookie对象的属性如表3.6所示。 表3.6Cookie的属性 属性名 说明 name Cookie名称 value Cookie值 domain 只有在该域中的服务器才会发送该Cookie,例如,www.bjtu.edu.cn maxAge Cookie持续存在的时间,-1表示一直有效 path 只有URL中包含指定的路径的服务器才发送该Cookie,例如,helloBeijing secure 是否仅当使用https协议才发送Cookie。https是http的加密形式 Cookie对象的常用方法如表3.7所示。 表3.7Cookie的方法 方 法 名 称 方 法 说 明 String getComment() 返回Cookie中注释,如果没有注释的话将返回空值 String getDomain() 返回Cookie中Cookie适用的域名,使用getDomain()方法可以指示浏览器把Cookie返回给同一域内的其他服务器,而通常Cookie只返回给与发送它的服务器名字完全相同的服务器。注意域名必须以点开始(例如,yesky.com) int getMaxAge() 返回Cookie过期之前的最大时间,以秒计算 String getName() 返回Cookie的名字 String getPath() 返回Cookie适用的路径。如果不指定路径,Cookie将返回给当前页面所在目录及其子目录下的所有页面 boolean getSecure() 如果浏览器通过安全协议发送Cookie将返回true值,如果浏览器使用标准协议则返回false值 String getValue() 返回Cookie的值 int getVersion() 返回Cookie所遵从的协议版本 void setComment(String purpose) 设置Cookie中注释 void setDomain(String pattern) 设置Cookie中Cookie适用的域名 void setMaxAge(int expiry) 以秒计算,设置Cookie过期时间 void setPath(String uri) 指定Cookie适用的路径 void setSecure(boolean flag) 指出浏览器使用的安全协议,例如HTTPS或SSL void setValue(String newValue) Cookie创建后设置一个新的值 void setVersion(int v) 设置Cookie所遵从的协议版本 例3.10简单地写入和读出Cookie。 写入Cookie的writeCookie.jsp代码如下: <!-- writeCookie.jsp --> <%@ page language="java" import="java.util.*" pageEncoding="GB2312"%> <% String str1="hello"; Cookie c=new Cookie("str2",str1); response.addCookie(c); %> 正在将<%=str1%>写入Cookie...<br> <jsp:include page="readCookie.jsp"/> 读出cookie的readCookie.jsp代码如下: <!-- readCookie.jsp --> <%@ page language="java" import="java.util.*" pageEncoding="GB2312"%> <br> 读出Cookie的值: <% Cookie cookies[]=request.getCookies(); for(int i=0;i<cookies.length;i++){ if(cookies[i].getName().equals("str2")) out.print(cookies[i].getValue()); } %> 运行writeCookie.jsp的结果如图3.11所示。 图3.11读写Cookie对象 2. Session对象 Session的常用方法如表3.8所示。 表3.8Session的常用方法 方 法 名 称 方 法 说 明 void setAttribute(String attribute, Object value) 设置Session属性。value参数可以为任何Java Object。通常为Java Bean。value信息不宜过大 String getAttribute(String attribute) 返回Session属性 Enumeration getAttributeNames() 返回Session中存在的属性名 void removeAttribute(String attribute) 移除Session属性 String getId() 返回Session的ID。该ID由服务器自动创建,不会重复 long getCreationTime() 返回Session的创建日期。返回类型为long,常被转化为Date类型,例如,Date createTime = new Date(session.getCreationTime()) long getLastAccessedTime() 返回Session的最后活跃时间。返回类型为long int getMaxInactiveInterval() 返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效 void setMaxInactiveInterval(int second) 设置Session的超时时间。单位为秒 例3.11该案例包含三个文件,一个登录界面login.jsp,一个判断页面select.jsp,如果输入用户名为“susan”,密码为“1234”时,跳转到ok.jsp页面,若成功跳转将会显示session的ID及用户名,如果用户名或密码错误直接给出提示。 login.jsp的代码如下: <!-- login.jsp --> <%@ page contentType="text/html; charset=UTF-8" language="java" %> <html> <head> <title>在线音乐_用户登录</title> </head> <body> <jsp:include page="top.jsp"/> <div id="navigation" style="font-size:12px; color:#000000">→ 欢迎您进入甜橙音乐网登录页面,请您填写正确的用户名与密码进行后台登录!祝您天天有份好心情!</div> <div id="main" style="padding-top:5px;margin-bottom:5px;" class="tableBorder_blue"> <form name="form1" method="post" action="select.jsp" onSubmit="return check()"> <table width="200" border="0" cellspacing="0" cellpadding="0"> <tr> <td height="69" colspan="2" align="center"> </td> </tr> <tr> <td width="80" height="30" class="word_gray1">用户名:</td> <td width="120"><input name="userName" type="text" id="user" size="16"></td> </tr> <tr> <td height="30" class="word_gray1">密 码:</td> <td><input name="pwd" type="password" id="pwd" size="16"></td> </tr> <tr> <td height="30" colspan="2" align="center"><input name="Submit2" type="submit" class="btn_green" value="确定"> <input name="Submit3" type="reset" class="btn_green" value="重置"></td> </tr> </table> </form> </div> </body> </html> select.jsp的代码如下: <!-- select.jsp --> <%@ page contentType="text/html;charset=GBK" %> <html> <body> <% String name= new String(request.getParameter("userName").getBytes("ISO-8859-1")); String pwd= new String(request.getParameter("pwd").getBytes("ISO-8859-1")); if(("susan".equals(name))&&("1234".equals(pwd))) { session.setAttribute("userName", name); %> <jsp:forward page="ok.jsp"/> <% } else out.print("用户名或密码错误"); %> </body> </html> ok.jsp的代码如下: <!-- ok.jsp --> <%@ page contentType="text/html;charset=GBK" %> <body> <% String name=(String)session.getAttribute("userName"); String ID=session.getId(); %> <table> <tr> <td><h2>服务器为您分配的账号是:<%=ID%><h2></h2></td> </tr> <tr> <td><h2>欢迎您<%=name%><h2></h2></td> </tr> </table> 运行结果如图3.12~图3.14所示。 图3.12登录界面 图3.13用户名或密码错误界面 图3.14登录成功界面 3.2.6案例6: 使用config隐含对象 config对象实现于javax.servlet.ServletConfig接口,Web容器在初始化时使用一个ServletConfig(即config)对象向JSP页面传递信息,此配置信息包括初始化参数(在当前Web应用的应用部署描述文件web.xml中定义)以及表示Servlet或JSP页面所属Web应用的ServletContext对象。 config对象的方法如表3.9所示。 表3.9config对象的方法 方 法 名 称 方 法 说 明 public String getInitParameter(name) 获取指定名字的初始参数 public java.util.Enumeration getInitParameterNames( ) 获取所有初始参数 public ServletContext getServletContext( ) 获取ServletContext对象(application) public Sring getServletName( ) 获取Servlet名字 如果在web.xml文件中,针对某个servlet文件或JSP文件设置了初始化参数,则可以通过config对象来获取这些初始化参数。 例3.12利用config对象获取web.xml的初始化参数。 <!-- config.jsp --> <%@ page contentType="text/html;charset=GBK" import="java.util.*"%> <html> <head> <title>config对象</title> </head> <body> <b>web应用初始参数:</b> <pre> <% Enumeration e = config.getInitParameterNames(); while (e.hasMoreElements()) { Object nameOb = e.nextElement(); String name = (String) nameOb; out.print(name+": "); out.println(config.getInitParameter(name)); } %> <b>web应用名称:</b> <%= config.getServletName() %><br/> </pre> </body> </html> 没有对web.xml进行初始化设置的情况下,运行结果如图3.15所示。 图3.15获取web.xml初始化参数 3.2.7案例7: 使用exception隐含对象 exception对象的基类是javax.servlet.jsp.JspException类。当JSP页面在执行过程中发生异常或错误时,会自动产生一个exception对象。在JSP页面中,使用page指令,设置isErrorPage属性值为true后,就可以使用该exception对象,来查找页面出错信息。 Exception对象的使用包括两部分: 确定可能出现异常的页面和专门处理异常的页面。 1. 可能出现异常的页面 在有可能产生异常或错误的JSP页面中,使用page指令设置errorPage属性,属性值为能够进行异常处理的某个JSP页面。 2. 专门处理异常的页面 在专门负责处理异常的JSP页面中,使用page指令设置isErrorPage属性为true,并使用exception对象来获取出错信息。 exception对象的常用方法如表3.10所示。 表3.10exception的常用方法 方 法 名 称 方 法 说 明 String getMessage() 返回简短的JSP页面的出错信息 String toString() 返回详细的JSP页面的出错信息 String getLocalizedMessage() 输出错误信息 void printStackTrace() 显示异常的栈跟踪轨迹 nativeThrowable fillInStackTrace() 重写异常错误的栈执行轨迹 例3.13创建一个出现异常的页面exception.jsp和一个专门处理异常的页面error.jsp。代码如下: <!-- exception.jsp --> <%@ page isErrorPage="true" errorPage="error.jsp" contentType="text/html;charset=GBK" %> <h2>发生异常</h2> <%! boolean throwError=true;%> <% if (throwError){ throwError=false; throw new Exception("抛出异常"); } %> <i>错误描述:<i><%= exception.getMessage() %><br/> <%= exception.toString() %><p/> <i>详细出错原因:</i><p/> <pre> <% exception.printStackTrace(new java.io.PrintWriter(out)); throwError=true; %> </pre> <!-- error.jsp --> <%@ page contentType="text/html; charset=UTF-8" language="java" import="java.sql.*" errorPage="" %> <html> <head> <title>错误提示</title> <link href="CSS/style.css" rel="stylesheet"> </head> <body> <table width="100%" height="100%" border="0" cellpadding="0" cellspacing="0"> <tr> <td align="center"><table width="419" height="226" border="0" cellpadding="0" cellspacing="0"> <tr> <td align="center"> 错误提示信息 ${error}<br> <br> <input name="Submit" type="submit" class="btn_grey" value="返回" onClick="history.back(-1)"></td> </tr> </table></td> </tr> </table> <center> </center> </body> </html> 运行exception.jsp的结果如图3.16所示。 图3.16exception对象的应用 3.2.8案例8: 使用page隐含对象 page是java.lang.Object类的对象。page对象在当前JSP页面中可以用this关键字替代。在JSP页面的Java程序脚本中和JSP表达式中都可以使用page对象。 page对象常见的方法如表3.11所示。 表3.11page的常用方法 方 法 名 称 方 法 说 明 class getClass() 返回当时Object的类 int hashCode() 返回此时Object的哈希代码 String toString() 将此时的Object类转换成字符串 boolean equals(Object ob) 比较此对象是否与指定的对象相等 续表 方 法 名 称 方 法 说 明 void copy(Object ob) 将此对象复制到指定的对象中 Object clone() 对此对象进行克隆 ServletConfig getServletConfig() 获取ServletConfig对象 ServletContext getServletContext() 获取ServletContext对象 String getServletInfo() 获取当前JSP页面的Info属性 例3.14使用page指令定义属性info,然后使用getServletInfo()方法取得属性info的值,page.jsp代码如下: <!-- page.jsp --> <%@ page info="音乐之声 可以试听下载。" contentType="text/html;charset=GBK" %> <html> <head> <title>page对象</title> </head> <body> <b>页面指令中定义的Info属性 :</b> <%=this.getServletInfo() %> </body> </html> 运行结果如图3.17所示。 图3.17page对象的应用 3.2.9案例9: 使用pageContext隐含对象 pageContext对象是javax.servlet.jsp.PageContext类的实例对象,它是一个比较特殊的对象,它相当于页面中所有其他对象功能的最大集成者,即使用它可以访问到本页面中所有其他的对象,例如前面描述过的request、response、out和page对象等。由于在JSP中request和response等对象本来就可以通过直接调用方法使用,所以pageContext对象在实际JSP开发中很少使用到。 pageContext对象在存取其他隐含对象属性的setAttribute方法中需要指定范围的参数,其语法格式为: void setAttribute(String name, Object value, int scope) 语法说明: 范围参数scope有4个,分别代表4种范围: PAGE_SCOPE、REQUEST_SCOPE、SESSION_SCOPE、APPLICATION_SCOPE。 pageContext对象的常用方法如表3.12所示。 表3.12pageContext常用方法 方 法 名 称 方 法 说 明 Exception getException( ) 回传网页的异常 JspWriter getOut( ) 回传网页的输出流,例如,out Object getPage( ) 回传网页的Servlet 实体(instance),例如,page ServletRequest getRequest( ) 回传网页的请求,例如,request ServletResponse getResponse( ) 回传网页的响应,例如,response ServletConfig getServletConfig( ) 回传此网页的ServletConfig 对象,例如,config ServletContext getServletContext( ) 回传此网页的执行环境(context),例如,application HttpSession getSession( ) 回传和网页有联系的会话(session),例如,session Object getAttribute(String name, int scope) 回传name 属性,范围为scope的属性对象,回传类型为Object Enumeration getAttributeNamesInScope(int scope) 回传所有属性范围为scope 的属性名称,回传类型为Enumeration int getAttributesScope(String name) 回传属性名称为name 的属性范围 void removeAttribute(String name) 移除属性名称为name 的属性对象 void removeAttribute(String name, int scope) 移除属性名称为name,范围为scope 的属性对象 void setAttribute(String name, Object value, int scope) 指定属性对象的名称为name、值为value、范围为scope Object findAttribute(String name) 寻找在所有范围中属性名称为name 的属性对象 例3.15利用pageContext对象设置4种范围的属性值并进行获取。利用pageContext对象的常用方法进行删除、查找属性等简单操作。pageContext.jsp代码如下: <!-- pageContext.jsp --> <%@page contentType="text/html;charset=gb2312"%> <html> <head> <title>pageContext对象_例1</title> </head> <body> <h2>pageContext对象</h2> <% pageContext.setAttribute("name","爸爸去哪儿"); request.setAttribute("name","下载歌曲"); session.setAttribute("name","甜橙音乐之声"); application.setAttribute("name","音乐之声"); %> page设定的值:<%=pageContext.getAttribute("name")%><br> request设定的值:<%=pageContext.getRequest().getAttribute("name")%><br> session设定的值:<%=pageContext.getSession().getAttribute("name")%><br> application设定的值:<%=pageContext.getServletContext().getAttribute("name")%><br> <br> 页面有效的值:<%=pageContext.getAttribute("name",1)%><br> 请求有效的值:<%=pageContext.getAttribute("name",2)%><br> 会话有效的值:<%=pageContext.getAttribute("name",3)%><br> 应用有效的值:<%=pageContext.getAttribute("name",4)%><br> <br> <i>现在利用removeAttribute方法删除session设置。</i><br> <%pageContext.removeAttribute("name",3);%> <br> pageContext修改后的session设定的值:<%=session.getValue("name")%><br> <br> <i>现在修改application的值。</i><br> <%pageContext.setAttribute("name","音乐网",4);%> <br> pageContext修改后的application设定的值:<%=pageContext.getServletContext().getAttribute("name")%><br> <br> 默认属性的值:<%=pageContext.findAttribute("name")%><br> 默认属性的范围值:<%=pageContext.getAttributesScope("name")%><br> </body> </html> 运行界面如图3.18所示。 图3.18pageContext对象的应用 3.3小结 JSP隐含对象包括9种,本章主要对这9种对象进行了详细的介绍。从使用和开发的角度介绍了9种隐含对象各自的由来、特点以及常用方法,对每个隐含对象都有案例进行相应的解释。 9种隐含对象中涉及了4种有效范围,重点学习4种有效范围的特点。 学习本章时,应把注意力放在掌握各种隐含对象的使用上,为以后的编程打下坚实的基础。由于对象比较多,方法又很丰富,因此用了比较简单的例子进行说明。 3.4习题 一、 选择题 1. 下面不属于JSP内置对象的是()。 A. out对象B. respone对象C. application对象D. page对象 2. 以下哪个对象提供了访问和放置页面中共享数据的方式?() A. pageContextB. responseC. requestD. session 3. 在JSP中为内建对象定义了4种作用范围,即Application Scope、Session Scope、Page Scope和()4个作用范围。 A. Request ScopeB. Response Scope C. Out ScopeD. Writer Scope 4. Form表单的method属性能取下列哪项的值?() A. submitB. putsC. postD. out 5. 可以利用JSP动态改变客户端的响应,使用的语法是()。 A. response.setHeader()B. response.outHeader() C. response.writeHeader()D response.handlerHeader() 6. JSP页面中request.getParamter(String )得到的数据,其类型是()。 A. DoubleB. intC. StringD. Integer 7. 当利用request的方法获取Form中元素时,默认情况下字符编码是()。 A. ISO88591B. GB2312C. GB3000D. ISO82591 二、 填空题 1. JSP的()对象用来保存单个用户访问时的一些信息。 2. response对象的()方法可以将当前客户端的请求转到其他页面去。 3. 当客户端请求一个JSP页面时,JSP容器会将请求信息包装在()对象中。 4. 表单标记中的()属性用于指定处理表单数据程序url的地址。 5. <select>标记中的size属性默认值为()。 三、 简答题 1. 请说出JSP中常用的隐含对象。 2. 简述request对象和response对象的作用。 3. session对象与application对象有何区别? 4. 网页中的表单如何定义?通常表单中包含哪些元素? 5. JSP隐含对象有哪4个作用范围?什么情况下session会关闭? 6. response.sendRedirect(URL url)方法有何作用? 7. 是不是所有Web服务目录共用一个application? 8. 怎样使用request、session和application对象进行参数存取? 9. 设计注册表单,利用request对象实现获取用户注册信息。 10. 利用session对象实现购物车。