一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - javaweb Servlet開發總結(一)

javaweb Servlet開發總結(一)

2020-04-25 15:31孤傲蒼狼 JAVA教程

Servlet是sun公司提供的一門用于開發動態web資源的技術。這篇文章主要介紹了javaweb Servlet開發的第一篇,感興趣的小伙伴們可以參考一下

一、Servlet簡介

  Servlet是sun公司提供的一門用于開發動態web資源的技術。
  Sun公司在其API中提供了一個servlet接口,用戶若想用發一個動態web資源(即開發一個Java程序向瀏覽器輸出數據),需要完成以下2個步驟:
  1、編寫一個Java類,實現servlet接口。
  2、把開發好的Java類部署到web服務器中。
  按照一種約定俗成的稱呼習慣,通常我們也把實現了servlet接口的java程序,稱之為Servlet

二、Servlet的運行過程

Servlet程序是由WEB服務器調用,web服務器收到客戶端的Servlet訪問請求后:
  ①Web服務器首先檢查是否已經裝載并創建了該Servlet的實例對象。如果是,則直接執行第④步,否則,執行第②步。
  ②裝載并創建該Servlet的一個實例對象。
  ③調用Servlet實例對象的init()方法。
  ④創建一個用于封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP響應消息的HttpServletResponse對象,然后調用Servlet的service()方法并將請求和響應對象作為參數傳遞進去。
  ⑤WEB應用程序被停止或重新啟動之前,Servlet引擎將卸載Servlet,并在卸載之前調用Servlet的destroy()方法。

javaweb Servlet開發總結(一)

javaweb Servlet開發總結(一)

javaweb Servlet開發總結(一)

三、Servlet調用圖

javaweb Servlet開發總結(一)

四、在Eclipse中開發Servlet

  在eclipse中新建一個web project工程,eclipse會自動創建下圖所示目錄結構:

javaweb Servlet開發總結(一)

4.1、Servlet接口實現類

  Servlet接口SUN公司定義了兩個默認實現類,分別為:GenericServlet、HttpServlet。

  HttpServlet指能夠處理HTTP請求的servlet,它在原有Servlet接口上添加了一些與HTTP協議處理方法,它比Servlet接口的功能更為強大。因此開發人員在編寫Servlet時,通常應繼承這個類,而避免直接去實現Servlet接口。
  HttpServlet在實現Servlet接口時,覆寫了service方法,該方法體內的代碼會自動判斷用戶的請求方式,如為GET請求,則調用HttpServlet的doGet方法,如為Post請求,則調用doPost方法。因此,開發人員在編寫Servlet時,通常只需要覆寫doGet或doPost方法,而不要去覆寫service方法。

4.2、通過Eclipse創建和編寫Servlet

  選中gacl.servlet.study包,右鍵→New→Servlet,如下圖所示:

javaweb Servlet開發總結(一)

javaweb Servlet開發總結(一)

javaweb Servlet開發總結(一)

這樣,我們就通過Eclipse幫我們創建好一個名字為ServletDemo1的Servlet,創建好的ServletDemo01里面會有如下代碼:

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

  這些代碼都是Eclipse自動生成的,而web.xml文件中也多了<servlet></servlet>和<servlet-mapping></servlet-mapping>兩對標簽,這兩對標簽是配置ServletDemo1的,如下圖所示:

javaweb Servlet開發總結(一)

然后我們就可以通過瀏覽器訪問ServletDemo1這個Servlet,如下圖所示:

javaweb Servlet開發總結(一)

五、Servlet開發注意細節

5.1、Servlet訪問URL映射配置

  由于客戶端是通過URL地址訪問web服務器中的資源,所以Servlet程序若想被外界訪問,必須把servlet程序映射到一個URL地址上,這個工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
  <servlet>元素用于注冊Servlet,它包含有兩個主要的子元素:<servlet-name>和<servlet-class>,分別用于設置Servlet的注冊名稱和Servlet的完整類名。
