【JavaWeb】一文Servlet全解:继承关系、生命周期、容器和请求转发与重定向等
文章目錄
- 一、Servlet 概述
- 二、Servlet HelloWorld
- 三、Servlet 繼承關系
- 四、Servlet 生命周期
- 五、ServletConfig 和 ServletContext
- 六、請求轉發與重定向
- 七、獲取請求參數
一、Servlet 概述
1、Servlet名字
Servlet = Server + applet
Server:服務器
applet:小程序
Servlet:服務器端的小程序
2、Servlet在Web應用中的作用
①生活中的例子
②對應Web應用
③具體細節
④Servlet扮演角色
在整個Web應用中,Servlet主要負責處理請求、協調調度功能。我們可以把Servlet稱為Web應用中的『控制器』
二、Servlet HelloWorld
1、HelloWorld分析
①目標
在頁面上點擊超鏈接,由Servlet處理這個請求,并返回一個響應字符串:Hello,I am Servlet! 。
②思路
2、具體操作
①創建動態Web Module
《踩坑+排雷新版IDEA2021.1創建配置Javaweb項目并部署在Tomcat容器》
②創建前端頁面超鏈接
begin.html 的代碼如下:
③創建HelloServlet的Java類
package com.yeman.Servlets;import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import java.io.IOException; import java.io.PrintWriter;/*** @Author: Yeman* @Date: 2022-02-11-18:15* @Description:*/ public class Hello extends HttpServlet {@Overridepublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {System.out.println("執行了Hello這個Servlet!");// 返回響應字符串// 1、獲取能夠返回響應數據的字符流對象PrintWriter writer = res.getWriter();// 2、向字符流對象寫入數據writer.write("Hello,I am Servlet!");} }④配置Hello Servlet
配置文件位置:WEB-INF/web.xml
⑤測試
⑥小結
需求:在瀏覽器上點超鏈接能夠訪問Java程序。
3、梳理概念
①原生Tomcat
②IDEA中的Tomcat實例
③IDEA中的Web工程
④根據Web工程生成的war包
⑤Web工程中的資源
[1]靜態資源
- HTML文件
- CSS文件
- JavaScript文件
- 圖片文件
[2]動態資源
- Servlet
⑥訪問資源的地址
[1]靜態資源
/Web應用名稱/靜態資源本身的路徑
[2]動態資源
/Web應用名稱/虛擬路徑
⑦Web應用名稱
⑧總體的邏輯結構
三、Servlet 繼承關系
1、繼承關系
javax.servlet.Servlet接口----->javax.servlet.GenericServlet抽象類
----->javax.servlet.http.HttpServlet抽象子類
2、相關方法
①javax.servlet.Servlet接口:
- void init(config) - 初始化方法
- void service(request,response) - 服務方法
- void destory() - 銷毀方法
②javax.servlet.GenericServlet抽象類:
- void service(request,response) - 仍然是抽象的
③javax.servlet.http.HttpServlet 抽象子類:
- void service(request,response) - 不是抽象的
String method = req.getMethod(); 獲取請求的方式
各種if判斷,根據請求方式不同,決定去調用不同的do方法:
在HttpServlet這個抽象類中,do方法都差不多:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_get_not_supported");if (protocol.endsWith("1.1")) {resp.sendError(405, msg);} else {resp.sendError(400, msg);} }3、小結
①繼承關系: HttpServlet -> GenericServlet -> Servlet
②Servlet中的核心方法:init(),service(),destroy()
③服務方法: 當有請求過來時,service方法會自動響應(其實是tomcat容器調用的)。
④在HttpServlet中會分析請求的方式:到底是get、post、head還是delete等,然后再決定調用的是哪個do開頭的方法。
⑤在HttpServlet中的do方法默認都是405的實現風格,需要子類去實現對應的方法,否則默認會報405錯誤。因此,我們在新建Servlet時,需要考慮請求方法,從而決定重寫哪個do方法。
四、Servlet 生命周期
1、生命周期
從出生到死亡的過程就是生命周期。對應Servlet中的三個方法init(),service(),destroy()。
默認情況下:第一次接收請求時,這個Servlet會進行實例化(調用構造方法)、初始化(調用init())、然后服務(調用service())。從第二次請求開始,每一次都是服務。當容器關閉時,其中的所有的servlet實例會被銷毀,調用銷毀方法。
Servlet實例Tomcat只會創建一個,所有的請求都是這個實例去響應。默認情況下,第一次請求時,Tomcat才會去實例化,初始化,然后再服務。這樣的好處是什么是可以提高系統的啟動速度,這樣的缺點是什么是第一次請求耗時較長。因此得出結論: 如果需要提高系統的啟動速度,當前默認情況即可,如果需要提高響應速度,就應該設置Servlet的初始化時機。
2、初始化時機
我們可以通過<load-on-startup>來設置servlet啟動的先后順序,數字越小,啟動越靠前,最小值0。可以讓其在系統啟動時便實例化初始化,提高后期響應速度。
修改web.xml中Servlet的配置:
<!-- 配置Servlet本身 --> <servlet><!-- 全類名太長,給Servlet設置一個簡短名稱 --><servlet-name>HelloServlet</servlet-name><!-- 配置Servlet的全類名 --><servlet-class>com.yeman.servlet.HelloServlet</servlet-class><!-- 配置Servlet啟動順序 --><load-on-startup>1</load-on-startup> </servlet>3、Servlet 容器
①容器
在開發使用的各種技術中,經常會有很多對象會放在容器中。
②容器提供的功能
容器會管理內部對象的整個生命周期。對象在容器中才能夠正常的工作,得到來自容器的全方位的支持。
- 創建對象
- 初始化
- 工作
- 清理
③容器本身也是對象
特點1:往往是非常大的對象
特點2:通常的單例的
④典型Servlet容器產品舉例
Tomcat、jetty、jboss、Weblogic、WebSphere、glassfish
⑤Servlet在容器中是:單例的、線程不安全的。
單例:所有的請求都是同一個實例去響應
線程不安全:一個線程需要根據這個實例中的某個成員變量值去做邏輯判斷,但是在中間某個時機,另一個線程改變了這個成員變量的值,從而導致第一個線程的執行路徑發生了變化。
注意:盡量的不要在servlet中定義成員變量,如果不得不定義成員變量,那么不要去:①修改成員變量的值 ②根據成員變量的值做一些邏輯判斷。
4、小結
五、ServletConfig 和 ServletContext
1、ServletConfig 接口
①接口概覽
②接口方法
③初始化參數舉例
<!-- 配置Servlet本身 --> <servlet><!-- 全類名太長,給Servlet設置一個簡短名稱 --><servlet-name>HelloServlet</servlet-name><!-- 配置Servlet的全類名 --><servlet-class>com.yeman.servlet.HelloServlet</servlet-class><!-- 配置初始化參數 --><init-param><param-name>goodMan</param-name><param-value>me</param-value></init-param><!-- 配置Servlet啟動順序 --><load-on-startup>1</load-on-startup> </servlet>④體驗
public class HelloServlet implements Servlet {// 聲明一個成員變量,用來接收init()方法傳入的servletConfig對象private ServletConfig servletConfig;public HelloServlet(){System.out.println("HelloServlet對象創建!");}@Overridepublic void init(ServletConfig servletConfig) throws ServletException {System.out.println("HelloServlet對象初始化");// 將Tomcat調用init()方法時傳入的servletConfig對象賦值給成員變量this.servletConfig = servletConfig;}@Overridepublic ServletConfig getServletConfig() {// 返回成員變量servletConfig,方便使用return this.servletConfig;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {// 控制臺打印,證明這個方法被調用了System.out.println("我是HelloServlet,我執行了!");// 返回響應字符串// 1、獲取能夠返回響應數據的字符流對象PrintWriter writer = servletResponse.getWriter();// 2、向字符流對象寫入數據writer.write("Hello,I am Servlet!");// =============分割線===============// 測試ServletConfig對象的使用// 1.獲取ServletConfig對象:在init()方法中完成System.out.println("servletConfig = " + servletConfig.getClass().getName());// 2.通過servletConfig對象獲取ServletContext對象ServletContext servletContext = this.servletConfig.getServletContext();System.out.println("servletContext = " + servletContext.getClass().getName());// 3.通過servletConfig對象獲取初始化參數Enumeration<String> enumeration = this.servletConfig.getInitParameterNames();while (enumeration.hasMoreElements()) {String name = enumeration.nextElement();System.out.println("name = " + name);String value = this.servletConfig.getInitParameter(name);System.out.println("value = " + value);}}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {System.out.println("HelloServlet對象即將銷毀,現在執行清理操作");} }⑤Servlet標準和JDBC標準對比:
廣義Servlet:javax.servlet包下的一系列接口定義的一組Web開發標準。遵循這一套標準,不同的Servlet容器提供了不同的實現。
狹義Servlet:javax.servlet.Servlet接口和它的實現類,也就是實際開發時使用的具體的Servlet。
同樣都體現了面向接口編程的思想,同時也體現了解耦的思想:只要接口不變,下層方法有任何變化,都不會影響上層方法。
2、ServletContext 接口
①簡介
代表整個Web應用,是單例。
典型的功能:
- 獲取某個資源的真實路徑:getRealPath()
- 獲取整個Web應用級別的初始化參數:getInitParameter()
- 作為Web應用范圍的域對象
存入數據:setAttribute()
取出數據:getAttribute(
②體驗
[1]配置Web應用級別的初始化參數
[2]獲取參數
String handsomeMan = servletContext.getInitParameter("handsomeMan"); System.out.println("handsomeMan = " + handsomeMan);六、請求轉發與重定向
1、接力
發一個請求給Servlet,接力棒就傳遞到了Servlet手中。而絕大部分情況下,Servlet不能獨自完成一切,需要把接力棒繼續傳遞下去,此時我們就需要請求的『轉發』或『重定向』。
2、轉發
①本質:轉交
②完整定義:在請求的處理過程中,Servlet完成了自己的任務,需要把請求轉交給下一個Servlet繼續處理。
③代碼
request.getRequestDispatcher("/fruit/apple/red/big.html").forward(request, response);④類比
關鍵:由于轉發操作的核心部分是在服務器端完成的,所以瀏覽器感知不到,整個過程中瀏覽器只發送一次請求。
3、重定向
①本質:一種特殊的響應
②完整定義:在請求的處理過程中,Servlet完成了自己的任務,然后以一個響應的方式告訴瀏覽器:要完成這個任務還需要你另外再訪問下一個資源”。
③代碼
response.sendRedirect("/app/fruit/apple/red/big.html");
關鍵:由于重定向操作的核心部分是在瀏覽器端完成的,所以整個過程中瀏覽器共發送兩次請求。
4、對比
5、應用場景
可以簡單的判斷:能用轉發的先用轉發,如果轉發不行,再使用重定向。
需要通過同一個request對象把數據攜帶到目標資源:只能用轉發。
如果希望前往下一個資源之后,瀏覽器刷新訪問的是第二個資源:只能用重定向。
七、獲取請求參數
1、請求參數的概念
瀏覽器在給服務器發送請求的同時,攜帶的參數數據。
2、瀏覽器發送請求參數的基本形式
- URL地址后面附著的請求參數
/orange/CharacterServlet?username=Tom
- 表單
- Ajax請求
3、服務器對請求參數的封裝
總體上來說,服務器端將請求參數封裝為Map<String, String[]>。
鍵:請求參數的名字
值:請求參數的值組成的數組
4、獲取請求參數的方法
5、測試
①HTML代碼
<!-- 測試請求參數的表單 --> <form action="/orange/ParamServlet" method="post"><!-- 單行文本框 --><!-- input標簽配合type="text"屬性生成單行文本框 --><!-- name屬性定義的是請求參數的名字 --><!-- 如果設置了value屬性,那么這個值就是單行文本框的默認值 -->個性簽名:<input type="text" name="signal" value="單行文本框的默認值" /><br/><!-- 密碼框 --><!-- input標簽配合type="password"屬性生成密碼框 --><!-- 用戶在密碼框中填寫的內容不會被一明文形式顯示 -->密碼:<input type="password" name="secret" /><br/><!-- 單選框 --><!-- input標簽配合type="radio"屬性生成單選框 --><!-- name屬性一致的radio會被瀏覽器識別為同一組單選框,同一組內只能選擇一個 --><!-- 提交表單后,真正發送給服務器的是name屬性和value屬性的值 --><!-- 使用checked="checked"屬性設置默認被選中 -->請選擇你最喜歡的季節:<input type="radio" name="season" value="spring" />春天<input type="radio" name="season" value="summer" checked="checked" />夏天<input type="radio" name="season" value="autumn" />秋天<input type="radio" name="season" value="winter" />冬天<br/><br/>你最喜歡的動物是:<input type="radio" name="animal" value="tiger" />路虎<input type="radio" name="animal" value="horse" checked="checked" />寶馬<input type="radio" name="animal" value="cheetah" />捷豹<br/><!-- 多選框 --><!-- input標簽和type="checkbox"配合生成多選框 --><!-- 多選框被用戶選擇多個并提交表單后會產生『一個名字攜帶多個值』的情況 -->你最喜歡的球隊是:<input type="checkbox" name="team" value="Brazil"/>巴西<input type="checkbox" name="team" value="German" checked="checked"/>德國<input type="checkbox" name="team" value="France"/>法國<input type="checkbox" name="team" value="China" checked="checked"/>中國<input type="checkbox" name="team" value="Italian"/>意大利<br/><!-- 下拉列表 --><!-- 使用select標簽定義下拉列表整體,在select標簽內設置name屬性 -->你最喜歡的運動是:<select name="sport"><!-- 使用option屬性定義下拉列表的列表項 --><!-- 使用option標簽的value屬性設置提交給服務器的值,在option標簽的標簽體中設置給用戶看的值 --><option value="swimming">游泳</option><option value="running">跑步</option><!-- 使用option標簽的selected="selected"屬性設置這個列表項默認被選中 --><option value="shooting" selected="selected">射擊</option><option value="skating">溜冰</option></select><br/><br/><br/><!-- 表單隱藏域 --><!-- input標簽和type="hidden"配合生成表單隱藏域 --><!-- 表單隱藏域在頁面上不會有任何顯示,用來保存要提交到服務器但是又不想讓用戶看到的數據 --><input type="hidden" name="userId" value="234654745" /><!-- 多行文本框 -->自我介紹:<textarea name="desc">多行文本框的默認值</textarea><br/><!-- 普通按鈕 --><button type="button">普通按鈕</button><!-- 重置按鈕 --><button type="reset">重置按鈕</button><!-- 表單提交按鈕 --><button type="submit">提交按鈕</button> </form>②Java代碼
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 獲取包含全部請求參數的MapMap<String, String[]> parameterMap = request.getParameterMap();// 遍歷這個包含全部請求參數的MapSet<String> keySet = parameterMap.keySet();for (String key : keySet) {String[] values = parameterMap.get(key);System.out.println(key + "=" + Arrays.asList(values));}System.out.println("---------------------------");// 根據請求參數名稱獲取指定的請求參數值// getParameter()方法:獲取單選框的請求參數String season = request.getParameter("season");System.out.println("season = " + season);// getParameter()方法:獲取多選框的請求參數// 只能獲取到多個值中的第一個String team = request.getParameter("team");System.out.println("team = " + team);// getParameterValues()方法:取單選框的請求參數String[] seasons = request.getParameterValues("season");System.out.println("Arrays.asList(seasons) = " + Arrays.asList(seasons));// getParameterValues()方法:取多選框的請求參數String[] teams = request.getParameterValues("team");System.out.println("Arrays.asList(teams) = " + Arrays.asList(teams));}總結
以上是生活随笔為你收集整理的【JavaWeb】一文Servlet全解:继承关系、生命周期、容器和请求转发与重定向等的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 有道翻译官实时翻译怎么用(汉典有字的基本
- 下一篇: 安卓时代历史相似指的是哪方面(安卓时代)