Servlet入門,Servletconfig,Servletcontext,註解配置Servlet

知識點梳理

詳細講義

1 Servlet

1.1 Servlet概述

  • Servlet 是運行在 Java 服務器端的程序,用於接收和響應來自客戶端基於 HTTP 協議的請求html

  • 若是想實現 Servlet 的功能,能夠經過實現 javax.servlet.Servlet 接口或者繼承它的實現類java

  • 核心方法:service(),任何客戶端的請求都會通過該方法git

 

 

  • Servlet是SUN公司提供的一套規範,名稱就叫Servlet規範,它也是JavaEE規範之一github

  • 咱們能夠像學習Java基礎同樣,經過API來學習Servletweb

  • 這裏須要注意的是,在咱們以前JDK的API中是沒有Servlet規範的相關內容,須要使用JavaEE的API小程序

  • 目前在Oracle官網中的最新版本是JavaEE8,該網址中介紹了JavaEE8的一些新特性瀏覽器

  • 固然,咱們能夠經過訪問官方API,學習和查閱裏面的內容tomcat

  • 打開官方API網址,在左上部分找到javax.servlet包,在左下部分找到Servlet,以下圖顯示:安全

 

  • 經過閱讀API,咱們獲得以下信息:服務器

  • 第一:Servlet是一個運行在web服務端的java小程序

  • 第二:它能夠用於接收和響應客戶端的請求

  • 第三:要想實現Servlet功能,能夠實現Servlet接口,繼承GenericServlet或者HttpServlet

  • 第四:每次請求都會執行service方法

  • 第五:Servlet還支持配置

  • 具體請看下圖:

 

 

1.2 Servlet入門 ***

1.2.1 Servlet快速入門

  1. 建立一個 WEB 項目

    • servlet_demo1

  2. 建立一個類繼承 GenericServlet

    • 包:com.itheima.servlet

    • 類:ServletDemo1

    • GenericServlet介紹:implements Servlet,實現了Servlet裏的大部分方法,只有一個service方式是抽象的,咱們只須要實現這個方法便可

       

       

  3. 重寫 service 方法

    package com.itheima.servlet;

    import javax.servlet.GenericServlet;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import java.io.IOException;

    /*
       Servlet快速入門1
    */
    public class ServletDemo01 extends GenericServlet{

       @Override  
       public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
           System.out.println("service方法執行了...");
      }
    }
    • service有兩個參數,servletRequest,servletResponse ,這倆分別是處理請求和響應的,後續會詳細介紹

  4. 在 web.xml 中配置 Servlet

    <!--配置快速入門1Servlet-->
    <servlet>
       <servlet-name>servletDemo01</servlet-name>
       <servlet-class>com.itheima.servlet.ServletDemo01</servlet-class>
    </servlet>
    <servlet-mapping>
       <servlet-name>servletDemo01</servlet-name>
       <url-pattern>/servletDemo01</url-pattern>
    </servlet-mapping>
  5. 部署並啓動項目:配置項目虛擬路徑:/demo1

  6. 經過瀏覽器測試

     

     

  7. 分析圖:(下圖與實際案例有出入,可是咱們只須要搞清楚Servlet訪問流程便可)

 

 

1.2.2 Servlet執行過程分析

  1. 咱們經過瀏覽器發送請求,請求首先到達Tomcat服務器

  2. 由服務器解析請求URL,而後在部署的應用列表中找到咱們的應用

  3. 接下來,在咱們的應用中找應用裏的web.xml配置文件

  4. 在web.xml中找到Servlet的配置

  5. 找到後執行service方法,最後由ServletDemo1響應客戶瀏覽器

整個過程以下圖所示:

 

 

一句話總結執行過程:

瀏覽器——>Tomcat服務器——>咱們的應用——>應用中的web.xml——>Servlet——>響應瀏覽器

1.2.3 Servlet關係視圖

  • 關係視圖以下:

     

     

    • Servlet,GenericServlet,HTTPServlet,他們都有service方法

    • service方法都有倆參數,ServletRequest,ServletResponse

    • HTTPServlet的參數是HttpServletRequest,HttpServletResponse,他們分別繼承自ServletRequest,ServletResponse

    • 這倆參數都是接口,分別處理請求,響應

    • ServletConfig,處理配置

    • ServletContext,處理多個Servlet之間信息共享

     

