1. 程式人生 > 其它 >【JavaWeb】Servlet

【JavaWeb】Servlet

Servlet 簡介


  • Servlet 是 Java提供的一門動態web資源開發技術

  • Servlet 是JavaEE 規範之一,其實就是一個介面,將來我們需要定義Servlet類實現Servlet介面,並由web伺服器執行Servlet。

  • 按照一種約定俗成的稱呼習慣,通常我們也把實現了servlet介面的java程式,稱之為Servlet


使用者若想用發一個動態web資源(即開發一個Java程式向瀏覽器輸出資料),需要完成以下2個步驟:
  1、編寫一個Java類,實現servlet介面。
  2、把開發好的Java類部署到web伺服器中。

Servlet 執行過程

Servlet程式是由WEB伺服器呼叫,web伺服器收到客戶端的Servlet訪問請求後:

①Web伺服器首先檢查是否已經裝載並建立了該Servlet的例項物件。如果是,則直接執行第④步,否則,執行第②步。
  ②裝載並建立該Servlet的一個例項物件。
  ③呼叫Servlet例項物件的init()方法。
  ④建立一個用於封裝HTTP請求訊息的HttpServletRequest物件和一個代表HTTP響應訊息的HttpServletResponse物件,然後呼叫Servlet的service()方法並將請求和響應物件作為引數傳遞進去。
  ⑤WEB應用程式被停止或重新啟動之前,Servlet引擎將解除安裝Servlet,並在解除安裝之前呼叫Servlet的destroy()方法。

Servlet 生命週期

  • 物件的宣告週期指一個物件從被建立到被銷燬的整個過程

  • Servlet執行在Servlet 容器(web伺服器)中,其生命週期由容器來管理,分為4個階段:

  1. 載入和例項化:預設情況下,當Servlet第一次被訪問時,由容器建立Servlet物件
  2. 初始化:在Servlet例項化之後,容器將呼叫Servlet的init()方法初始化這個物件,完成一些如載入配置檔案,建立連線等初始化的工作。該方法只呼叫一次
  3. 請求處理:每次請求Servlet時,Servlet容器都會呼叫Servlet的service()方法對請求進行處理。
  4. 服務終止:當需要釋放記憶體或容器關閉時,容器會呼叫Servlet示例的destroy()方法完成資源的釋放。在destroy()方法呼叫之後,容器會釋放這個Servlet例項,該例項隨後會被Java的垃圾收集器所回收

通過配置改變Servlet例項化時機

@WebServlet(rulPatterns = "/demo",loadOnStartup = 1)
// 1 負整數:第一次被訪問時建立Servlet物件
// 2 0或正整數:伺服器啟動時建立Servlet物件,數字越小優先順序越高
public class ServletDemo1 implements Servlet{

}

Servlet 快速入門


  1. 匯入座標
<dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  1. 建立一個Java類實現servlet介面
package com.itheima.web;

import javax.servlet.*;
import java.io.IOException;

@WebServlet("/demo1") /*3.配置訪問路徑*/
public class ServletDemo1 implements Servlet{
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
	System.out.println("Hallo Servlet~");
    }
}
  1. 在原本的訪問地址後面加上剛剛配置的路徑

檢視控制檯會發現執行了剛剛我們寫在java類中的service方法

Sevlet 方法介紹


  • 初始化方法,在Servlet被建立時執行,只執行一次
void init(ServletConfig config)
  • 提供服務方法,每次Servlet被訪問,都會呼叫該方法
void service(ServletRequset req,ServletResponse res)
  • 銷燬方法,當Servlet被銷燬時,呼叫該方法。在記憶體釋放或伺服器關閉時銷燬Servlet
void destroy()
  • 獲取ServletConfig物件
ServletConfig getServletConflg()
  • 獲取Servlet資訊
String getServletInfo()

Servlet 體系結構


package com.itheima.web;

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;

@WebServlet("/demo1")
public class ServletDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

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

總結:

  • HttpServlet 使用步驟
  1. 繼承HttpServlet
  2. 重寫doGet和doPost方法
  • HttpServlet 原理
    獲取請求方法,並根據不同的請求方式,呼叫不同的doXxx方法

Servlet urlPatter配置


  • Servlet 要想被訪問,必須配置其訪問路徑(urlPattern)

一個Servlet,可以配置多個 urlPattern

WebServlet(urlPatterns={"/demo1","/demo2"})

urlPattern 配置規則

① 精確匹配:

@WebServlet("/user/select") //配置路徑
// 訪問路徑:localhost:8080/web-demo/user/select

② 目錄匹配:

