肥宅兜

导航

Servlet简介

Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
  ①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
  ②装载并创建该Servlet的一个实例对象。 
  ③调用Servlet实例对象的init()方法。
  ④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应           对象作为参数传递进去。
  ⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

 

 

在eclipse中新建一个web project工程,eclipse会自动创建下图所示目录结构:

 

接口实现类

  Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet、HttpServlet。

  HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。
  HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。

通过Eclipse创建和编写Servlet

  选中gacl.servlet.study包,右键→New→Servlet,如下图所示:

  

  

  

  这样,我们就通过Eclipse帮我们创建好一个名字为ServletDemo1的Servlet,创建好的ServletDemo01里面会有如下代码:

 1 package gacl.servlet.study;
 2 
 3 import java.io.IOException;
 4 import java.io.PrintWriter;
 5 
 6 import javax.servlet.ServletException;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 public class ServletDemo1 extends HttpServlet {
12 
13     /**
14      * The doGet method of the servlet. <br>
15      *
16      * This method is called when a form has its tag value method equals to get.
17      * 
18      * @param request the request send by the client to the server
19      * @param response the response send by the server to the client
20      * @throws ServletException if an error occurred
21      * @throws IOException if an error occurred
22      */
23     public void doGet(HttpServletRequest request, HttpServletResponse response)
24             throws ServletException, IOException {
25 
26         response.setContentType("text/html");
27         PrintWriter out = response.getWriter();
28         out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
29         out.println("<HTML>");
30         out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
31         out.println("  <BODY>");
32         out.print("    This is ");
33         out.print(this.getClass());
34         out.println(", using the GET method");
35         out.println("  </BODY>");
36         out.println("</HTML>");
37         out.flush();
38         out.close();
39     }
40 
41     /**
42      * The doPost method of the servlet. <br>
43      *
44      * This method is called when a form has its tag value method equals to post.
45      * 
46      * @param request the request send by the client to the server
47      * @param response the response send by the server to the client
48      * @throws ServletException if an error occurred
49      * @throws IOException if an error occurred
50      */
51     public void doPost(HttpServletRequest request, HttpServletResponse response)
52             throws ServletException, IOException {
53 
54         response.setContentType("text/html");
55         PrintWriter out = response.getWriter();
56         out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
57         out.println("<HTML>");
58         out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
59         out.println("  <BODY>");
60         out.print("    This is ");
61         out.print(this.getClass());
62         out.println(", using the POST method");
63         out.println("  </BODY>");
64         out.println("</HTML>");
65         out.flush();
66         out.close();
67     }
68 
69 }

  这些代码都是Eclipse自动生成的,而web.xml文件中也多了<servlet></servlet>和<servlet-mapping></servlet-mapping>两对标签,这两对标签是配置ServletDemo1的,如下图所示:

然后我们就可以通过浏览器访问ServletDemo1这个Servlet,如下图所示:

  

 

同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名

 1  <servlet>
 2     <servlet-name>ServletDemo1</servlet-name>
 3     <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class>
 4   </servlet>
 5 
 6   <servlet-mapping>
 7     <servlet-name>ServletDemo1</servlet-name>
 8     <url-pattern>/servlet/ServletDemo1</url-pattern>
 9   </servlet-mapping>
10  <servlet-mapping>
11     <servlet-name>ServletDemo1</servlet-name>
12     <url-pattern>/1.htm</url-pattern>
13   </servlet-mapping>
14    <servlet-mapping>
15     <servlet-name>ServletDemo1</servlet-name>
16     <url-pattern>/2.jsp</url-pattern>
17   </servlet-mapping>
18    <servlet-mapping>
19     <servlet-name>ServletDemo1</servlet-name>
20     <url-pattern>/3.php</url-pattern>
21   </servlet-mapping>
22    <servlet-mapping>
23     <servlet-name>ServletDemo1</servlet-name>
24     <url-pattern>/4.ASPX</url-pattern>
25   </servlet-mapping>

通过上面的配置,当我们想访问名称是ServletDemo1的Servlet,可以使用如下的几个地址去访问:

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/servlet/ServletDemo1

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/1.htm

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/2.jsp

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/3.php

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/4.ASPX

  ServletDemo1被映射到了多个URL上。

 

Servlet访问URL使用*通配符映射

在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是"*.扩展名",另一种格式是以正斜杠(/)开头并以"/*"结尾。例如:

  