1.2.4 Servlet實現方式

1)實現方式說明

  1. 第一種 實現 Servlet 接口,實現全部的抽象方法。該方式支持最大程度的自定義。

  2. 第二種 繼承 GenericServlet 抽象類,必須重寫 service 方法,其餘方法可選擇重寫。該方式讓咱們開發 Servlet 變得簡單。可是這種方式和 HTTP 協議無關。

  3. 第三種 繼承 HttpServlet 抽象類,須要重寫 doGet 和 doPost 方法。該方式表示請求和響應都須要和 HTTP 協議相關。

  • 上述前兩種都給你們演示過了,咱們接下來來試一下第三種

2)繼承HttpServlet ***

  • 步驟

    1. 建立一個類繼承 HttpServlet

      //servlet_demo1新建:ServletDemo02.java
      package com.itheima.servlet;

      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;

      /*
         Servlet快速入門2
      */
      public class ServletDemo02 extends HttpServlet {
       
      }
    2. 重寫 doGet 和 doPost 方法

      public class ServletDemo02 extends HttpServlet {

         @Override
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             System.out.println("方法執行了...");
        }

         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             //post請求方式通常與get請求方式處理的邏輯同樣,因此直接調用doGet
             doGet(req,resp);
        }
      }
    3. 在 web.xml 中配置 Servlet

      <!--配置快速入門2Servlet-->
      <servlet>
         <servlet-name>servletDemo02</servlet-name>
         <servlet-class>com.itheima.servlet.ServletDemo02</servlet-class>
      </servlet>
      <servlet-mapping>
         <servlet-name>servletDemo02</servlet-name>
         <url-pattern>/servletDemo02</url-pattern>
      </servlet-mapping>
    4. 部署並啓動項目

    5. 經過瀏覽器測試

       

       

     

1.3 Servlet使用細節

1.3.1 Servlet的生命週期

  • 對象的生命週期,就是對象從出生到死亡的過程。即:出生 -> 活着 -> 死亡。官方說法是對象建立到銷燬的過程

  • 出生:請求第一次到達 Servlet 時,對象就建立出來,而且初始化成功。只出生(建立)一次,將對象放到內存中

  • 活着:服務器提供服務的整個過程當中,該對象一直存在,每次都是執行 service 方法

  • 死亡:當服務中止時,或者服務器宕機時,對象死亡

  • 結論:Servlet 對象只會建立一次,銷燬一次。因此 Servlet 對象只有一個實例。若是一個對象實例在應用中是惟一的存在,那麼咱們就稱它爲單例模式

  • 代碼

    1. 建立ServletDemo03

      package com.itheima.servlet;

      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      /*
         Servlet生命週期
      */
      public class ServletDemo03 extends HttpServlet {
         @Override
         public void init() throws ServletException {
             System.out.println("對象建立並初始化了...");
        }

         @Override
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             System.out.println("接收到了客戶端的請求...");
        }

         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             doGet(req,resp);
        }

         @Override
         public void destroy() {
             System.out.println("對象銷燬了...");
        }
      }
    2. 配置Servlet

      <!--演示Servlet生命週期的配置-->
      <servlet>
         <servlet-name>servletDemo03</servlet-name>
         <servlet-class>com.itheima.servlet.ServletDemo03</servlet-class>
      </servlet>
      <servlet-mapping>
         <servlet-name>servletDemo03</servlet-name>
         <url-pattern>/servletDemo03</url-pattern>
      </servlet-mapping>
    3. 部署並啓動

       

       

      • 說明:init只會執行一次

    4. 中止服務

       

       

      • 中止tomcat,執行destory

