JavaWeb基礎學習(二)--Servlet

 

一. Servlet簡介

 

基於Java技術的Web組件,運行在服務器端,由Servlet容器管理,用於生成動態內容。

Servlet容器管理Servlet,負責Servlet和客戶的通信以及調用Servlet的方法。

Servlet功能:

  1. 接收用戶請求的http協議
  2. 返回http響應協議

 

Servlet優勢:

  1. Servlet 在 Web 服務器的地址空間內執行。這樣它就沒有必要再創建一個單獨的進程來處理每個客戶端請求。
  2. Servlet 是獨立於平臺的,因爲它是用 Java 編寫的。
  3. 服務器上的 Java 安全管理器執行了一系列限制,以保護服務器計算機上的資源。因此,Servlet 是可信的。
  4. Java 類庫的全部功能對 Servlet 來說都是可用的。它可通過 sockets 和 RMI 機制與 applets、數據庫或其他軟件進行交互。

 

Servlet框架:

 

Servlet實現方式:

  1. 實現javax.servlet.Servlet接口                                           (對應三)
  2. 繼承javax.servlet.GenericServlet類                                  (對應六)
  3. 繼承javax.servlet.http.HttpServlet類(常用方式)     (對應七)

 

Servlet核心jar包:

         tomcat/lib目錄下的servlet-api.jar

 

響應客戶請求的過程:

 

二. 在web.xml中配置Servlet

 

在新建項目的WebContent\WEB-INF\下,有web.xml配置文件。如果沒有,新建項目時,第三步需要勾選