一個<servlet-mapping>元素用于映射一個已注冊的Servlet的一個對外訪問路徑,它包含有兩個子元素:<servlet-name>和<url-pattern>,分別用于指定Servlet的注冊名稱和Servlet的對外訪問路徑。例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<servlet>
  <servlet-name>ServletDemo1</servlet-name>
  <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/servlet/ServletDemo1</url-pattern>
 </servlet-mapping>
  同一個Servlet可以被映射到多個URL上,即多個<servlet-mapping>元素的<servlet-name>子元素的設置值可以是同一個Servlet的注冊名。 例如:
<servlet>
  <servlet-name>ServletDemo1</servlet-name>
  <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/servlet/ServletDemo1</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/1.htm</url-pattern>
 </servlet-mapping>
  <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/2.jsp</url-pattern>
 </servlet-mapping>
  <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/3.php</url-pattern>
 </servlet-mapping>
  <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/4.ASPX</url-pattern>
 </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上。

5.2、Servlet訪問URL使用*通配符映射  

在Servlet映射到的URL中也可以使用*通配符,但是只能有兩種固定的格式:一種格式是"*.擴展名",另一種格式是以正斜杠(/)開頭并以"/*"結尾。例如:

javaweb Servlet開發總結(一)

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

  *可以匹配任意的字符,所以此時可以用任意的URL去訪問ServletDemo1這個Servlet,如下圖所示:

javaweb Servlet開發總結(一)

對于如下的一些映射關系:
  Servlet1 映射到 /abc/*
  Servlet2 映射到 /*
  Servlet3 映射到 /abc
  Servlet4 映射到 *.do
問題:
  當請求URL為“/abc/a.html”,“/abc/*”和“/*”都匹配,哪個servlet響應
      Servlet引擎將調用Servlet1。
  當請求URL為“/abc”時,“/abc/*”和“/abc”都匹配,哪個servlet響應
      Servlet引擎將調用Servlet3。
  當請求URL為“/abc/a.do”時,“/abc/*”和“*.do”都匹配,哪個servlet響應
      Servlet引擎將調用Servlet1。
  當請求URL為“/a.do”時,“/*”和“*.do”都匹配,哪個servlet響應
      Servlet引擎將調用Servlet2。
  當請求URL為“/xxx/yyy/a.do”時,“/*”和“*.do”都匹配,哪個servlet響應
      Servlet引擎將調用Servlet2。
  匹配的原則就是"誰長得更像就找誰"

5.3、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()方法。
    舉例:

?
1
2
3
4
5
6
7
<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應用創建必要的數據庫表和數據。

5.4、缺省Servlet

  如果某個Servlet的映射路徑僅僅為一個正斜杠(/),那么這個Servlet就成為當前Web應用程序的缺省Servlet。
  凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它們的訪問請求都將交給缺省Servlet處理,也就是說,缺省Servlet用于處理所有其他Servlet都不處理的訪問請求。 例如:

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

  當訪問不存在的Servlet時,就使用配置的默認Servlet進行處理,如下圖所示:

javaweb Servlet開發總結(一)

  在<tomcat的安裝目錄>\conf\web.xml文件中,注冊了一個名稱為org.apache.catalina.servlets.DefaultServlet的Servlet,并將這個Servlet設置為了缺省Servlet。

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

  當訪問Tomcat服務器中的某個靜態HTML文件和圖片時,實際上是在訪問這個缺省Servlet。

5.5、Servlet的線程安全問題

  當多個客戶端并發訪問同一個Servlet時,web服務器會為每一個客戶端的訪問請求創建一個線程,并在這個線程上調用Servlet的service方法,因此service方法內如果訪問了同一個資源的話,就有可能引發線程安全問題。例如下面的代碼:

不存在線程安全問題的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package gacl.servlet.study;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class ServletDemo3 extends HttpServlet {
 
  
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    
    /**
     * 當多線程并發訪問這個方法里面的代碼時,會存在線程安全問題嗎
     * i變量被多個線程并發訪問,但是沒有線程安全問題,因為i是doGet方法里面的局部變量,
     * 當有多個線程并發訪問doGet方法時,每一個線程里面都有自己的i變量,
     * 各個線程操作的都是自己的i變量,所以不存在線程安全問題
     * 多線程并發訪問某一個方法的時候,如果在方法內部定義了一些資源(變量,集合等)
     * 那么每一個線程都有這些東西,所以就不存在線程安全問題了
     */
    int i=1;
    i++;
    response.getWriter().write(i);
  }
 
  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGet(request, response);
  }
 
}

