日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

重学JavaWeb —— Servlet,简单全面一发入魂

發布時間:2024/1/8 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重学JavaWeb —— Servlet,简单全面一发入魂 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • Servlet
    • 概述
    • 基本使用
    • 兩個重要對象
    • 請求轉發
    • 會話技術
      • Cookie
      • Session
      • 對比小結
    • 其它相關對象
      • ServletContext
      • ServletConfig
    • 過濾器
      • 概述
      • 使用
      • 配置參數
      • 注意
      • 應用場景
    • 監聽器

Servlet

概述

狹義地說,Servlet就是定義在JavaEE規范中的一個接口,javax.servlet.Servlet,參見JavaEE的API文檔

package javax.servlet;import java.io.IOException;public interface Servlet {void init(ServletConfig config) throws ServletException;ServletConfig getServletConfig();void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;String getServletInfo();void destroy(); }

Servlet接口定義的是一套處理網絡請求的規范。一個實現了Servlet接口的類(下面簡稱Servlet類),表明它是一個可以處理網絡請求的類。Servlet類需要實現Servlet接口中的5個方法,其中最主要的3個是:

  • init()
  • destroy()
  • service()

它們分別定義了,一個Servlet類,

  • 在初始化時需要干什么
  • 在銷毀時需要干什么
  • 在每次接收到請求時,要作何處理

實現了Servlet接口的類,就能處理網絡請求了嗎?

顯然沒這么簡單。

我們只知道,一個Servlet類在處理請求時,執行的是它的service()方法,但service()方法是由誰調用的,方法入參中的request和response對象又是怎么來的,這顯然不是Servlet類自己做的,而且Servlet中也沒有諸如監聽網絡端口等和網絡請求有關的操作。

所以,Servlet類要處理網絡請求,還需要依賴一個東西——Servlet容器。這個容器要負責監聽網絡端口,封裝網絡請求數據,管理眾多的Servlet類,進行請求的調度分發,返回響應數據等。最典型的Servlet容器就是Tomcat。

Servlet容器和Servlet類是如何協作處理一個HTTP請求的?

1. Servlet容器監聽網絡端口,接收到HTTP請求 2. 根據請求的url, 查找對應的Servlet類 3. 若對應的Servlet類不在容器中,則檢索并創建該Servlet實例,并初始化(調Servlet的init方法) 4. 容器構建該次請求的request和response對象, 調用對應Servlet的service方法,傳入這2個參數 5. Servlet類執行service方法, 對請求進行處理,并設置響應數據到response對象中 6. 容器取出response對象中的響應數據,封裝好HTTP響應報文,返回給客戶端

我們可以看到,在HTTP請求的整個處理過程中,干活兒最多的,其實是Servlet容器。Servlet容器把處理請求的整個流程,框架,都搭好了,只是在中間留了很小的一部分空間,給Servlet類。所以,Servlet類負責的,其實只是整個流程中很小的一環。

不過,這也是因為,在處理網絡請求時,諸如監聽網絡端口,封裝請求數據,響應請求數據,這些操作,都是共性的。也就是說,所有的處理網絡請求的程序,都必須有這些相同的步驟,而唯一不同的地方,只是在于對請求的業務處理。于是就把這些相同的地方抽取出來,做成了Servlet容器,不同的地方,交給各個Servlet類。這也體現了編程領域中,抽取共性,封裝變化的設計理念。試想,若沒有Servlet容器,則每開發一個網絡程序,都要自己完整實現一套處理網絡請求和響應的流程,那開發的門檻就太高了,開發量也很大,并且都是重復的工作。

廣義地講,Servlet是一套規范體系,不僅僅是javax.servlet.Servlet接口,而是javax.servlet包下定義的全部規范。主要包括了JavaWeb三大組件,Servlet,Filter,Listener,以及其他一系列相關的接口。

下面,對Servlet的規范體系進行非常簡要的歸納總結。

基本使用