1.3.2 Servlet的線程安全 **難點

  • 因爲 Servlet 採用的是單例模式,也就是整個應用中只有一個實例對象。因此咱們須要分析這個惟一的實例對象中的類成員是否線程安全

  • 模擬用戶登陸功能來查看 Servlet 線程是否安全

  • 結論:一個瀏覽器表明一個線程,多個瀏覽器表明多個線程。按理說咱們指望的應該是每一個瀏覽器查看的都應該是本身的用戶名。而如今的結果是瀏覽器中數據混亂。所以,咱們能夠認爲 Servlet 是線程不安全的!

  • 解決:定義類成員要謹慎。若是是共用的,而且只會在初始化時賦值,其餘時間都是獲取的話,那麼是沒問題的。若是不是共用的,或者每次使用都有可能對其賦值,那就要考慮線程安全問題了,能夠將其定義到 doGet 或 doPost 方法內或者使用同步功能便可。

  • 案例演示

    1. 新建ServletDemo4

      package com.itheima.servlet;

      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.io.PrintWriter;

      /*
         Servlet線程安全
      */
      public class ServletDemo04 extends HttpServlet{
         //1.定義用戶名成員變量
         private String username = null;

         @Override
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

                 //2.獲取用戶名
                 username = req.getParameter("username");
                 try {
                     Thread.sleep(3000);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }

                 //3.獲取輸出流對象
                 PrintWriter pw = resp.getWriter();

                 //4.響應給客戶端瀏覽器
                 pw.print("welcome:" + username);

                 //5.關流
                 pw.close();
        }

         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             doGet(req,resp);
        }
      }
    2. Servlet配置

      <!--演示Servlet線程安全的配置-->
         <servlet>
             <servlet-name>servletDemo04</servlet-name>
             <servlet-class>com.itheima.servlet.ServletDemo04</servlet-class>
         </servlet>
         <servlet-mapping>
             <servlet-name>servletDemo04</servlet-name>
             <url-pattern>/servletDemo04</url-pattern>
         </servlet-mapping>
    3. 演示

      • 由於須要演示線程安全,因此須要兩個瀏覽器模擬兩個線程,因此要開兩個瀏覽器

      • 谷歌瀏覽器中url傳遞參數username=aaa

      • 火狐瀏覽器中url傳遞參數username=bbb

      • 而後谷歌瀏覽器先訪問,緊接着火狐瀏覽器訪問

       

       

      • 結果現象是,倆瀏覽器都是welcome:bbb

    4. 分析

       

       

    5. 解決1:將username由成員變量,放到方法中

      package com.itheima.servlet;

      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.io.PrintWriter;

      /*
         Servlet線程安全
      */
      public class ServletDemo04 extends HttpServlet{
         //1.定義用戶名成員變量
         //private String username = null;

         @Override
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             String username = null;//谷歌瀏覽器進來有一個username,火狐進來也有一個username,因此不會覆蓋
                 //2.獲取用戶名
                 username = req.getParameter("username");

                 try {
                     Thread.sleep(3000);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }

                 //3.獲取輸出流對象
                 PrintWriter pw = resp.getWriter();

                 //4.響應給客戶端瀏覽器
                 pw.print("welcome:" + username);

                 //5.關流
                 pw.close();
        }

         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             doGet(req,resp);
        }
      }
    6. 使用同步代碼塊

      package com.itheima.servlet;

      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.io.PrintWriter;

      /*
         Servlet線程安全
      */
      public class ServletDemo04 extends HttpServlet{
         //1.定義用戶名成員變量
         //private String username = null;

         @Override
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      //       String username = null;
             synchronized (this) { //鎖須要惟一,Servlet對象就是惟一的,因此用this
                 //2.獲取用戶名
                 username = req.getParameter("username");

                 try {
                     Thread.sleep(3000);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }

                 //3.獲取輸出流對象
                 PrintWriter pw = resp.getWriter();

                 //4.響應給客戶端瀏覽器
                 pw.print("welcome:" + username);

                 //5.關流
                 pw.close();
            }
        }

         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             doGet(req,resp);
        }
      }

1.3.3 不一樣映射方式

1)介紹

  1. 第一種 具體名稱的方式。訪問的資源路徑必須和映射配置徹底相同

  2. 第二種 / 開頭 + 通配符的方式。只要符合目錄結構便可,不用考慮結尾是什麼

  3. 第三種 通配符 + 固定格式結尾的方式。只要符合固定結尾格式便可,不用考慮前面的路徑

注意:優先級問題。越是具體的優先級越高,越是模糊通用的優先級越低。第一種 -> 第二種 -> 第三種

