【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個階段:
- 載入和例項化:預設情況下,當Servlet第一次被訪問時,由容器建立Servlet物件
- 初始化:在Servlet例項化之後,容器將呼叫Servlet的init()方法初始化這個物件,完成一些如載入配置檔案,建立連線等初始化的工作。該方法只呼叫一次
- 請求處理:每次請求Servlet時,Servlet容器都會呼叫Servlet的service()方法對請求進行處理。
- 服務終止:當需要釋放記憶體或容器關閉時,容器會呼叫Servlet示例的destroy()方法完成資源的釋放。在destroy()方法呼叫之後,容器會釋放這個Servlet例項,該例項隨後會被Java的垃圾收集器所回收
通過配置改變Servlet例項化時機
@WebServlet(rulPatterns = "/demo",loadOnStartup = 1)
// 1 負整數:第一次被訪問時建立Servlet物件
// 2 0或正整數:伺服器啟動時建立Servlet物件,數字越小優先順序越高
public class ServletDemo1 implements Servlet{
}
Servlet 快速入門
- 匯入座標
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
- 建立一個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~");
}
}
- 在原本的訪問地址後面加上剛剛配置的路徑
檢視控制檯會發現執行了剛剛我們寫在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 使用步驟
- 繼承HttpServlet
- 重寫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 繼承體系
- Tomcat需要解析請求資料,封裝為request物件,並且建立request物件傳遞到service方法中
- 使用request物件,查閱javaEE API文件的HttpServletRequest介面
Requset 獲取請求資料
請求資料分為三部分:
-
請求行:
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
-
請求頭:
User-Agent:Mozilla/5.0 Chorme/91.0.4472.106
- String getHeader(String name):根據請求頭名稱,獲取值
-
請求體:
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資料進行訪問
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 原理
Cookie 的實現是基於HTTP協議的
- 響應頭:set-cookie
- 響應體: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