#Servlethtml
- 編寫一個Java類,實現servlet接口
- 把開發好的Java類部署到web服務器中
###demo:使用servlet給瀏覽器輸出「Hello World!~」java
使用UML描述Servlet的調用過程web
###Servlet的生命週期 Servlet會在第一次被訪問的時候建立出相應的Servlet對象,爲了方便後續請求的訪問,Web容器建立一個Servlet對象後,會一直將其保存在容器中,之後關於該Servlet的請求,都使用該對象處理,一直不會被銷燬,直到web容器關閉。也就是說,在一個Servlet運行的過程當中,web容器中有且只有一個該Servlet對象存在,多個請求使用多線程來分別處理,一個請求對應一個線程,多個請求多個線程(Tomcat會給每一個線程建立對應的request對象和response對象,一塊兒交給Servlet對象),這些線程共享Servlet對象!能夠得出一個結論:Servlet是非線程安全的,可是request對象和response對象是線程安全的數據庫
Servlet的生命週期演示(init方法與destroy方法)設計模式
###使用Eclipse開發Servletapi
###HttpServlet HttpServlet指得是可以處理HTTP請求的serlvet,它在原有的Servlet接口上添加了一些HTTP協議處理的方法,它更增強大,在開發中一般繼承這個類。 HttpServlet在實現Servlet接口時,重寫了service方法,該方法內部會自動判斷用戶的請求方式,好比是get請求,則會調用HttpServlet的doGet方法,post請求,調用doPost方法。 在開發中,直接覆蓋doGet和doPost方法,不用覆蓋service方法。瀏覽器
閱讀HttpServlet文檔,查看HttpServlet源碼(ctrl+shift+T) 使用Eclipse建立一個新的Servlet,繼承HttpServlet,直接建立Servlet,自動生成配置(一個Servlet能夠配置多個映射)緩存
#Servlet細節總結安全
**Servlet若是想要外部訪問,必須把Servlet程序映射到一個URL地址上,在web.xml中使用`<servlet>`元素和`<servlet-mapping>`元素完成** >`<servlet>`元素用於註冊Servlet,它包含兩個子元素:`<servlet-name>`和`<servlet-class>`,分別用於註冊Servlet的註冊名稱和Servlet的完整類名 >`<servlet-mapping>`元素用於映射一個已經註冊的Servet對外訪問路徑,它包含兩個子元素:`<servlet-name>`和`<url-pattern>`,分別用於指定註冊名和對外訪問路徑
用一個Servlet能夠被映射到多個URL上服務器
在Servlet映射到的URL,可使用通配符來配置,可是隻能有兩種固定的格式: > *
「 * . 擴展名」,如: *.do,*.html(僞靜態)
> *"/* ",如:/action/*
使用了通配符後,就會產生一些新的問題,以下:
那麼當這樣通配後,對於類似的URL請求會怎麼去處理呢?舉例來講明: * `/abc/a.html,/abc/* 和 /* 都匹配,Servlet引擎將會調用Servlet1` * `/abc,/abc/* 和 /abc 都匹配,Servlet引擎將會調用Servlet3` * `/abc/a.do,/abc/* 和 *.do 都匹配,Serlvet引擎將會調用Servlet1` * `/a.do,/* 和 *.do 都匹配,Servlet引擎將會調用Servlet2` * `/xxx/yyy/a.do,/* 和 *.do 都匹配,Servlet引擎將會調用Servlet2` \*號開頭的優先級最低!不以\*開頭的話,哪一個最像選擇哪一個
Servlet是不能獨立運行的,它的運行徹底是由Servlet引擎來控制和調度的。一個Servlet若是被訪問,無論訪問多少次,Web容器中以後一個Servlet對象,被多個請求(線程)共享,可是每次執行service方法,都是根據此次請求從新建立的請求對象和響應對象。當本次請求完成,請求對象和響應對象都會被銷燬(響應對象的銷燬在建立了標準的Http響應以後)。
<serlvet>
元素能夠配置隨着web容器的啓動而建立該Servlet對象。使用<load-on-startup>
元素來完成,在建立過程當中,就會調用Servlet的init方法。若是有一些操做須要在服務 器啓動的時候就完成,就可使用這種方式來完成(初始化數據庫鏈接池等)。
若是某個Servlet的映射路徑爲 "/",那麼這個Servlet就是當前web應用的默認Servlet。凡是在web.xml中找不到映射的URL,它們的訪問請求都將交給這個默認的Servlet處理,也就是說,默認的Servlet用於處理全部其它Servlet都不處理的請求。
其實對於Tomcat來講,咱們全部的請求都不能直接到達web資源,都會通過一個Servlet。如:http://localhost:8080/testweb/1.html ,若是項目根目錄有一個 1.html 文件 是能夠請求的到的,但其實,並非直接訪問了該資源,Tomcat有一個默認的Servlet,由這個默認的Servlet讀取了這個資源,而後返回給客戶端。若是沒有,就是404 若是你自定義了默認的Servlet,將會覆蓋掉系統的默認Servlet,因此不建議這麼作。(查看Tomcat的web.xml,其實全部的靜態資源,都由該Servlet處理)
線程安全
Servlet存在線程安全問題,在實際開發中,要根據具體狀況來編寫解決同步的代碼 在Servlet中編寫程序時,要注意對象的靜態屬性的處理,否則會引起內容溢出的問題(對象的靜態集合屬性處理) 標準解決方案:同步代碼塊。非標準解決方案:SingleThreadModel(已經被廢棄) 對於Servlet的線程安全問題,的確是一個比較靈活的問題,那麼有如下幾條開發建議,能夠避免Servlet的線程安全問題: 1. 儘可能避免使用成員變量,若是萬不得已使用了,就須要同步,可是注意同步可用性最小的代碼路徑 2. 要清楚request是線程安全的,HttpSession,ServletContext都不會線程安全的 3. 使用同步的集合類 4. 不要在Servlet中建立本身的線程來完成某個功能(增長了複雜度) 5. 在多個servlet中對外部對象(好比文件)進行修改操做時,必定要加鎖,作到互斥的訪問效果
#ServletConfig對象
<init-param>
標籤爲servlet配置一些初始化參數#ServletContext對象(重點)
getServletContext()
來獲取ServletContext對象)###MVC簡單介紹 到目前爲止,對於客戶端的請求,咱們都是使用對應的Servlet來作簡單處理,可是問題是,通常的,不可能就簡單在返回一個字符串或者在控制檯打印一個語句,應該給客戶返回一個html頁面,那麼這個html頁面哪裏來?若是這個html是個靜態資源,那麼很簡單,可是咱們開發的是動態web資源,該怎麼辦呢?其實很簡單,使用Servlet的response對象發送html的字符流給客戶端。這種方法表面上看起來是沒有什麼問題,可是實際操做你就會發現,這個作法至關麻煩,並且開發效率很低,應該專門有一種特殊能力的Servlet來處理html的繪製,這種具備特殊能力的Servlet就是JSP。
JSP其實就是一個特殊的Servlet,它能很好的處理html的問題,使得頁面的渲染與程序邏輯的處理能夠得以分離。(demo,在Servlet中傳值並轉發給一個JSP)
#在Servlet中獲取各類資源文件(重點)
在實際開發中,不少時候須要獲取服務器上的一些別的資源來幫助開發,這些資源的獲取方式都不太同樣。
若是在開發中,須要的文件存儲在WebContent(項目目錄)中,那就使用ServletContext來讀取,相關的方法有:
getRealPath(String path),返回一個虛擬路徑對應資源的真實路徑
getResource(String path),返回一個虛擬路徑對應資源的URL對象
getRescourceAsStream(String path),返回一個虛擬路徑對應資源的輸入流
getResoucePaths(String path),返回一個虛擬路徑下的全部對應資源的集合
這些方法中的參數都不該該是資源的絕對路徑或相對路徑,應該是一個針對當前應用的虛擬路徑,應該以 「/」 開頭,這個 "/" 就表示web應用所在目錄,也成爲項目根目錄,而後按照資源在應用的目錄結構來指定資源的虛擬路徑。
在不少時候,咱們的資源文件並不在Web資源目錄中,而是在類目錄中,這個時候怎麼讀取呢?
使用類加載器來獲取類路徑中的資源:getSystemResource(String path),getResource(String path)
使用類自己來獲取類路徑中的資源:getResource(String path)
使用ServletContext獲取項目根目錄,而後按照項目層級去讀取文件(WEB-INF/classes/a.txt)
- 根據類加載器來獲取資源時,不要添加 "/",類加載器會從該加載器的類路徑根目錄來查找 path 指定的資源,加了 "/",反而找不到。
- 使用類自己來獲取資源時,加 "/" ,意味着從類路徑的根目錄來查找,不加 "/",意味着,從當前類所在的文件夾來查找資源
- web應用和本地方法運行的效果是不同的,有關於System的資源獲取,在web應用中是不起做用的
- 還有 getResourceAsStream(String path)系列的方法,跟上述的 getResource(String path)方法特色是一致的,只不過一個是返回URL對象,一個是返回流對象
- 使用類加載器的 getResourceAsStream(String path) 方法來獲取資源的輸入流時,不能實現動態讀取文件變動,應該用類加載器來獲取路徑,而後用傳統的讀取文件的方式再次讀取文件,這樣就能實現實時更新數據了
- 若是資源文件過大,不要使用類加載器的方式來直接獲取,由於這種方式會直接把資源所有加載進內存,容易內存溢出,使用類加載器獲取地址,用傳統方式的流而後緩衝讀取
- 關於System與no-System的方法有什麼區別,我已經總結好了,若是須要進一步瞭解,參看官方關於Resources的解釋
#在客戶端緩存Servlet的輸出 對於不常常變化的數據,在Servlet中能夠爲其設置合理的緩存時間值,以免瀏覽器頻繁得向服務器發送請求,提高服務器的性能。
String data = "aaaaaaaaaaaaaaaaaaaaaa"; long time = System.currentTimeMillis() + 1 * 24 * 60 * 60 * 1000; System.out.println("hehe"); response.setDateHeader("expires", time); response.getWriter().write(data);