2)第一種:具體名稱的方式 (精準匹配)***

  • 此種方式,只有和映射配置如出一轍時,Servlet纔會接收和響應來自客戶端的請求。

  • 例如:映射爲:/servletDemo5

  • 訪問URL:http://localhost:8080/demo1/servletDemo5

  • 新建ServletDemo5

    package com.itheima.servlet;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    /*
       Servlet不一樣映射方式
    */
    public class ServletDemo05 extends HttpServlet {
       @Override
       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           System.out.println("ServletDemo05執行了...");
      }

       @Override
       protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           doGet(req,resp);
      }
    }
  • 配置Servlet

     <!--演示Servlet不一樣映射方式-->
    <!--具體名稱的方式-->
    <servlet>
       <servlet-name>servletDemo05</servlet-name>
       <servlet-class>com.itheima.servlet.ServletDemo05</servlet-class>
    </servlet>
    <servlet-mapping>
       <servlet-name>servletDemo05</servlet-name>
       <url-pattern>/servletDemo05</url-pattern>
    </servlet-mapping>
  • 訪問:

 

 

3)第二種:/開頭+通配符的方式

  • 咱們仍是使用ServletDemo5,只須要修改配置便可(把上一個具體名稱的配置屏蔽掉)

     <!--/開頭+通配符的方式-->
    <servlet>
       <servlet-name>servletDemo05</servlet-name>
       <servlet-class>com.itheima.servlet.ServletDemo05</servlet-class>
    </servlet>
    <servlet-mapping>
       <servlet-name>servletDemo05</servlet-name>
       <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
  • 訪問

     

     

4) 第三種:通配符+固定格式結尾

  • 此種方式,只要符合固定結尾格式便可,其前面的訪問URI無須關心(注意協議,主機和端口必須正確)

  • 例如:映射爲:*.do

  • 訪問URL:http://localhost:8080/demo1/aaa.do

    http://localhost:8080/demo1/bbb.do

  • 這兩個URL均可以方法。由於都是以.do做爲結尾,而前面用*號通配符配置的映射,全部無須關心。

  • 依然使用ServletDemo5,修改配置便可

    <!--通配符+固定格式結尾的方式-->
    <servlet>2
       <servlet-name>servletDemo05</servlet-name>
       <servlet-class>com.itheima.servlet.ServletDemo05</servlet-class>
    </servlet>
    <servlet-mapping>
       <servlet-name>servletDemo05</servlet-name>
       <url-pattern>*.do</url-pattern>
    </servlet-mapping>
  • 訪問

     

     

 