構建一個最基本的web程序,只需要有Servlet類(實現了javax.servlet.Servlet接口的類)即可

  • 在IDEA中新建一個JavaWeb項目
  • 導入servlet-api.jar依賴
  • 創建一個實現javax.servlet.Servlet接口的類
  • 對該Servlet類進行配置(主要配置該Servlet對應的url),有2種配置方法
  • 在web.xml中配置
  • 使用注解@WebServlet進行配置
  • 配置并部署Tomcat
  • Servlet配置參數

    • urlPattern:該Servlet處理的url
    • initParams:name - value,鍵值對形式,可通過ServletConfig獲取
    • loadOnStartup:值為一個整數。若是0或正數,容器啟動時就立刻加載Servlet,數字越小越先加載。若是負數,容器可自由選擇何時加載(一般會懶加載,即用到該Servlet時才加載)

    Servlet生命周期

    • init():容器加載Servlet實例,進行初始化時,調用執行Servlet的init()
    • destroy():容器銷毀Servlet實例時,調用執行Servlet的destroy()
    • service():容器將請求交由一個Servlet處理時,調用執行Servlet的service()

    javax.servlet.Servlet只是最原始的接口規范,javax.servlet包下還定義了一些基本的抽象子類,如javax.servlet.GenericServlet,javax.servlet.http.HttpServlet,類的層次結構圖如下

    由于構建的web應用幾乎都是基于HTTP協議的,我們創建一個Servlet時,通常只需要繼承HttpServlet,由于最常用的HTTP方法是GET和POST,通常我們只需要重寫doGet和doPost方法即可。本文下面的內容,默認基于HTTP協議。

    兩個重要對象

    在Servlet處理請求時,有兩個最重要的對象——request和response。前者封裝了HTTP請求數據,后者封裝了HTTP響應數據。這兩個對象分別是HttpServletRequest和HttpServletResponse類的實例。對于request,主要的操作是get,因為需要從其中獲取請求數據,對于response,主要的操作是set,因為需要往里面設置響應數據

    它們中的常用方法下面列舉一二

    HttpServletRequest:

    • getRequestURL:獲取請求URL
    • getMethod:獲取請求方法
    • getParameter(String s):獲取請求參數
    • getHeader(String s):獲取請求頭
    • getInputStream() / getReader():獲取請求體

    HttpServletResponse

    • addHeader(String k, String v):添加響應頭
    • getOutputStream() / getWriter():獲取輸出流,以便往響應體里寫入數據
    • setStatus(int sc):設置HTTP響應狀態碼
    • sendRedirect(String s):設置重定向

    請求轉發

    當一個請求,在一個Servlet中不能完成處理,需要進行請求轉發時,有2種轉發方式

    • 服務端轉發

      通過request.getRequestDispatcher("/xx").forward(request,response)

      轉發到能處理/xx這種url的Servlet。發生在服務端內部,本質相當于方法調用,只能轉發到服務端內部的資源。

    • 客戶端轉發

      通過設置HTTP狀態碼為3xx(一般設置為302),并在HTTP響應頭添加Location指定重定向的url地址,瀏覽器收到3xx的HTTP響應,會自動重定向到Location頭部指定的url地址。實際發生了2次HTTP請求,可跳轉到任意url。可以調用response對象的sendRedirect方法完成。

    會話技術

    眾所周知,HTTP是無狀態的協議,即每組HTTP請求/響應,都是互相獨立的,HTTP協議本身不具備記憶能力。但有的場景需要在多次HTTP請求之間維護一些狀態信息,此時,就輪到會話技術登場了。根據狀態信息是保存在服務端,還是客戶端,會話技術分為了2種:Cookie和Session

    Cookie

    cookie是HTTP協議的擴展標準。本質就是一個簡單的k-v鍵值對。當瀏覽器收到的響應報文中,包含了Set-Cookie頭部時,會將該頭部中的k-v鍵值對,保存在瀏覽器端(默認保存在瀏覽器內存,在瀏覽器關閉后失效),下次再發起請求時,會自動添加Cookie頭部,攜帶先前保存下來的k-v鍵值對。

    在Servlet中,通過response對象來向瀏覽器發送一個cookie,具體操作如下

    Cookie cookie = new Cookie("userId","123"); response.addCookie(cookie);

    HTTP響應報文如下(簡化)

    HTTP/1.1 200 OK Set-Cookie: userId=123

    下次請求時的HTTP請求報文如下(簡化)

    GET / HTTP/1.1 Host: www.baidu.com Cookie: userId=123

    在Servlet中,通過request對象獲取請求中攜帶的cookie,具體操作如下

    Cookie[] cookies = request.getCookies(); // 獲取請求攜帶的全部Cookie for(Cookie c : cookies) {String name = c.getName();String value = c.getValue(); }

    k-v鍵值對,是cookie最基本的信息。除此之外,cookie還可以設置以下屬性

    • domain:設置允許攜帶cookie的域
    • path:設置允許攜帶cookie的資源路徑
    • maxAge:設置cookie最大存活時間,單位秒(若不設置,cookie默認在瀏覽器關閉時失效)
    • httpOnly:設為true,可避免JS腳本竊取cookie
    • secure:設為true,則只有使用HTTPS等安全的協議時,才攜帶Cookie

    另:Cookie,翻譯過來是小餅干的意思,這樣的命名也意味著,它只能保存少量的信息(簡單的k-v鍵值對),且瀏覽器一般對cookie的大小,數量等都有所限制,而由于將信息保存在了瀏覽器端,也就意味著信息容易遭到竊取或篡改,不夠安全。

    于是,將信息保存在服務端的Session技術,輪到它登場了。

    Session

    session是依賴于cookie的。它的大概原理是:一次請求到來,服務器端在處理請求時,生成一個session對象(保存在服務端的內存中),以及一個對應的sessionId。當服務端處理完畢,返回響應時,在HTTP響應報文添加這樣的頭部Set-Cookie:JSESSIONID=123。瀏覽器端保存下這個name為JSESSIONID的cookie,在下次請求時,攜帶這個cookie。服務端根據JSESSIONID,找到自己內存中對應的session對象,這樣,即可在多個HTTP請求之間共享數據。在tomcat的配置中,session的默認有效時間為30分鐘。session對象中也可以添加k-v鍵值對,但不僅僅是字符串,還可以是任意的Object對象,這就比cookie能攜帶的信息要大得多了。且session對象的大小,理論上只會受到服務器內存大小的限制。且由于存在服務端,安全性相對就高了許多。

    在Servlet中,一個session對象是一個HttpSession類的實例,通過request對象來生成或獲取一個session對象,如下

    // 1. 若此次請求中沒有攜帶name為JSESSIONID的cookie, 則getSession會新創建一個session對象 // 并把對應的id添加到響應頭 // 2. 若此次請求中有攜帶name為JSESSIONID的cookie, 則getSession會根據這個id的值 // 從內存中找到該id對應的session對象 HttpSession session = request.getSession();

    session對象中常用的方法:

    • setAttribute(String s, Object o):往session對象中添加一組鍵值對數據
    • getAttribue(String s)
    • setMaxInactiveInterval(int i):設置session對象最大有效時長,單位秒。(負數表示永不失效)
    • invalidate():使該session對象失效

    另:

  • 由于session對象是保存在服務端內存,當服務器關閉時,內存中的數據就沒了。所以session還有鈍化和活化處理。這種處理在tomcat中是默認開啟的。當session未失效且服務器正常關閉時,內存中的session對象,會被序列化,存儲到磁盤,文件名為SESSIONS.ser(這叫鈍化)。下次服務器啟動時,會自動讀取并刪除這個SESSIONS.ser,將session對象的數據從磁盤加載到內存(這叫活化)。由于session對象中可以保存任意Object對象,若要成功支持session鈍化活化,則保存在session中的數據,都需要可序列化(實現Serializable接口)
  • 由于name為JSESSIONID的cookie,是自動設置到響應中的,所以這個cookie遵循默認的配置,在瀏覽器關閉后就會失效。若需要在瀏覽器關閉后不失效,則手動設置一個name為JSESSIONID的cookie,并設置其maxAge
  • 對比小結

    CookieSession
    數據存儲位置客戶端(瀏覽器端)服務端
    限制少量數據,簡單的字符串鍵值對可存很多數據,任意Object類型
    有效性默認在瀏覽器關閉后失效默認有效時長30分鐘(tomcat中)
    安全性

    其它相關對象

    上面的會話技術,是在同一用戶的多次請求之間進行數據共享。若要在整個web應用中共享數據,則可以通過ServletContext對象實現。

    ServletContext

    一個Web應用,對應一個ServletContext對象,根據命名也能看出,這是整個web應用的上下文環境。這個對象中的常用方法,下面列舉一二

    • setAttribue(String s, Object o):添加一組鍵值對數據
    • getAttribe(String s)
    • getInitParameter(String s):獲取web應用的全局初始化參數(web.xml中的<context-param>標簽)

    小應用:統計網站訪問量。每收到一個請求,就對ServletContext中的一個屬性進行累加操作

    ServletConfig

    ServletConfig對象用于向Servlet傳遞一些參數,以便在Servlet初始化時使用。它主要包含了如下方法

    • getServletContext():獲取web應用全局上下文
    • getInitParameter(String s):獲取Servlet初始化參數(web.xml中的<init-param>標簽,也可通過@WebInitParam注解進行設置)

    過濾器

    概述

    Servlet,Filter,Listener并稱JavaWeb三大組件。

    其中的Filter,指的就是javax.servlet.Filter接口。它可以在請求被處理(請求的資源可以是Servlet,也可以是HTML等靜態資源)的之前之后,進行一些額外的操作。

    它的工作流程如下圖所示

    過濾器可以配置不止一個,當有多個過濾器時,它們就形成了一個,如下圖

    與Servlet的生命周期類似,Filter也有如下3個方法

    • init():過濾器被創建時,該方法被調用
    • destroy():過濾器被銷毀時,該方法被調用
    • doFilter():過濾器對請求/響應進行過濾處理時,該方法被調用

    Filter相關的一共有3個類

    • javax.servlet.Filter:核心接口
    • javax.servlet.FilterConfig:過濾器配置接口,可以通過該接口給過濾器傳遞一些初始化參數
    • javax.servlet.FilterChain:過濾器鏈接口

    使用

    創建一個過濾器的步驟如下

  • 新建一個類,實現javax.servlet.Filter接口

  • 重寫init(),destroy(),doFilter()方法

  • 配置過濾器

    • xml方式:web.xml

      <filter><filter-name>myFilter</filter-name><filter-class>filter.LogFilter</filter-class></filter><filter-mapping><filter-name>myFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
    • 注解方式:@WebFilter

      @WebFilter(servletNames = {"ElServlet"}) public class LogFilter implements Filter {// 代碼略 }
  • 配置參數

    只需要配置過濾器在何時起作用即可,可以指定其urlPattern,對滿足某一格式的url進行攔截;也可以指定servletNames,對指定的Servlet進行攔截(二者選其一即可)

    • urlPattern

    • servletNames

    如下

    @WebFilter(servletNames = {"ElServlet"}) public class LogFilter implements Filter {// 代碼略 } @WebFilter(urlPatterns = "/*") public class LogFilter implements Filter {// 代碼略 }

    注意

    由于攔截某一請求的過濾器,可能有多個,這就形成一條過濾器鏈,當一個過濾器處理完畢后,應該調用鏈上的下一個過濾器,或者直接進入到資源處理(當該過濾器是鏈中的最后一個時)。

    所以,在某個過濾器的doFilter()方法中,完成了處理后,應該調用FilterChain的doFilter()方法,將請求/響應在過濾器鏈上傳遞下去(若不調用,則請求不會到達最終的web資源)。在調用FilterChain的doFilter()方法之前,請求還未被處理,在其后,請求已完成處理。這就對應了先前說的,Filter可以在請求被處理之前之后,進行一些額外的操作。

    @WebFilter(urlPatterns = "/*") public class LogFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println("before servlet");chain.doFilter(req, resp);System.out.println("after servlet");}public void init(FilterConfig config) throws ServletException {} }

    應用場景

    Filter的常見應用場景列舉如下

    • 進行日志記錄(記錄被調用的接口,請求參數,以便進行問題排查,數據統計等工作)

    • 統一設置編碼格式(如處理中文亂碼問題等)

    • 過濾敏感詞匯

    • 數據壓縮

    • 數據加密

    • 身份認證

    監聽器

    JavaWeb三大組件的最后一個,Listener。

    用于監聽一些重要事件的發生。以便在事件發生時,能夠做一些額外操作。

    Servlet API中針對如下對象,提供了對應的監聽器接口

    • ServletContext對象

      ServletContextListener,ServletContextAttributeListener

    • HttpSession對象

      HttpSessionListener,HttpSessionAttributeListener,HttpSessionIdListener

    • ServletRequest對象

      ServletRequestListener,ServletRequestAttributeListener

    比如,可以監聽HttpSession對象的創建和銷毀,來實現一個網站在線人數統計的功能(若用戶請求的是一個JSP頁面,JSP頁面在默認情況下,會為每一個新的請求創建一個session對象,這是下面進行人數統計的基礎,這個默認行為,可以通過JSP指令<%@ page session="false" %>來取消)

    import javax.servlet.ServletContext; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import java.time.LocalDateTime;/*** 統計網線在線人數* Session創建, 就全局人數+1, Session銷毀, 就全局人數-1* **/ @WebListener // 加上注解后,就不必在web.xml中進行配置 public class OnLineCounter implements HttpSessionListener {private final String COUNT = "count";@Overridepublic void sessionCreated(HttpSessionEvent httpSessionEvent) {HttpSession session = httpSessionEvent.getSession();System.out.println(LocalDateTime.now() + ", 新來了一個人, id = " + session.getId());ServletContext servletContext = session.getServletContext();Object o = servletContext.getAttribute(COUNT);int count = o == null ? 0 : (int) o;servletContext.setAttribute(COUNT, ++count);}@Overridepublic void sessionDestroyed(HttpSessionEvent httpSessionEvent) {HttpSession session = httpSessionEvent.getSession();System.out.println(LocalDateTime.now() + ", 走了一個人, id = " + session.getId());ServletContext servletContext = session.getServletContext();int count = (int) servletContext.getAttribute(COUNT);servletContext.setAttribute(COUNT, --count);} }

    總結

    以上是生活随笔為你收集整理的重学JavaWeb —— Servlet,简单全面一发入魂的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。