我们在Servlet解析(二)中讨论了Servlet UML 类图中的Servlet接口,本篇我们将继续讨论ServletRequest、ServletResponse、ServletConfig。除此之外还有Servlet异常、Servlet上下文。
ServletRequest和ServletResponse
ServletRequest和ServletResponse接口都在javax.servlet包中定义。ServletRequest接口中的常用方法如下:
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源端口 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 //覆盖在请求正文中所使用的字符编码的名字。
ServletResponse接口中的常用方法如下:
public void flushBuffer() throws java.io.IOException //强制把任何在缓存中的内容发送到客户端。 public int getBufferSize() //返回实际用于响应的缓存的大小。如果没有使用缓存,这个方法将返回0。 public java.lang.String getCharacterEncoding() //返回在响应中发送的正文所使用的字符编码(MIME字符集)。 public java.lang.String getContentType() //返回在响应中发送的正文所使用的MIME类型。 public ServletOutputStream getOutputStream() throws java.io.IOException //返回ServletOutputStream对象,用于在响应中写入二进制数据。javax.servlet. ServletOutputStream是一个抽象类,继承自java.io.OutputStream。 public java.io.PrintWriter getWriter() throws java.io.IOException //返回PrintWriter对象,用于发送字符文本到客户端。PrintWriter对象使用getCharacterEncoding()方法返回的字符编码。如果没有指定响应的字符编码方式,默认将使用ISO-8859-1。 public boolean isCommitted() //返回一个布尔值,指示是否已经提交了响应。 public void reset() //清除在缓存中的任何数据,包括状态代码和消息报头。如果响应已经被提交,这个方法将抛出IllegalStateException异常。 public void resetBuffer() //清除在缓存中的响应内容,保留状态代码和消息报头。如果响应已经被提交,这个方法将抛出IllegalStateException异常。 public void setBufferSize(int size) //设置响应正文的缓存大小。Servlet容器将使用一个缓存,其大小至少是请求的尺寸大小。这个方法必须在响应正文被写入之前调用,如果内容已经被写入或者响应对象已经被提交,这个方法将抛出IllegalStateException异常。 public void setCharacterEncoding(java.lang.String charset) //设置发送到客户端的响应的字符编码,例如,UTF-8。 public void setContentLength(int len) //对于HTTP Servlet,在响应中,设置内容正文的长度,这个方法设置HTTP Content-Length实体报头。 public void setContentType(java.lang.String type) //设置要发送到客户端的响应的内容类型,此时响应应该还没有提交。给出的内容类型可以包括字符编码说明,例如:text/html;charset=UTF-8。如果这个方法在getWriter()方法被调用之前调用,那么响应的字符编码将仅从给出的内容类型中设置。这个方法如果在getWriter()方法被调用之后或者在响应被提交之后调用,将不会设置响应的字符编码。在使用HTTP协议的情况中,这个方法设置Content-Type实体报头。
上面所列的方法,不需要全部记下来,只需要大致了解即可。关键是要理解请求和响应对象能够提供哪些方法,只要理解了交互的过程及请求对象和响应对象所起的作用,当我们需要用到某个方法时,完全可以在API文档中进行查找。
ServletConfig
在javax.servlet包中,定义了ServletConfig接口。Servlet容器使用ServletConfig对象在Servlet初始化期间向它传递配置信息,一个Servlet只有一个ServletConfig对象。在这个接口中,定义了下面四个方法:
public java.lang.String getInitParameter(java.lang.String name) //返回名字为name的初始化参数的值,初始化参数在web.xml配置文件中进行配置。如果参数不存在,这个方法将返回null。 public java.util.Enumeration getInitParameterNames() //返回Servlet所有初始化参数的名字的枚举集合。如果Servlet没有初始化参数,这个方法将返回一个空的枚举集合。 public ServletContext getServletContext() //返回Servlet上下文对象的引用,关于ServletContext的使用。 public java.lang.String getServletName() //返回Servlet实例的名字。这个名字是在Web应用程序的部署描述符中指定的。如果是一个没有注册的Servlet实例,这个方法返回的将是Servlet的类名。
在javax.servlet包中定义了两个异常类,ServletException和UnavailableException。
1)ServletException类
ServletException类定义了一个通用的异常,可以被init()、service()和doXXX()方法抛出,这个类提供了下面4个构造方法和1个实例方法:
public ServletException() //该方法构造一个新的Servlet异常。 public ServletException(java.lang.String message) //该方法用指定的的消息构造一个新的Servlet异常。这个消息可以被写入服务器的日志中,或者显示给用户。 public ServletException(java.lang.String message, java.lang.Throwable rootCause) //在Servlet执行时,如果有一个异常阻碍了Servlet的正常操作,那么这个异常就是根原因(root cause)异常。如果需要在一个Servlet异常中包含根原因的异常,可以调用这个构造方法,同时包含一个描述消息。例如:可以在ServletException异常中嵌入一个java.sql.SQLException异常。 public ServletException(java.lang.Throwable rootCause) //该方法同上,只是没有指定描述消息的参数。 public java.lang.Throwable getRootCause() //该方法返回引起这个Servlet异常的异常,也就是返回根原因的异常。2)UnavailableException类
UnavailableException类是ServletException类的子类,该异常被Servlet抛出,用于向Servlet容器指示这个Servlet永久地或者暂时地不可用。这个类提供了下面2个构造方法和2个实例方法:
public UnavailableException(java.lang.String msg) //该方法用一个给定的消息构造一个新的异常,指示Servlet永久不可用。 public UnavailableException(java.lang.String msg, int seconds) //该方法用一个给定的消息构造一个新的异常,指示Servlet暂时不可用。其中的参数seconds指明在这个以秒为单位的时间内,Servlet不可用。如果Servlet不能估计出多长时间后它将恢复功能,可以传递一个负数或零给seconds参数。 public int getUnavailableSeconds() //该方法返回Servlet预期的暂时不可用的秒数。如果返回一个负数,表明Servlet永久不可用或者不能估计出Servlet多长时间不可用。 public boolean isPermanent() //法回一个布尔值,用于指示Servlet是否是永久不可用。返回true,表明Servlet永久不可用;返回false,表明Servlet可用或者暂时不可用。
ServletContext接口
一个ServletContext对象表示了一个Web应用程序的上下文。Servlet容器在Servlet初始化期间,向其传递ServletConfig对象,可以通过ServletConfig对象的getServletContext()方法来得到ServletContext对象。也可以通过GenericServlet类的getServletContext()方法得到ServletContext对象,不过GenericServlet类的getServletContext()也是调用ServletConfig对象的getServletContext()方法来得到这个对象的。
ServletContext接口定义了下面的这些方法,Servlet容器提供了这个接口的实现。
public java.lang.Object getAttribute(java.lang.String name) public java.util.Enumeration getAttributeNames() public void removeAttribute(java.lang.String name) public void setAttribute(java.lang.String name, java.lang.Object object)上面4个方法用于读取、移除和设置共享属性,任何一个Servlet都可以设置某个属性,而同一个Web应用程序的另一个Servlet可以读取这个属性,不管这些Servlet是否为同一个客户进行服务。
public ServletContext getContext(java.lang.String uripath)该方法返回服务器上与指定的URL相对应的ServletContext对象。给出的uripath参数必须以斜杠(/)开始,被解释为相对于服务器文档根的路径。出于安全方面的考虑,如果调用该方法访问一个受限制的ServletContext对象,那么该方法将返回null。
public String getContextPath()该方法用于返回Web应用程序的上下文路径。上下文路径总是以斜杠(/)开头,但结束没有斜杠(/)。在默认(根)上下文中,这个方法返回空字符串""。
public java.lang.String getInitParameter(java.lang.String name) public java.util.Enumeration getInitParameterNames()可以为Servlet上下文定义初始化参数,这些参数被整个Web应用程序所使用。可以在部署描述符(web.xml)中使用<context-param>元素来定义上下文的初始化参数,上面两个方法用于访问这些参数。
public int getMajorVersion() public int getMinorVersion()上面两个方法用于返回Servlet容器支持的Java Servlet API的主版本和次版本号。例如,对于遵从Servlet 2.4版本的容器,getMajorVersion()方法返回2,getMinorVersion()方法返回4。
public java.lang.String getMimeType(java.lang.String file)该方法返回指定文件的MIME类型,如果类型是未知的,这个方法将返回null。MIME类型的检测是根据Servlet容器的配置,也可以在Web应用程序的部署描述符中指定。
public RequestDispatcher getRequestDispatcher(java.lang.String path)该方法返回一个RequestDispatcher对象,作为指定路径上的资源的封装。可以使用RequestDispatcher对象将一个请求转发(forward)给其他资源进行处理,或者在响应中包含(include)资源。要注意的是,传入的参数path必须以斜杠(/)开始,被解释为相对于当前上下文根(context root)的路径。
public RequestDispatcher getNamedDispatcher(java.lang.String name)该方法与getRequestDispatcher()方法类似。不同之处在于,该方法接受一个在部署描述符中以<servlet-name>元素给出的Servlet(或JSP页面)的名字作为参数。
public java.lang.String getRealPath(java.lang.String path)在一个Web应用程序中,资源用相对于上下文路径的路径来引用,这个方法可以返回资源在服务器文件系统上的真实路径(文件的绝对路径)。返回的真实路径的格式应该适合于运行这个Servlet容器的计算机和操作系统(包括正确的路径分隔符)。如果Servlet容器不能够将虚拟路径转换为真实的路径,这个方法将会返回null。
public java.net.URL getResource(java.lang.String path) throws java.net.Malformed URLException该方法返回被映射到指定路径上的资源的URL。传入的参数path必须以斜杠(/)开始,被解释为相对于当前上下文根(context root)的路径。这个方法允许Servlet容器从任何来源为Servlet生成一个可用的资源。资源可以是在本地或远程文件系统上,在数据库中,或者在WAR文件中。如果没有资源映射到指定的路径上,该方法将返回null。
public java.io.InputStream getResourceAsStream(java.lang.String path)该方法与getResource()方法类似,不同之处在于,该方法返回资源的输入流对象。另外,使用getResourceAsStream()方法,元信息(如内容长度和内容类型)将丢失,而使用getResource()方法,元信息是可用的。
public java.util.Set getResourcePaths(java.lang.String path)该方法返回资源的路径列表,参数path必须以斜杠(/)开始,指定用于匹配资源的部分路径。例如,一个Web应用程序包含了下列资源:
/welcome.html
/catalog/index.html
/catalog/products.html
/catalog/offers/books.html
/catalog/offers/music.html
/customer/login.jsp
/WEB-INF/web.xml
/WEB-INF/classes/com.acme.OrderServlet.class
如果调用getResourcePaths("/"),将返回[/welcome.html, /catalog/, /customer/, /WEB-INF/]。如果调用getResourcePaths("/catalog/"),将返回[/catalog/index.html,/catalog/products.html, /catalog/offers/]。
public java.lang.String getServerInfo()该方法返回运行Servlet的容器的名称和版本。
public java.lang.String getServletContextName()该方法返回在部署描述符中使用<display-name>元素指定的对应于当前ServletContext的Web应用程序的名称。
public void log(java.lang.String msg) public void log(java.lang.String message, java.lang.Throwable throwable)
ServletContext接口提供了上面两个记录日志的方法,第一个方法用于记录一般的日志,第二个方法用于记录指定异常的栈跟踪信息。
一个简单示例:统计访问次数
很多网站都有统计访问次数的功能,我们可以使用ServletContext对象来保存访问的次数。我们知道一个Web应用程序只有一个ServletContext对象,而且该对象可以被Web应用程序中的所有Servlet所访问,因此使用ServletContext对象来保存一些需要在Web应用程序中共享的信息是再合适不过了。
要在ServletContext对象中保存共享信息,可以调用该对象的setAttribute()方法,要获取共享信息,可以调用该对象的getAttribute()方法。针对本例,我们可以调用setAttribute()方法将访问计数保存到上下文对象中,新增一次访问时,调用getAttribute()方法从上下文对象中取出访问计数加1,然后再调用setAttribute()方法保存回上下文对象中。
我们接着继续以MyDemo为web工程,在com.shan.web包下建立CounterServlet类,即在MyDemo\src\com\shan\web目录下新建CounterServlet.java,代码如下所示。
package com.shan.web; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; /** ** A Count Servlet ** @author shan **/ public class CounterServlet extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException { ServletContext context = getServletContext(); Integer count = null; synchronized(context) { count = (Integer) context.getAttribute("counter"); if (null == count) { count = new Integer(1); } else { count = new Integer(count.intValue() + 1); } context.setAttribute("counter", count); } response.setContentType("text/html;charset=gb2312"); PrintWriter out = response.getWriter(); out.println("<html><head>"); out.println("<title>页面访问统计</title>"); out.println("</head><body>"); out.println("该页面已被访问了" + "<b>" + count + "</b>" + "次"); out.println("</body></html>"); out.close(); } }程序调用getServletContext()方法(从GenericServlet类间接继承而来)得到Web应用程序的上下文对象。为了避免线程安全的问题,使用了synchronized关键字对context对象进行同步。通过调用上下文对象的getAttribute()方法获取counter属性的值。并判断count是否为null,如果为null,则将它的初始值设为1。当这个Servlet第一次被访问的时候,在上下文对象中还没有保存counter属性,所以获取该属性的值将返回null。如果count不为null,则将count加1。通过将count作为counter属性的值保存到ServletContext对象中。
编写完上述代码之后,需要对代码进行编译,执行如下语句:
javac -classpath D:\apache-tomcat-7.0.33\lib\servlet-api.jar -d classes src\com\shan\web\CounterServlet.java将编译后的classes文件夹复制到D:\apache-tomcat-7.0.33\webapps\MyDemo文件夹中。接下来还需要修改web.xml文件,修改后的文件如下:
<?xml version='1.0' encoding='utf-8'?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <description> My Demo. </description> <servlet> <servlet-name>selectServlet</servlet-name> <servlet-class>com.shan.web.MyDemoServlet</servlet-class> </servlet> <servlet> <servlet-name>countServlet</servlet-name> <servlet-class>com.shan.web.CounterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>selectServlet</servlet-name> <url-pattern>/SelectColor.do</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>countServlet</servlet-name> <url-pattern>/count.do</url-pattern> </servlet-mapping> </web-app>将web.xml文件复制到D:\apache-tomcat-7.0.33\webapps\MyDemo\WEB-INF文件夹下。启动Tomcat,在浏览器中输入http:localhost:8080/MyDemo/count.do即可看到结果。
交替刷新两个浏览器中的页面,可以看到访问次数也在交替增长,说明利用ServletContext保存属性,可以在多个客户端之间共享属性。但要注意,不同的Web应用程序具有不同的Servlet上下文,所以在不同的Web应用程序之间不能利用ServletContext来共享属性。另外,访问次数在重启Tomcat服务器后,将重新从1开始,为了永久保存访问次数,可以将这个值保存到文件或数据库中。
转载请注明出处:http://blog.csdn.net/iAm333