1.3.4 Servlet多映射的使用場景

  • 咱們能夠給一個 Servlet 配置多個訪問映射,從而根據不一樣的請求路徑來實現不一樣的功能

  • 場景分析:

    • 若是訪問的資源路徑是 /vip 商品價格打9折

    • 若是訪問的資源路徑是 /vvip 商品價格打5折

    • 若是訪問的資源路徑是其餘 商品價格不打折

  • 案例:新建ServletDemo6

    package com.itheima.servlet;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    /*
       Servlet 多路徑映射
    */
    public class ServletDemo06 extends HttpServlet {
       @Override
       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //1. 定義一個商品金額
           int money = 1000;

           //2. 獲取訪問的資源路徑
           String name = req.getRequestURI();
           name = name.substring(name.lastIndexOf("/"));
           
           //3. 條件判斷
           if("/vip".equals(name)) {
               //若是訪問資源路徑是/vip 商品價格爲9折
               System.out.println("商品原價爲:" + money + "。優惠後是:" + (money*0.9));
          } else if("/vvip".equals(name)) {
               //若是訪問資源路徑是/vvip 商品價格爲5折
               System.out.println("商品原價爲:" + money + "。優惠後是:" + (money*0.5));
          } else {
               //若是訪問資源路徑是其餘 商品價格原樣顯示
               System.out.println("商品價格爲:" + money);
          }
      }

       @Override
       protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           doGet(req,resp);
      }
    }
  • 配置Servlet

    <!--演示Servlet多路徑映射-->
        <servlet>
            <servlet-name>servletDemo06</servlet-name>
            <servlet-class>com.itheima.servlet.ServletDemo06</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>servletDemo06</servlet-name>
            <url-pattern>/itheima/*</url-pattern>
        </servlet-mapping>
  • 訪問

     

     

1.3.5 Servlet建立時機

  1. 第一次訪問時建立

優點:減小對服務器內存的浪費。提升了服務器啓動的效率

弊端:若是有一些要在應用加載時就作的初始化操做,沒法完成

  1. 服務器加載時建立

優點:提早建立好對象,提升了首次執行的效率。能夠完成一些應用加載時要作的初始化操做

弊端:對服務器內存佔用較多,影響了服務器啓動的效率

 

  • 修改 Servlet 建立時機。在<servlet>標籤中,添加<load-on-startup>標籤。

 

 

  • 正整數表明服務器加載時建立,值越小、優先級越高。 負整數或不寫表明第一次訪問時建立

    • <load-on-startup>加載順序的序號</load-on-startup>

    • 序號爲1,就是服務器啓動時第一個加載

    • 序號爲2,就是服務器啓動時第二個加載

  • 若是兩個Servlet都要配置爲正整數,那麼值小的優先級高

  • 配置:修改ServletDemo3的配置,增長load-on-startup

     <!--演示Servlet生命週期的配置-->
        <servlet>
            <servlet-name>servletDemo03</servlet-name>
            <servlet-class>com.itheima.servlet.ServletDemo03</servlet-class>
            <!--配置Servlet啓動時機 正整數表明服務器啓動時建立,負數或不寫表明第一次訪問時建立-->
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>servletDemo03</servlet-name>
            <url-pattern>/servletDemo03</url-pattern>
        </servlet-mapping>
  • 效果:若是不配置,是在訪問ServletDemo3 的時候初始化,若是配置,那就是在啓動tomcat的時候初始化

    • 下圖是配置後,啓動tomcat打印的

     

     

1.3.6 默認Servlet

  • 默認Servlet是由服務器提供的一個Servlet,它配置在Tomcat的conf目錄下的web.xml中。以下圖所示:

 

 

  • 它的映射路徑是<url-pattern>/<url-pattern>,咱們在發送請求時,首先會在咱們項目中的 web.xml 中查找映射配置,找到則執行

  • 可是當找不到對應的 Servlet 路徑時,就去找默認的 Servlet,由默認 Servlet 處理。因此,一切都是 Servlet。

  • 訪問一個不存在的url

     

     

    • 這個404界面,其實就是tomcat配置的默認的Servlet處理的結果

2 ServletConfig

2.1 ServletConfig介紹

2.1.1 基本概念 ***

  • ServletConfig 是 Servlet 的配置參數對象,在 Servlet 的規範中,容許爲每個 Servlet 都提供一些初始化的配置。因此,每一個 Servlet 都有一個本身的 ServletConfig

  • 做用:在 Servlet 的初始化時,把一些配置信息傳遞給 Servlet

2.1.2 生命週期

  • 生命週期:和 Servlet 相同

  • 因爲它是在初始化階段讀取了web.xml中爲Servlet準備的初始化配置,並把配置信息傳遞給Servlet,因此生命週期與Servlet相同

  • 這裏須要注意的是,若是Servlet配置了<load-on-startup>1</load-on-startup>,那麼ServletConfig也會在應用加載時建立

 

 

  • ServletConfig的配置信息都是鍵值對的形式

2.2 ServletConfig的使用

2.2.1 配置方式

  • <servlet>標籤中,經過<init-param>標籤來配置。有兩個子標籤。

  • <param-name>:表明初始化參數的 key。

  • <param-value>:表明初始化參數的 value。

     

     

    • 一個init-param配置一個信息,一個信息由name和value組成

  • 案例

    1. 新建項目:servlet_demo2

    2. src中新建包:com.itheima.servlet

    3. 新建類:ServletConfigDemo

      package com.itheima.servlet;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      
      /*
          ServletConfig的使用
       */
      public class ServletConfigDemo extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      
          }
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req,resp);
          }
      }
      
    4. 配置Servlet

      <!--配置Servlet-->
      <servlet>
          <servlet-name>servletConfigDemo</servlet-name>
          <servlet-class>com.itheima.servlet.ServletConfigDemo</servlet-class>
          <!--配置ServletConfig初始化參數-->
          <init-param>
               <!--用於獲取初始化參數的key-->
              <param-name>encoding</param-name>
              <!--初始化參數的值-->
              <param-value>UTF-8</param-value>
          </init-param>
          <init-param>
              <param-name>desc</param-name>
              <param-value>This is ServletConfig</param-value>
          </init-param>
      </servlet>
      <servlet-mapping>
          <servlet-name>servletConfigDemo</servlet-name>
          <url-pattern>/servletConfigDemo</url-pattern>
      </servlet-mapping>