存在線程安全問題的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package gacl.servlet.study;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class ServletDemo3 extends HttpServlet {
 
  int i=1;
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    
    i++;
    try {
      Thread.sleep(1000*4);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    response.getWriter().write(i+"");
  }
 
  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGet(request, response);
  }
 
}

  把i定義成全局變量,當多個線程并發訪問變量i時,就會存在線程安全問題了,如下圖所示:同時開啟兩個瀏覽器模擬并發訪問同一個Servlet,本來正常來說,第一個瀏覽器應該看到2,而第二個瀏覽器應該看到3的,結果兩個瀏覽器都看到了3,這就不正常。

javaweb Servlet開發總結(一)

  線程安全問題只存在多個線程并發操作同一個資源的情況下,所以在編寫Servlet的時候,如果并發訪問某一個資源(變量,集合等),就會存在線程安全問題,那么該如何解決這個問題呢?

先看看下面的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package gacl.servlet.study;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
 
public class ServletDemo3 extends HttpServlet {
 
  int i=1;
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    /**
     * 加了synchronized后,并發訪問i時就不存在線程安全問題了,
     * 為什么加了synchronized后就沒有線程安全問題了呢?
     * 假如現在有一個線程訪問Servlet對象,那么它就先拿到了Servlet對象的那把鎖
     * 等到它執行完之后才會把鎖還給Servlet對象,由于是它先拿到了Servlet對象的那把鎖,
     * 所以當有別的線程來訪問這個Servlet對象時,由于鎖已經被之前的線程拿走了,后面的線程只能排隊等候了
     *
     */
    synchronized (this) {//在java中,每一個對象都有一把鎖,這里的this指的就是Servlet對象
      i++;
      try {
        Thread.sleep(1000*4);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      response.getWriter().write(i+"");
    }
    
  }
 
  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGet(request, response);
  }
 
}

  現在這種做法是給Servlet對象加了一把鎖,保證任何時候都只有一個線程在訪問該Servlet對象里面的資源,這樣就不存在線程安全問題了,如下圖所示:

javaweb Servlet開發總結(一)

  這種做法雖然解決了線程安全問題,但是編寫Servlet卻萬萬不能用這種方式處理線程安全問題,假如有9999個人同時訪問這個Servlet,那么這9999個人必須按先后順序排隊輪流訪問。

  針對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(過時的)。
以上就是本文的全部內容,希望對大家的學習有所幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲激情欧美 | 男生同性啪视频在线观看 | 天天干天天操天天爽 | 日本高清中文字幕视频在线 | 亚洲日本视频在线观看 | 免费一区二区 | 亚洲欧美精品一区天堂久久 | 精品国产美女AV久久久久 | www.91在线播放 | 精品午夜寂寞影院在线观看 | 护士xxxx| 草逼视频网站 | 2020最新韩国理论三级0k | 国产日韩精品一区二区 | 美女的隐私视频免费看软件 | 国产成人夜色91 | 色综合天天综合网看在线影院 | 51国产| 久久黄视频| 99久久一区二区精品 | 国产精品极品 | gay小太正初精 | 四虎精品永久在线网址 | 免费人成在线观看69式小视频 | 99re最新网址 | 国内精品免费一区二区三区 | 欧美丰满大乳大屁在线观看股 | 欧美日韩亚洲一区二区三区在线观看 | 免费一级欧美片片线观看 | 久久精品亚洲牛牛影视 | 欧美色图亚洲 | 精品国产自在现线拍400部 | 特黄特级高清免费视频毛片 | 亚洲精品久久麻豆蜜桃 | 国产精品久久久久久五月尺 | 4438全国免费观看 | 成人看片免费无限观看视频 | 国产东北三老头伦一肥婆 | 免费看一级a一片毛片 | 13日本xxxxxxxxx18 1313午夜精品久久午夜片 | 极品手交handjobtattoo |