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官網中的最新版本是瀏覽器
固然,咱們能夠經過訪問tomcat
打開官方API網址,在左上部分找到javax.servlet包,在左下部分找到Servlet,以下圖顯示:安全
經過閱讀API,咱們獲得以下信息:服務器
第一:Servlet是一個運行在web服務端的java小程序
第二:它能夠用於接收和響應客戶端的請求
第三:要想實現Servlet功能,能夠實現Servlet接口,繼承GenericServlet或者HttpServlet
第四:每次請求都會執行service方法
第五:Servlet還支持配置
具體請看下圖:
建立一個 WEB 項目
servlet_demo1
建立一個類繼承 GenericServlet
包:com.itheima.servlet
類:ServletDemo1
GenericServlet介紹:implements Servlet,實現了Servlet裏的大部分方法,只有一個service方式是抽象的,咱們只須要實現這個方法便可
重寫 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{
service有兩個參數,servletRequest,servletResponse ,這倆分別是處理請求和響應的,後續會詳細介紹
在 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>
部署並啓動項目:配置項目虛擬路徑:/demo1
經過瀏覽器測試
分析圖:(下圖與實際案例有出入,可是咱們只須要搞清楚Servlet訪問流程便可)
咱們經過瀏覽器發送請求,請求首先到達Tomcat服務器
由服務器解析請求URL,而後在部署的應用列表中找到咱們的應用
接下來,在咱們的應用中找應用裏的web.xml配置文件
在web.xml中找到Servlet的配置
找到後執行service方法,最後由ServletDemo1響應客戶瀏覽器
整個過程以下圖所示:
一句話總結執行過程:
瀏覽器——>Tomcat服務器——>咱們的應用——>應用中的web.xml——>Servlet——>響應瀏覽器
關係視圖以下:
Servlet,GenericServlet,HTTPServlet,他們都有service方法
service方法都有倆參數,ServletRequest,ServletResponse
HTTPServlet的參數是HttpServletRequest,HttpServletResponse,他們分別繼承自ServletRequest,ServletResponse
這倆參數都是接口,分別處理請求,響應
ServletConfig,處理配置
ServletContext,處理多個Servlet之間信息共享
第一種 實現 Servlet 接口,實現全部的抽象方法。該方式支持最大程度的自定義。
第二種 繼承 GenericServlet 抽象類,必須重寫 service 方法,其餘方法可選擇重寫。該方式讓咱們開發 Servlet 變得簡單。可是這種方式和 HTTP 協議無關。
第三種 繼承 HttpServlet 抽象類,須要重寫 doGet 和 doPost 方法。該方式表示請求和響應都須要和 HTTP 協議相關。
上述前兩種都給你們演示過了,咱們接下來來試一下第三種
步驟
建立一個類繼承 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 {
}
重寫 doGet 和 doPost 方法
public class ServletDemo02 extends HttpServlet {
在 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>
部署並啓動項目
經過瀏覽器測試
對象的生命週期,就是對象從出生到死亡的過程。即:出生 -> 活着 -> 死亡。官方說法是對象建立到銷燬的過程
出生:請求第一次到達 Servlet 時,對象就建立出來,而且初始化成功。只出生(建立)一次,將對象放到內存中
活着:服務器提供服務的整個過程當中,該對象一直存在,每次都是執行 service 方法
死亡:當服務中止時,或者服務器宕機時,對象死亡
結論:Servlet 對象只會建立一次,銷燬一次。因此 Servlet 對象只有一個實例。若是一個對象實例在應用中是惟一的存在,那麼咱們就稱它爲單例模式
代碼
建立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 {
配置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>
部署並啓動
說明:init只會執行一次
中止服務
中止tomcat,執行destory
因爲 Servlet 採用的是單例模式,也就是整個應用中只有一個實例對象。因此咱們須要分析這個惟一的實例對象中的類成員是否線程安全
模擬用戶登陸功能來查看 Servlet 線程是否安全
結論:一個瀏覽器表明一個線程,多個瀏覽器表明多個線程。按理說咱們指望的應該是每一個瀏覽器查看的都應該是本身的用戶名。而如今的結果是瀏覽器中數據混亂。所以,咱們能夠認爲 Servlet 是線程不安全的!
解決:定義類成員要謹慎。若是是共用的,而且只會在初始化時賦值,其餘時間都是獲取的話,那麼是沒問題的。若是不是共用的,或者每次使用都有可能對其賦值,那就要考慮線程安全問題了,能夠將其定義到 doGet 或 doPost 方法內或者使用同步功能便可。
案例演示
新建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;
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>
演示
由於須要演示線程安全,因此須要兩個瀏覽器模擬兩個線程,因此要開兩個瀏覽器
谷歌瀏覽器中url傳遞參數username=aaa
火狐瀏覽器中url傳遞參數username=bbb
而後谷歌瀏覽器先訪問,緊接着火狐瀏覽器訪問
結果現象是,倆瀏覽器都是welcome:bbb
分析
解決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;
使用同步代碼塊
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;
第一種 具體名稱的方式。訪問的資源路徑必須和映射配置徹底相同
第二種 / 開頭 + 通配符的方式。只要符合目錄結構便可,不用考慮結尾是什麼
第三種 通配符 + 固定格式結尾的方式。只要符合固定結尾格式便可,不用考慮前面的路徑
注意:優先級問題。越是具體的優先級越高,越是模糊通用的優先級越低。第一種 -> 第二種 -> 第三種
此種方式,只有和映射配置如出一轍時,Servlet纔會接收和響應來自客戶端的請求。
例如:映射爲:/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 {
配置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>
訪問:
此種方式,只要符合目錄結構便可,不用考慮結尾是什麼。
例如:映射爲:/servlet/*
這兩個URL均可以。由於用的*,表示/servlet/後面的內容是什麼均可以。
咱們仍是使用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>
訪問
此種方式,只要符合固定結尾格式便可,其前面的訪問URI無須關心(注意協議,主機和端口必須正確)
例如:映射爲:*.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>
訪問
咱們能夠給一個 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 {
配置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>
訪問
第一次訪問時建立
優點:減小對服務器內存的浪費。提升了服務器啓動的效率
弊端:若是有一些要在應用加載時就作的初始化操做,沒法完成
服務器加載時建立
優點:提早建立好對象,提升了首次執行的效率。能夠完成一些應用加載時要作的初始化操做
弊端:對服務器內存佔用較多,影響了服務器啓動的效率
修改 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打印的
默認Servlet是由服務器提供的一個Servlet,它配置在Tomcat的conf目錄下的web.xml中。以下圖所示:
它的映射路徑是<url-pattern>/<url-pattern>
,咱們在發送請求時,首先會在咱們項目中的 web.xml 中查找映射配置,找到則執行
可是當找不到對應的 Servlet 路徑時,就去找默認的 Servlet,由默認 Servlet 處理。因此,一切都是 Servlet。
訪問一個不存在的url
這個404界面,其實就是tomcat配置的默認的Servlet處理的結果
ServletConfig 是 Servlet 的配置參數對象,在 Servlet 的規範中,容許爲每個 Servlet 都提供一些初始化的配置。因此,每一個 Servlet 都有一個本身的 ServletConfig
做用:在 Servlet 的初始化時,把一些配置信息傳遞給 Servlet
生命週期:和 Servlet 相同
因爲它是在初始化階段讀取了web.xml中爲Servlet準備的初始化配置,並把配置信息傳遞給Servlet,因此生命週期與Servlet相同
這裏須要注意的是,若是Servlet配置了<load-on-startup>1</load-on-startup>
,那麼ServletConfig也會在應用加載時建立
ServletConfig的配置信息都是鍵值對的形式
在<servlet>
標籤中,經過<init-param>
標籤來配置。有兩個子標籤。
<param-name>
:表明初始化參數的 key。
<param-value>
:表明初始化參數的 value。
一個init-param配置一個信息,一個信息由name和value組成
案例
新建項目:servlet_demo2
src中新建包:com.itheima.servlet
新建類: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); } }
配置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>
經常使用方法:
掌握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
效果
ServletContext 是應用上下文對象。每個應用中只有一個 ServletContext 對象。
做用:能夠得到應用的全局初始化參數和達到 Servlet 之間的數據共享。
上下文理解:環境,不一樣環境給咱們帶來的信息是不同的。因此環境中有不少信息,數據,也就是環境是用於存儲數據的。
生命週期:應用一加載則建立,應用被中止則銷燬。
出生——活着——死亡
出生: 應用一加載,該對象就被建立出來了。一個應用只有一個實例對象。(Servlet和ServletContext都是單例的)
活着:只要應用一直提供服務,該對象就一直存在。
死亡:應用被卸載(或者服務器掛了),該對象消亡。
ServletContext圖示:
域對象指的是對象有做用域。也就是有做用範圍
域對象能夠實現數據的共享
不一樣做用範圍的域對象,共享數據的能力也不同
在 Servlet 規範中,一共有 4 個域對象
ServletContext 就是其中的一個
它也是 web 應用中最大的做用域,也叫 application 域
在整個項目範圍均可以使用 應用域共享的數據
它能夠實現整個應用以內的數據共享
ServletContext是一個接口,程序運行起來以後打印ServletContext的實例對象,實際上是一個ApplicationContextFacade對象
ApplicationContextFacade是ServletContext的實現類
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配置同級別
經常使用方法
掌握: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("/");獲取到的就是當前項目發佈的路徑
經常使用方法2
代碼:
//修改ServletContextDemo:存儲數據 //向域對象中存儲數據 context.setAttribute("username","zhangsan"); //修改ServletConfigDemo:獲取數據 //獲取ServletContextDemo設置共享的數據 Object username = context.getAttribute("username"); System.out.println(username);
效果
先訪問contextdemo存儲數據
再訪問configdemo獲取數據
咱們使用的是 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就出現了註解方式,能夠省去配置
新建項目:servlet_demo3
配置Java EE8
剩餘兩步省略
新建以後,項目目錄以下
web下沒有WEB-INF了,web.xml也沒有了
雖然web.xml不用了,可是WEB-INF還須要,因此WEB-INF須要本身建立出來
index.jsp沒用,刪除便可
新建類: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); } }
能夠正常訪問
註解詳解
Servlet 3.0 規範除了使用自動註解的配置方式外,還支持手動建立 Servlet 容器的方式
若是使用必須遵循其編寫規範。在 3.0 版本加入了一個新的接口:
定義一個類ServletDemo2,繼承 HttpServlet
重寫 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); } }
定義一個類,實現 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的建立和配置 } }
在 src 目錄下建立一個 META-INF 的包
在 META-INF 包下建立一個 services 的包
在 services 包下建立一個 javax.servlet.ServletContainerInitializer 的文件
文件中的內容爲容器實現類的全類名
com.itheima.servlet.MyRegister
在容器實現類中的 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"); //映射訪問資源路徑 }
部署並啓動項目
經過瀏覽器測試
效果
訪問案例首頁,看到一個能夠保存學生信息的界面
輸入內容,點擊保存,經過java服務器,而後最終保存到txt中
最後java服務器返回成功結果
建立一個 web 項目:servlet_test,配置虛擬目錄/stu
選擇javaee 7,這裏咱們仍是用web.xml
建立一個用於保存學生信息的 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>
建立一個類com.itheima.servlet.StudentServlet,繼承 HttpServlet
重寫 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); } }
在 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>
在 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(); }
部署並啓動項目
經過瀏覽器測試