2.2.2 經常使用方法

  • 經常使用方法:

     

     

    • 掌握getInitParameter()方法

  • 代碼:接着在ServletConfigDemo中寫代碼:

    public class ServletConfigDemo extends HttpServlet {
    
        //聲明ServletConfig配置對象
        private ServletConfig config;
    
        /*
            經過init方法來爲ServletConfig配置對象賦值
         */
        @Override
        public void init(ServletConfig config) throws ServletException {
            this.config = config;
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //根據key獲取value
            String encodingValue = config.getInitParameter("encoding");
            System.out.println(encodingValue);
    
            //獲取Servlet的名稱
            String servletName = config.getServletName();
            System.out.println(servletName);
    
            //獲取全部的key
            Enumeration<String> names = config.getInitParameterNames();
            //遍歷獲得的key
            while(names.hasMoreElements()) {
                //獲取每個key
                String name = names.nextElement();
                //經過key獲取value
                String value = config.getInitParameter(name);
                System.out.println("name:" + name + ",value:" + value);
            }
    
            //獲取ServletContext對象
            ServletContext context = config.getServletContext();
            System.out.println(context);
    
            //獲取ServletContextDemo設置共享的數據 , 這個是在寫下個案例的時候添加的
            //Object username = context.getAttribute("username");
            //System.out.println(username);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 部署項目,配置虛擬目錄爲demo2,啓動tomcat

  • 效果

     

     

 

3 ServletContext

3.1 ServletContext介紹

3.1.1 基本介紹 ***

  • ServletContext 是應用上下文對象每個應用中只有一個 ServletContext 對象

  • 做用:能夠得到應用的全局初始化參數和達到 Servlet 之間的數據共享。

  • 上下文理解:環境,不一樣環境給咱們帶來的信息是不同的。因此環境中有不少信息,數據,也就是環境是用於存儲數據的。

  • 生命週期:應用一加載則建立,應用被中止則銷燬。

    • 出生——活着——死亡

    • 出生: 應用一加載,該對象就被建立出來了。一個應用只有一個實例對象。(Servlet和ServletContext都是單例的)

    • 活着:只要應用一直提供服務,該對象就一直存在。

    • 死亡:應用被卸載(或者服務器掛了),該對象消亡。

  • ServletContext圖示:

     

     

3.1.2 域對象概念 ***

  • 域對象指的是對象有做用域也就是有做用範圍

  • 域對象能夠實現數據的共享

  • 不一樣做用範圍的域對象,共享數據的能力也不同

  • 在 Servlet 規範中,一共有 4 個域對象

    • ServletContext 就是其中的一個

    • 它也是 web 應用中最大的做用域,也叫 application 域

      • 在整個項目範圍均可以使用 應用域共享的數據

    • 它能夠實現整個應用以內的數據共享

    • ServletContext是一個接口,程序運行起來以後打印ServletContext的實例對象,實際上是一個ApplicationContextFacade對象

      • ApplicationContextFacade是ServletContext的實現類

3.2 ServletContext的使用

3.2.1 配置方式

  • ServletContext 並不屬於某個 Servlet 的配置,而是針對於整個應用的配置,也叫全局的初始化參數

  • <web-app>標籤中,經過<context-param>標籤來配置。有兩個子標籤

  • <param-name>:表明全局初始化參數的 key

  • <param-value>:表明全局初始化參數的 value

     

     

  • 案例:新建ServletContextDemo

    package com.itheima.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class ServletContextDemo extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 配置Servlet,而且配置ServletContext

    <web-app>
        ....
        <!--配置Servlet-->
        <servlet>
            <servlet-name>servletContextDemo</servlet-name>
            <servlet-class>com.itheima.servlet.ServletContextDemo</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>servletContextDemo</servlet-name>
            <url-pattern>/servletContextDemo</url-pattern>
        </servlet-mapping>
    
    
        <!--配置ServletContext-->
        <context-param>
            <param-name>globalEncoding</param-name>
            <param-value>UTF-8</param-value>
        </context-param>
        <context-param>
            <param-name>globalDesc</param-name>
            <param-value>This is ServletContext</param-value>
        </context-param>
    </web-app>
    • 注意ServletContext的配置是在wep-app節點下,與servlet配置同級別

3.2.2 經常使用方法1 ***

  • 經常使用方法

     

     

    • 掌握:getContextPath和getRealPath

  • 準備工做:新建三個空的txt文件,以下

     

     

  • 代碼:繼續在ServletContextDemo中寫:

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //獲取ServletContext對象
            ServletContext context = getServletContext();
    
            //獲取全局配置的globalEncoding
            String value = context.getInitParameter("globalDesc");
            System.out.println(value);
    
            //獲取應用的訪問虛擬目錄
            String contextPath = context.getContextPath();
            System.out.println(contextPath);
    
            //根據虛擬目錄獲取應用部署的磁盤絕對路徑
        	String realPath = context.getRealPath("/");
            System.out.println(realPath);
            //獲取b.txt文件的絕對路徑
            String b = context.getRealPath("/b.txt");
            System.out.println(b);
    
            //獲取c.txt文件的絕對路徑
            String c = context.getRealPath("/WEB-INF/c.txt");
            System.out.println(c);
    
            //獲取a.txt文件的絕對路徑
            String a = context.getRealPath("/WEB-INF/classes/a.txt");
            System.out.println(a);
        }
    
  • 效果

     

     

    • context.getRealPath("/");獲取到的就是當前項目發佈的路徑

3.2.3 經常使用方法2 ***

  • 經常使用方法2

     

     

  • 代碼:

    //修改ServletContextDemo:存儲數據
     	//向域對象中存儲數據
     	context.setAttribute("username","zhangsan");
    //修改ServletConfigDemo:獲取數據
        //獲取ServletContextDemo設置共享的數據
        Object username = context.getAttribute("username");
        System.out.println(username);
  • 效果

    • 先訪問contextdemo存儲數據

    • 再訪問configdemo獲取數據

     

     

4 註解開發Servlet

4.1 Servlet3.0規範

  • 咱們使用的是 Tomcat 9 版本。JavaEE 規範要求是 8 。對應的 Servlet 版本應該是 4.x 版本。可是,在企業開發中,穩定要遠比追求新版本要重要。因此咱們會降版本使用,用的是 Servlet 3.1 版本

  • 其實咱們以前的操做全都是基於 Servlet 2.5 版本規範的,也就是藉助於配置文件的方式。後來隨着軟件開發逐步的演變,基於註解的配置開始流行。而 Servlet 3.0 版本也就開始支持註解開發了

  • Servlet 3.0 版本既保留了 2.5 版本的配置方式,同時又支持了全新的註解配置方式。它能夠徹底不須要 web.xml 配置文件,就能實現 Servlet 的配置,同時還有一些其餘的新特性,咱們在後面的課程中會慢慢學習到

     

     

  • 總結:

    • 以前基於配置文件方式,這個是Servlet2.5版本的規範

    • 可是每添加一個Servlet,就須要本身配置一個,感受有點繁瑣

    • Servlet3.0就出現了註解方式,能夠省去配置

4.2 註解開發

4.2.1 自動註解開發Servlet ***

  1. 新建項目:servlet_demo3

  2. 配置Java EE8

     

     

    • 剩餘兩步省略

  3. 新建以後,項目目錄以下

     

     

    • web下沒有WEB-INF了,web.xml也沒有了

      • 雖然web.xml不用了,可是WEB-INF還須要,因此WEB-INF須要本身建立出來

    • index.jsp沒用,刪除便可

  4. 新建類:com.itheima.servlet.ServletDemo1

    package com.itheima.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /*
        自動註解配置Servlet
        @WebServlet("Servlet路徑")
     */
    @WebServlet("/servletDemo1")
    public class ServletDemo1 extends HttpServlet{
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("servlet執行了...");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  5. 能夠正常訪問

4.2.2 註解詳解

  • 註解詳解

     

     

4.2.3 手動建立容器(瞭解)

1)前置說明

  • Servlet 3.0 規範除了使用自動註解的配置方式外,還支持手動建立 Servlet 容器的方式

  • 若是使用必須遵循其編寫規範。在 3.0 版本加入了一個新的接口:

     

     

2)編寫步驟

  1. 定義一個類ServletDemo2,繼承 HttpServlet

  2. 重寫 doGet 和 doPost 方法

    package com.itheima.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    /*
        手動建立容器配置Servlet
     */
    public class ServletDemo2 extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("servlet執行了...");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
  3. 定義一個類,實現 ServletContainerInitializer 接口

    package com.itheima.servlet;
    
    import javax.servlet.ServletContainerInitializer;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletRegistration;
    import java.util.Set;
    /*
        註冊配置Servlet的功能類
     */
    public class MyRegister implements ServletContainerInitializer {
        @Override
        public void onStartup(Set<Class<?>> set, ServletContext servletContext) {
            //完成Servlet的建立和配置
        }
    }
    
  4. 在 src 目錄下建立一個 META-INF 的

  5. 在 META-INF 包下建立一個 services 的包

  6. 在 services 包下建立一個 javax.servlet.ServletContainerInitializer 的文件

  7. 文件中的內容爲容器實現類的全類名

    com.itheima.servlet.MyRegister
  8. 在容器實現類中的 onStartup 方法中完成註冊 Servlet

    public void onStartup(Set<Class<?>> set, ServletContext servletContext) {
        //完成Servlet的建立和配置
        //1.建立Servlet對象
        ServletDemo2 servletDemo2 = new ServletDemo2();
    
        //2.在ServletContext中添加Servlet,並獲得Servlet的配置對象
        ServletRegistration.Dynamic registration = servletContext.addServlet("servletDemo2", servletDemo2);
    
        //3.配置Servlet
        registration.setLoadOnStartup(0);   //Servlet加載時機
        registration.addMapping("/servletDemo2");   //映射訪問資源路徑
    }
  9. 部署並啓動項目

  10. 經過瀏覽器測試

     

     