1  <servlet>
2     <servlet-name>ServletDemo1</servlet-name>
3     <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class>
4   </servlet>
5 
6    <servlet-mapping>
7     <servlet-name>ServletDemo1</servlet-name>
8    <url-pattern>/*</url-pattern>

 

Servlet与普通Java类的区别  

  Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度
  针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁
  在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。

  如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法
    举例:
    <servlet>
        <servlet-name>invoker</servlet-name>
        <servlet-class>
            org.apache.catalina.servlets.InvokerServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

  用途:为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据。

 

如下一段配置,熟悉DWR的再熟悉不过了:
<servlet>
   <servlet-name>dwr-invoker</servlet-name>
   <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
   <init-param>
    <param-name>debug</param-name>
    <param-value>true</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
   <servlet-name>dwr-invoker</servlet-name>
   <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

我们注意到它里面包含了这段配置:<load-on-startup>1</load-on-startup>,那么这个配置有什么作用呢?

贴一段英文原汁原味的解释如下:
Servlet specification:
The load-on-startup element indicates that this servlet should be loaded (instantiated and have its init() called) on the startup of the web application. The optional contents of these element must be an integer indicating the order in which the servlet should be loaded. If the value is a negative integer, or the element is not present, the container is free to load the servlet whenever it chooses.   If the value is a positive integer or 0, the container must load and initialize the servlet as the application is deployed. The container must guarantee that servlets marked with lower integers are loaded before servlets marked with higher integers. The container may choose the order of loading of servlets with the same load-on-start-up value.

翻译过来的意思大致如下:
1)load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法)。

2)它的值必须是一个整数,表示servlet应该被载入的顺序

2)当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;

3)当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载。

4)正数的值越小,该servlet的优先级越高,应用启动时就越先加载。

5)当值相同时,容器就会自己选择顺序来加载。

所以,<load-on-startup>x</load-on-startup>,中x的取值1,2,3,4,5代表的是优先级,而非启动延迟时间。

如下题目:

2.web.xml中不包括哪些定义(多选)

 

a.默认起始页

b.servlet启动延迟时间定义

c.error处理页面

d.jsp文件改动后重新载入时间

答案:b,d

通常大多数Servlet是在用户第一次请求的时候由应用服务器创建并初始化,但<load-on-startup>n</load-on-startup>   可以用来改变这种状况,根据自己需要改变加载的优先级!

 

缺省Servlet用于处理所有其他Servlet都不处理的访问请求(在web.xml文件中找不到匹配的<servlet-mapping>元素的URL)

 1  <servlet>
 2     <servlet-name>ServletDemo2</servlet-name>
 3     <servlet-class>gacl.servlet.study.ServletDemo2</servlet-class>
 4     <load-on-startup>1</load-on-startup>
 5   </servlet>
 6   
 7   <!-- 将ServletDemo2配置成缺省Servlet -->
 8   <servlet-mapping>
 9     <servlet-name>ServletDemo2</servlet-name>
10     <url-pattern>/</url-pattern>
11   </servlet-mapping>

 

 

在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet。

 1     <servlet>
 2         <servlet-name>default</servlet-name>
 3         <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
 4         <init-param>
 5             <param-name>debug</param-name>
 6             <param-value>0</param-value>
 7         </init-param>
 8         <init-param>
 9             <param-name>listings</param-name>
10             <param-value>false</param-value>
11         </init-param>
12         <load-on-startup>1</load-on-startup>
13     </servlet>
14 
15  <!-- The mapping for the default servlet -->
16     <servlet-mapping>
17         <servlet-name>default</servlet-name>
18         <url-pattern>/</url-pattern>
19     </servlet-mapping>

  当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。

 

Servlet的线程安全问题

当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题

上面的定义的是局部变量,所以不存在线程安全问题

 

把 i 定义成全局变量,当多个线程并发访问变量i时,就会存在线程安全问题了

 

用锁来限制

 

 

针对Servlet的线程安全问题,Sun公司是提供有解决方案的:让Servlet去实现一个SingleThreadModel接口,如果某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。
  查看Sevlet的API可以看到,SingleThreadModel接口中没有定义任何方法和常量,在Java中,把没有定义任何方法和常量的接口称之为标记接口,经常看到的一个最典型的标记接口就是"Serializable",这个接口也是没有定义任何方法和常量的,标记接口在Java中有什么用呢?主要作用就是给某个对象打上一个标志,告诉JVM,这个对象可以做什么,比如实现了"Serializable"接口的类的对象就可以被序列化,还有一个"Cloneable"接口,这个也是一个标记接口,在默认情况下,Java中的对象是不允许被克隆的,就像现实生活中的人一样,不允许克隆,但是只要实现了"Cloneable"接口,那么对象就可以被克隆了。

  让Servlet实现了SingleThreadModel接口,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。  
  对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象
  实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过时的)。

 

 

 

ServletConfig 配置Servlet初始化参数

 

当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,我们通过ServletConfig对象就可以得到当前servlet的初始化参数信息。

 

 

ServletContext对象(多个Servlet通过ServletContext对象实现数据共享)

范例:ServletContextDemo1和ServletContextDemo2通过ServletContext对象实现数据共享

 

 

先运行ServletContextDemo1,将数据data存储到ServletContext对象中,然后运行ServletContextDemo2就可以从ServletContext对象中取出数据了,这样就实现了数据共享

 

获取WEB应用的初始化参数

 

 

 

用servletContext实现请求转发

访问的是ServletContextDemo4,浏览器显示的却是ServletContextDemo5的内容,这就是使用ServletContext实现了请求转发

 

 

利用ServletContext对象读取资源文件

InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db1.properties");

Properties prop = new Properties();

prop.load(in);

String driver = prop.getProperty("driver");

 

posted on 2016-08-16 17:06  肥宅兜  阅读(237)  评论(0编辑  收藏  举报