在根標籤<web-app></webapp>中配置Servlet的相關信息,如下:

  <servlet>

         <!-- 聲明名字,可以任意 -->

         <servlet-name>firstServlet</servlet-name>

         <!-- 聲明類名字 -->

         <servlet-class>com.qibao.servlet.firstServlet</servlet-class>

    </servlet>

   

    <!-- 配置如何訪問這個servlet -->

    <servlet-mapping>

         <!-- 必須和要和 某個聲明的servlet名字一樣 -->

         <servlet-name>oneServlet</servlet-name>

         <!-- 聲明訪問的url路徑 -->

         <url-pattern>/first</url-pattern>

    </servlet-mapping>

  1. Servlet程序必須通過Servlet容器來啓動運行,並且儲存目錄有特殊要求,需要存儲在<WEB應用程序目錄>\WEB-INF\classes\目錄中。
  2. Servlet程序必須在WEB應用程序的web.xml文件中進行註冊和映射其訪問路徑,纔可以被Servlet引擎加載和被外界訪問。
  3. 一個<servlet>元素用於註冊一個Servlet,它包含有兩個主要的子元素:<servlet-name>和<servlet-class>,分別用於設置Servlet的註冊名稱和Servlet的完整類名。
  4. 一個<servlet-mapping>元素用於映射一個已註冊的Servlet的一個對外訪問路徑,它包含有兩個子元素:<servlet-name>和<url-pattern>,分別用於指定Servlet的註冊名稱和Servlet的對外訪問路徑。

 

  • 一個Servlet可映射多個URL,即多個<servlet-mapping>元素的<servlet-name>設置的值可以是同一個Servlet的註冊名。
  • Servlet映射中可使用*通配符,但是隻能有兩種固定的格式:一種格式是“*.擴展名”;另一種格式是以正斜槓/開頭並以“/*”結尾,例如/action/*。/代表當前web應用的路徑,即http://localhost:8080/webapp/
  • * 兩邊不能同時出現數據  /action/*do

 

<load-on-startup>1</load-on-startup>

在<servlet></servlet>標籤中添加,容器加載web應用時,就創建此servlet實例,並調用init()方法.需要一個大於0的整數.值越小優先級越高.

不加這個選項只有當頁面第一次發送請求時纔去創建servlet,調用init().

通過註解的方式註冊Servlet

@WebServlet("/firstServlet")

  1. @WebServlet 用於將一個類聲明爲 Servlet
  2. @WebInitParam該註解通常不單獨使用,而是配合 @WebServlet 或者 @WebFilter 使用。它的作用是爲 Servlet 或者過濾器指定初始化參數

屬性名

類型

描述

name

String

指定 Servlet name 屬性。如果沒有顯式指定,則該 Servlet 的取值即爲類的全限定名。

value

String[]

該屬性等價於 urlPatterns 屬性

urlPatterns

String[]

指定一組 Servlet URL 匹配模式

loadOnStartup

int

指定 Servlet 的加載順序

initParams

WebInitParam[]

指定一組 Servlet 初始化參數

asyncSupported

boolean

聲明 Servlet 是否支持異步操作模式

description

String

Servlet 的描述信息

displayName

String

Servlet 的顯示名,通常配合工具使用

 

Servlet的調用過程:

 

三. 實現Servlet接口

 

開發Servlet的第一種方式——實現Servlet接口。

        Servlet接口中有六個方法需要實現:

public class FirstServlet implements Servlet {

    //tomcat服務停止時,初始化Servlet的方法,由tomcat調用,只執行一次。

    @Override

    public void init(ServletConfig arg0) throws ServletException {}



    //用戶的每一次請求,都會執行這個方法,由用戶發出請求,由tomcat調用這個方法

    @Override

    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {}



    //tomcat服務停止時,服務器會去銷燬Servlet,由tomcat調用,用於清空某些資源,只調用一次

    @Override

    public void destroy() {}

   

    //獲取這個servlet在web.xml中的配置信息

    @Override

    public ServletConfig getServletConfig() {return null;}



    //獲取這個serlvet的名稱

    @Override

    public String getServletInfo() {return null;}

}

 

四. Servlet生命週期

指的就是Servlet的出生到結束。分別經歷了加載、初始化、服務、銷燬。

  1. 加載階段:加載並實例化,創建servlet實例,只調用一次構造方法;
  2. 初始化階段: 調用init()方法,只調用一次初始化方法;
  3. 響應客戶請求階段:調用service()方法,一般業務邏輯在這裏處理;
  4. 終止階段:調用destroy()方法。

當請求servlet的時候:

  • Servlet引擎檢查是否已經裝載並創建了該Servlet的實例對象。如果是,則直接執行第④步,否則,執行第②步。
  • 裝載並創建該Servlet的一個實例對象:調用該 Servlet 的構造器
  • 調用Servlet實例對象的init()方法。
  • 創建一個用於封裝請求的ServletRequest對象和一個代表響應消息的ServletResponse對象,然後調用Servlet的service()方法並將請求和響應對象作爲參數傳遞進去。
  • WEB應用程序被停止或重新啓動之前,Servlet引擎將卸載Servlet,並在卸載之前調用Servlet的destroy()方法。

 

五. ServletConfig接口

 

功能:讀取web.xml中配置的serlvet信息。

 

Servlet容器將代表當前web應用的對象(ServletContext)和Servlet的配置參數信息一併封裝到一個稱爲ServletConfig的對象中,並在初始化Servlet實例對象時調用init(ServletConfig  config)方法將ServletConfig對象傳遞給Servlet。

 

常見方法(可在初始化時通過傳入的參數ServletConfig  config調用):

  • getServletName()                      獲取當前Servlet在web.xml中配置的名字
  • getServletContext()           獲取代表當前web應用的ServletContext對象
  • getInitParameter(String)   獲取當前Servlet指定名稱的初始化參數的值
  • getInitParameterNames()  獲取當前Servlet所有初始化參數的名字組成的枚舉

配置web.xml

    <servlet>

         <servlet-name>secondServlet</servlet-name>

         <servlet-class>com.qibao.servlet.SecondServlet</servlet-class>

         <init-param>

             <param-name>username</param-name>

             <param-value>admin</param-value>

         </init-param>

         <init-param>

             <param-name>password</param-name>

             <param-value>123456</param-value>

         </init-param>

    </servlet>

    <servlet-mapping>

         <servlet-name>secondServlet</servlet-name>

         <url-pattern>/second.do</url-pattern>

    </servlet-mapping>

在init(ServletConfig  config)方法中調用:

    @Override

    public void init(ServletConfig config) throws ServletException {

         System.err.println("在配置文件中的名稱:" + config.getServletName());

         //獲取所有初始化參數的名字組成的枚舉

         Enumeration<String> en = config.getInitParameterNames();

         while (en.hasMoreElements()) {

             String nm = (String) en.nextElement();

             // 根據初始化的名字獲取值

             String value = config.getInitParameter(nm);

             System.err.println(nm + ":" + value);

         }

    }

 

六. GenericServlet

 

開發Servlet的第二種方式——繼承GenericServlet類。

省略在web.xml中配置的環節,直接看代碼

public class SecondServlet extends GenericServlet{

    private static final long serialVersionUID = 1L;

    @Override
    public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {}

}
  1. GenericServlet提供除service()方法外所有Servlet接口中方法的缺省實現,GenericServlet的方法,只有service(req,res)是抽象方法,只需要實現這個方法就好
  2. GenericServlet也實現了ServletConfig接口,處理初始化參數和servlet上下文,提供對授權傳遞到init()方法中的ServletConfig對象的獲取方法getServletConfig()。
  3. 如果要做初始化操作,可重寫GenericServlet中的init()方法 。而非init(servleconfig)帶參數的方法。 init() --- 此方法不是serlvet的生命週期方法,只是被GenericSerlvet中的init(servleconfig)再次調用的方法 。

1:實現了javax.serlvet.Selvet接口,用戶只需要重寫service方法;

2:包裝了SevletConfig用戶可直接調用。

 

七. HttpServlet

 

開發Servlet的第三種方式——繼承HttpServlet類。

  1. HttpServlet是GenericServlet的子類
  2. HttpServlet 類通過調用指定到HTTP請求的方法實現service()
  3. 通過HttpServlet去開發servlet,需要重寫doGet、doPost方法
@WebServlet("/thirdServlet")

public class ThirdServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public ThirdServlet() {super();}



    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

         response.getWriter().append("Served at: ").append(request.getContextPath());

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

         doGet(request, response);

    }

}

  • 調用 MyServlet的service(ServletRequest, ServletResponse)方法,但MyServlet沒有重寫這個方法,所以到MyServlet的父類HttpServlet去找;
  • 調用HttpServlet的service(ServletRequest, ServletResponse)方法,它又調用了service(HttpServletRequest, HttpServletResponse);
  • HttpServlet的service(HttpServletRequest, HttpServletResponse)方法,它先對請的方法進行判斷,如果是GET請求,則調用doGet()方法,如果是POST請求,則調用doPost()方法;
  • 如果在MyServlet中重寫了 doGet(),doPost()方法,則會調用MyServlet中的重寫的響應的doGet(),doPost()方法。

注:必須要重寫至少一個doXXX方法,如果沒有重寫doXXX方法,則會報405錯誤

 

八. 線程安全問題

 

servlet不是線程安全的。Servlet體系結構建立在Java多線程機制之上,它的生命週期由Web容器負責。當客戶端第一次請求某個Servlet時,Servlet容器將會根據配置文件實例化這個Servlet類。當有新的客戶端請求該Servlet時,一般不會再實例化該Servlet類,也就是有多個線程在使用這個實例。當兩個或多個線程同時訪問同一個Servlet時,可能會發生多個線程同時訪問同一資源的情況,數據可能會變得不一致。可參考售票系統.

解決方法:

  • 使用 synchronized同步代碼塊。效率太低,不建議使用
  • 不依賴實例全局成員變量,將接收參數的變量聲明成局部變量。因爲,局部變量默認就是線程安全的。局部變量在線程的棧中,先進後出。

 

九. ServletContext接口

 

ServletContext是一個全局的儲存信息的空間,服務器開始就存在,服務器關閉才釋放。

一個web項目,只存在一個ServletContext實例,每個Servlet都可以訪問到它,用於共享數據。        

獲取方法:

ServletConfig和GenericServlet的getServletContext()方法

功能:

  • 獲取WEB應用程序的初始化參數。
  • //配置全局初始化參數

<context-param>

         <param-name>name</param-name>

         <param-value>張三</param-value>

</context-param>

//獲取全局初始化參數

ServletContext ctx = getServletContext();

Enumeration<String> en = ctx.getInitParameterNames();

while (en.hasMoreElements()) {

  String nm = (String) en.nextElement();

  //根據初始化的名字獲取值

  String value = ctx.getInitParameter(nm);

  out.print(nm+":"+value+"<hr>");

}

 

  • 獲取項目的真實的路徑。

 

//獲取真實路徑(在服務器上的絕對路徑)

response.getWriter().print(ctx.getRealPath("/imgs")+"<hr>");

//獲取項目應用上下文(/webapp名稱)

response.getWriter().print(ctx.getContextPath()+"<hr>");

 

  • 做爲域對象,保存多個客戶共享的數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章