Servlet概述
爲什麼要學習Servlet
Java Web的演變過程大概可以分爲4個階段:
- Servlet + jdbc + jsp
- Spring + Struts2+ Hibernate(SSH)
- Spring + SpringMVC + Mybatis(SSM)
- 微服務階段
前兩個階段基本上可以說是歷史了,當今Spring家族一統天下。
現在實際開發中很少直接使用Servlet了,但是各個框架的底層還是大量使用了Servlet,學習Servlet對後續各個框架的理解和學習都很有幫助。
什麼是 Servlet
Servlet 是運行在 Web 服務器或應用服務器上的程序,它是作爲來自 Web 瀏覽器或其他 HTTP 客戶端的請求和 HTTP 服務器上的數據庫或應用程序之間的中間層。
Servlet其實就是一個遵循Servlet開發的java類。Serlvet是由服務器調用的,運行在服務器端。
Servlet帶給我們最大的作用就是能夠處理瀏覽器帶來HTTP請求,並返回一個響應給瀏覽器,從而實現瀏覽器和服務器的交互。
工作流程
-
Tomcat將瀏覽器提交的請求封裝成HttpServletRequest對象,同時將輸出流封裝成HttpServletResponse對象
-
Tomcat把request、response作爲參數,調用Servlet的相應方法,例如doGet(request, response)等
-
Servlet中主要處理業務邏輯
生命週期
在 Web 容器中,Servlet 主要經歷 4 個階段,如下圖:
- 加載Servlet。當Tomcat第一次訪問Servlet的時候,Tomcat會負責創建Servlet的實例
- 初始化。當Servlet被實例化後,Tomcat會調用
init()
方法初始化這個對象 - 處理服務。當瀏覽器訪問Servlet的時候,Servlet 會調用
service()
方法處理請求 - 銷燬。當Tomcat關閉時或者檢測到Servlet要從Tomcat刪除的時候會自動調用
destroy()
方法,讓該實例釋放掉所佔的資源。一個Servlet如果長時間不被使用的話,也會被Tomcat自動銷燬 - 卸載。當Servlet調用完
destroy()
方法後,等待垃圾回收。
如果有需要再次使用這個Servlet,會重新調用init()
方法進行初始化操作。
只要訪問Servlet,service()
就會被調用。init()
只有第一次訪問Servlet的時候纔會被調用。
destroy()
只有在Tomcat關閉的時候纔會被調用。
處理請求的方法
Servlet 即實現了 Servlet 接口 的類,實現 Servlet 接口 的時候,需要實現5個方法
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
爲了方便使用可以直接繼承 HttpServlet 類,該類已經默認實現了 Servlet 接口中的所有方法。
在編寫 Servlet 的時候,只需要重寫你需要的方法就好了。
並且該類還在原有 Servlet 接口上添加了一些與 HTTP 協議處理相關的方法。
- Servlet 處理請求的方法一共有三種:
- 實現
service()
方法 - 重寫
doGet()
- 重寫
doPost()
- 實現
HttpServletRequest 和 HttpServletResponse
對於每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,即 request 和 response 對象。
HttpServletRequest 常用方法
String getContextPath()
獲取上下文路徑String getHeader(String headName)
根據指定的請求頭獲取對應的請求頭的值.String getRequestURI()
返回當期請求的資源名稱. 上下文路徑/資源名StringBuffer getRequestURL()
返回瀏覽器地址欄的內容String getRemoteAddr()
返回請求服務器的客戶端的IP
獲取請求參數的方法:
String getParameter(String name)
根據參數名稱,獲取對應參數的值.String[] getParameterValues(String name)
根據參數名稱,獲取該參數的多個值.Enumeration getParameterNames()
獲取所有請求參數的名字Map<String,String[]> getParameterMap()
返回請求參數組成的Map集合.
HttpServletResponse 常用方法
-
OutputStream getOutputStream():
獲取字節輸出流:文件下載 -
Writer getWriter()
獲取字符輸出流:輸出內容 -
resp.setContentType("text/html;charset=utf-8")
設置文件輸出的編碼格式和內容類型
-
resp.sendRedirect()
302重定向,臨時跳轉
301要使用另外的手段
Servlet 是單例的
解釋
瀏覽器多次對Servlet的請求,一般情況下,服務器只創建一個Servlet對象,也就是說,Servlet對象一旦創建了,就會駐留在內存中,爲後續的請求做服務,直到服務器關閉。
每次訪問請求對象和響應對象都是新的
對於每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,然後將這兩個對象作爲參數傳遞給它調用的Servlet的service()
方法,service()
方法再根據請求方式分別調用其他方法。
線程安全問題
當多個用戶訪問Servlet的時候,服務器會爲每個用戶創建一個線程。當多個用戶併發訪問Servlet共享資源的時候就會出現線程安全問題。
原則
- 如果一個變量需要多個用戶共享,則應當在訪問該變量的時候,需要加鎖
- 如果一個變量不需要共享,則直接在 doGet() 或者 doPost()定義,這樣不會存在線程安全問題
通過註解配置 Servlet
在之前的開發工作中,每次編寫一個Servlet都需要在web.xml文件中進行配置
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>com.web.controller.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ActionServlet</servlet-name>
<url-pattern>/servlet/ActionServlet</url-pattern>
</servlet-mapping>
而當一個項目中存在很多 Servlet,那麼配置文件就會變得很亂很大,在 Servlet 3.0 推出之後,我們可以使用註解來配置 Servlet
@WebServlet(name = "ActionServlet", urlPatterns = "/servlet/ActionServlet")
Web 組件之間的跳轉方式
請求轉發(forward)
又叫做直接轉發方式,客戶端和瀏覽器只發出一次請求,Servlet、HTML、JSP或其它信息資源,由第二個信息資源響應該請求,在請求對象request中,保存的對象對於每個信息資源是共享的。
比如:從 AServlet 請求轉發到 BServlet
- 語法:
request.getRequestDispatcher(path).forward(request, response);
參數:path
,要跳轉到的資源路徑:上下文路徑 / 資源路徑
- 特點:
- 地址欄中的地址不變
- 只有一個請求
- 資源是共享的
- 可以訪問 WEB-INF 中的資源
- 請求轉發不能跨域訪問
URl 重定向(redirect)
又叫做間接轉發方式(Redirect)實際是兩次HTTP請求,服務器端在響應第一次請求的時候,讓瀏覽器再向另外一個URL發出請求,從而達到轉發的目的。
比如:從AServlet重定向到BServlet
- 語法:
response.sendRedirect(String location);
參數:location
,轉發到的資源路徑
- 特點:
- 地址欄中的地址【會】發生改變
- 有兩個請求
- 在兩個 Servlet 中不可以共享請求中的數據
- 最終的響應由BServlet來決定,和 AServlet 沒有關係
- 不可以訪問 WEB-INF 中的資源
- 請求轉發可以跨域訪問