@WebServlet("/user/*") //配置路徑
// 訪問路徑:localhost:8080/web-demo/user/aaa
// 訪問路徑:localhost:8080/web-demo/user/bbb

精確匹配的優先順序比目錄匹配是要高的

③ 匹配名匹配:

@WebServlet("*.do*") //配置路徑
// 訪問路徑:localhost:8080/web-demo/aaa.do
// 訪問路徑:localhost:8080/web-demo/bbb.do

注意:匹配名匹配的配置路徑中不得以/開頭,否則就會報錯

④ 任意匹配:

@WebServlet("/") //配置路徑
@WebServlet("/*") //配置路徑
// 訪問路徑:localhost:8080/web-demo/hehe
// 訪問路徑:localhost:8080/web-demo/haha
  • / 與 /*的區別:
    • 當我們的專案中的Servlet 配置了 "/",會覆蓋掉tomcat中的DefaultServlet,當其他的 url-pattern都匹配不上時都會走著個Servlet

    • 當我們專案中配置了"/*",意味著匹配任意訪問路徑

基本不用:因為很危險

XML 配置方式編寫 Servlet


  • Servlet 從3.0版本後開始支援使用註解配置,3.0版本前只支援 XML 配置檔案的配置方式

  • 步驟:

    • 1.編寫Servlet類
    • 2.在web.xml中配置該Servlet
<servlet>
    <servlet-name>demo5<servlet-name>
    <servlet-class>com.itheima.web.servlet.ServletDemo5<servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>demo5</servlet-name>
    <url-pattern>/demo5</url-pattern>
</servlet-mapping>

這是舊版的配置方式瞭解就好

Request(請求) &Response(響應)



Web瀏覽器傳送HTTP請求到Web伺服器,而請求資料就是一些字串,字串會被Tomcat解析,解析完後其實tomcat就會將資料存在request物件中

requset物件儲存了請求解析後的資料

在處理完請求的資料後,我們需要對使用者進行響應,然後瀏覽器接受將資料展示在頁面上。Tomcat會發送一些響應的字串,而這些響應的字串就在 respons中

response物件儲存了響應時的資料

於是將來我們就可以拿來做一些事情:

  • Requset:獲取請求資料
  • Response:設定響應資料

Requset(請求)

Requset 繼承體系


  1. Tomcat需要解析請求資料,封裝為request物件,並且建立request物件傳遞到service方法中
  2. 使用request物件,查閱javaEE API文件的HttpServletRequest介面

Requset 獲取請求資料


請求資料分為三部分:

  1. 請求行:GET/request-demo/req1?username=zhangsan HTTP/1.1

    • String getMethod(); 獲取請求方式:GET
    • String getContextPath(); 獲取虛擬目錄(專案訪問路徑):/request-demo
    • StringBuffer getRequestURL(); 獲取URL(統一資源定位符):http://localhost:8080/request-demo/req1
    • String getRequestURL(); 獲取URL(統一資源識別符號):/request-demo/req1
    • String getQueryString(); 獲取請求引數(GET方式):username=zhangsan&password=123
  2. 請求頭:User-Agent:Mozilla/5.0 Chorme/91.0.4472.106

    • String getHeader(String name):根據請求頭名稱,獲取值
  3. 請求體:username=superbaby&password=123

    • ServletinputStream getinputStream():獲取位元組輸入流
    • BufferedReader getReader():獲取字元輸入流

Requset 通用獲取請求引數的方式

當HTTP請求傳送過來時,系統會自動幫我們將資料截斷,放入一個鍵值隊Map資料裡,且對於相同鍵的資料不會覆蓋,而是以陣列的形式儲存,所以這個Map 定義為 Map<String,String[]>我們可以通過這個Map獲取到我們想要的資料

  • Map<String,string[]> getParameterMap():獲取所以引數Map集合
  • String[] getparameterValues(String name):根據名稱獲取引數值(陣列)
  • String getParameter(String name):根據名稱獲取引數值(單個值)

Requset 中文亂碼解決方案

  • 請求引數存在中文資料,則會亂碼

  • 亂碼原因:編解碼字符集不一致

  • URL編碼
    1.將字串按照編碼方式轉為二進位制
    2.每個字元轉為2個16進位制數並在前面加上%

  • 解決方案:

    • POST:設定輸入流的編碼
    req.setCharacterEncoding("UTF-8");
    
    • 通用方式(GET/POST):先解碼,再編碼
    new String(username.getBytes("ISO-8859-1"),"UTF-8");
    
  • URL編碼實現方式:

    • 編碼
    URLEncoder.encode(str,"utf-8");
    
    • 解碼
    URLDecoedr.decode(s,"ISO-8859-1");
    

Tomcat8 之後其實就已經解決了中文亂碼問題

Request 請求轉發

說的是一種在伺服器內部的資源跳轉方式

  • 實現方式:
req.getRequestDispatcher("資源B路徑").forward(req,resp);
  • 請求轉發資源間共享資料:使用Request物件

    • void setAttribute(String name,Object o):儲存資料到 request 域中
    • Object getAttribute(String name):根據 key,獲取值
    • void removeAttribute(String name):根據key,刪除該鍵值對
  • 請求轉發特點:

    • 瀏覽器資源欄路徑不發生變化
    • 只能轉發到當前伺服器的內部資源
    • 一次請求,可以在轉發的資源間使用request共享資料

Response(響應)

Response 設定響應資料功能

  • 響應資料分為3部分:

    • 響應行:HTTP/1.1 200 OK
    void setStatus(int sc); //設定響應狀態碼
    
    • 響應頭:Content-Type:text/html
    void setHeader(String name,String value); //設定響應頭鍵值對
    
    • 響應體:<html><head><body></body></head></html>
    PrintWriter getWriter(); //獲取字元輸出流
    ServletOutputStream getOutputStream(); //獲取位元組輸出流
    

Response 重定向

說的是一種資源調整方式:當伺服器處理不了瀏覽器的請求,但其他資源可以處理請求時,會返回狀態碼以及其他資源的響應頭給瀏覽器。瀏覽器拿到狀態碼和資源路徑就會將請求傳送給指定資源處理

實現方式:

// 1.設定響應狀態碼
resp.setStatus(302);
// 2.設定響應頭
resp.setHeader("location","資源B的路徑");

// 簡化寫法
resp.sendRedirect("資源B的路徑");

會化跟蹤技術


  • 會話:使用者開啟瀏覽器,訪問web瀏覽器的資源,會話建立,直到有一方斷開連線,會話結束,在一次會話中可以包含多次請求和響應

  • 會話跟蹤:一種維護瀏覽器狀態的方法,伺服器需要識別多次請求是否來自於同一瀏覽器,以便在同一次會話的多個請求間共享資料

  • Http協議是無狀態的,每次瀏覽器向伺服器請求時,伺服器都會將該請求視為新的請求,因此我們需要會話跟蹤技術來實現會話內資料共享

  • 實現方式:
    1.客戶端會話跟蹤技術:Cookie
    2.服務端會話跟蹤技術:Session


客戶端會話技術,將資料儲存到客戶端,以後每次請求都攜帶Cookie資料進行訪問

  • 傳送Cookie
// 1. 建立Cookie物件,設定資料
Cookie cookie = new Cookle("key","value");

// 2. 傳送Cookie到客戶端:使用response物件
response.addCookle(cookie);
  • 獲取Cookie
// 1. 獲取客戶端攜帶的所有Cookie,使用request物件
Cookie[] cookies=request.getCookies();

// 2. 遍歷陣列,獲取每個Cookie物件:for
// 3. 使用Cookie物件方法獲取資料
cookie.getName();
cookie.getValue();

Cookie 的實現是基於HTTP協議的

  • 響應頭:set-cookie
  • 響應體:cookie
  • Cookie 存活時間
    • 預設情況下,Cookie 儲存在瀏覽器記憶體中,當然瀏覽器關閉,記憶體釋放,則Cookie銷燬
    • setMaxAge(int seconds):設定Cookie存活時間
      1.正數:將 Cookie寫入瀏覽器所在電腦的硬碟,持久化儲存,到時間自動刪除
      2.負數:預設值,Cookie在當前瀏覽器記憶體中,當瀏覽器關閉,則Cookie被銷燬
      3.零:刪除對應 Cookie

Cookie 不能直接儲存中文,如果需要儲存,則需要進行轉碼:URL 轉碼

String value="張三";
//URL編碼
value = URLEncoder.encode(value,"UTF-8");

Cookie cookie = new Cookie("username",value);

//URL解碼
value = URLDecoder.decode(value,"UTF-8");

Session


服務端會話跟蹤技術,將資料儲存到服務端,這其實是一種比較不安全的方式。因為資料往返頻繁有被擷取攔截的風險。

JavaEE 提供 HttpSession介面,來實現一次會話的多次請求間資料的共享功能

//1.獲取Session物件
HttpSession session =request.getSession();
//2.Session物件功能:
void setAttribute(String name,Object o);//儲存資料到 session 域中
Object getAttribute(String name);//根據 key,獲取值
void removeAttribute(String name);//根據 key,刪除該鍵值對

Seesion 原理

Seesion 的實現是基於cookie

Seesion 使用細節