5 Servlet應用案例-學生管理系統 ***

5.1 案例效果介紹

  • 效果

     

     

    • 訪問案例首頁,看到一個能夠保存學生信息的界面

    • 輸入內容,點擊保存,經過java服務器,而後最終保存到txt中

    • 最後java服務器返回成功結果

5.2 案例實現

  1. 建立一個 web 項目:servlet_test,配置虛擬目錄/stu

    • 選擇javaee 7,這裏咱們仍是用web.xml

  2. 建立一個用於保存學生信息的 html 文件:web下新建addStudent.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>添加學生</title>
    </head>
    <body>
        -- ?username=張三&age=18&score=718
        <form action="/stu/studentServlet" method="get" autocomplete="off">
            學生姓名:<input type="text" name="username"> <br/>
            學生年齡:<input type="number" name="age"> <br/>
            學生成績:<input type="number" name="score"> <br/>
            <button type="submit">保存</button>
        </form>
    </body>
    </html>
  3. 建立一個類com.itheima.servlet.StudentServlet,繼承 HttpServlet

  4. 重寫 doGet 和 doPost 方法

    package com.itheima.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class StudentServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  5. 在 web.xml 文件中修改默認主頁和配置 Servlet

     <!--修改默認主頁-->
        <welcome-file-list>
            <welcome-file>/addStudent.html</welcome-file>
        </welcome-file-list>
    
        <!--配置Servlet-->
        <servlet>
            <servlet-name>studentServlet</servlet-name>
            <servlet-class>com.itheima.servlet.StudentServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>studentServlet</servlet-name>
            <url-pattern>/studentServlet</url-pattern>
        </servlet-mapping>
  6. 在 doGet 方法中接收表單數據保存到文件中,並響應給瀏覽器結果

    // -- ?username=張三&age=18&score=718
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //獲取表單中的數據
            String username = req.getParameter("username"); // 獲取url後邊的?的參數
            String age = req.getParameter("age");
            String score = req.getParameter("score");
    
            //將數據保存到stu.txt文件中
            BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\stu.txt",true));
            bw.write(username + "," + age + "," + score);
            bw.newLine();
            bw.close();
    
            //給瀏覽器迴應
            PrintWriter pw = resp.getWriter();
            pw.println("Save Success~");
            pw.close();
        }
  7. 部署並啓動項目

  8. 經過瀏覽器測試

     

相關文章
相關標籤/搜索