Servlet 编程基础
可參考博文 超文本傳輸協議HTTP。
Servlet 概述
Servlet(Server Applet)是Java Servlet 的簡稱,稱為小服務程序或服務連接器,用Java 編寫的服務器端程序,主要功能在于交互式地瀏覽和修改數據,生成動態Web 內容。
從原理上講,Servlet 可以響應任何類型的請求,但絕大多數情況下Servlet 只用來擴展基于HTTP 協議的Web 服務器。HTTP 定義的與服務器交互的方法有GET、POST、PUT和DELETE 等,其中最基本的是GET 與POST。HTTP-GET 與HTTP-POST 是使用HTTP 的標準協議動詞,用于編碼和傳送變量名/變量值對參數,并使用相關的請求(Request)語義。每個HTTP-GET 與HTTP-POST 都由一系列的HTTP 請求頭組成,這些請求頭定義了客戶端從服務器上請求了什么,而響應(Response)則是由一系列HTTP 應答頭和應答數據組成,如果請求成功,則返回應答數據。
其中GET 與POST 的主要區別如下
- GET 方法是默認的瀏覽器向Web 服務傳遞信息的方法,它會產生一個 很長的字符串,出現在瀏覽器的地址欄中。而POST 方式則是把數據作為一個單獨的消息以標準輸出的形式傳到后臺程序,所以使用POST 不會將數據顯示在地址欄中。
- 對于GET 方式,服務端用Request,QueryString 獲取變量的值;對于POST 方式,服務端使用Request,Form 獲取提交的數據。
- GET 方式受傳輸數據字節的限制,POST 方式不受限制。
狹義的Servlet是指Java語言實現的一個接口,廣義的Servlet是指任何實現了這個Servlet接口的類,一般情況下,人們將Servlet理解為后者。下面是Servlet 架構圖。
Servlet 與 CGI
Servlet 與CGI(Common Gateway Interfece,公共網關接口)都是服務端組件,通常情況下可以實現相同的效果。但是與CGI 相比,Servlet 有以下的相關優勢
- 性能更好
- 由于Servlet 是由Java 語言實現的,所以是獨立于平臺的。
- Servlet 在Web 服務器的地址空間內執行,沒有必要再創建一個單獨的進程來處理每個客戶端的請求。
- Java 類庫的全部功能對于Servlet 來說都是可用的。
Servlet 與 JSP
SUN 首先發展出 Servlet,其功能比較強勁,體系設計也很先進,只是,它輸出HTML 語句還是采用了老的 CGI 方式,是一句一句輸出,所以,編寫和修改 HTML 非常不方便。
Java Server Pages(JSP)是一種實現普通靜態HTML 和動態 HTML 混合編碼的技術,JSP 并沒有增加任何本質上不能用 Servlet 實現的功能。但是,在 JSP 中編寫靜態HTML 更加方便,不必再用 println語 句來輸出每一行 HTML 代碼。更重要的是,借助內容和外觀的分離,頁面制作中不同性質的任務可以方便地分開:比如,由頁面設計者進行 HTML設計,同時留出供 Servlet 程序員插入動態內容的空間。
JSP 在首次被訪問的時候會被服務器轉換為Servlet ,在以后的運行中,容器直接調用這個Servlet,而不再訪問JSP 頁面。所以來說JSP 的本質就是Servlet。
總而言之,JSP 的本質是Servlet ,由于在Servlet 中開發HTML 代碼不方便,所以JSP 應運而生。我們一般使用JSP 作數據頁面展示,使用Servlet 來處理客戶端與服務端的交互。
Servlet 的繼承結構
Servlet 接口:定義了一個servlet 應該具有的方法(如init、service 與destroy 方法等),所有的Servlet都應該直接或間接實現此接口。
GenericServlet 抽象類:通用Servlet,對Servlet 接口的默認實現,這是一個抽象類,其中的大部分方法都做了默認實現,只有service 方法是一個抽象方法需要繼承者自己實現。
HttpServlet 抽象類:對HTTP 協議進行了優化的Servlet,繼承自GenericServlet 類,并且實現了其中的service 抽象方法,默認的實現中判斷了請求的請求方式,并根據請求方式的不同分別調用不同的doXXX() 方法。通常我們編寫Servlet 直接繼承該抽象類即可。
下面就結合源碼來看一下HttpServlet 中service() 方法的實現(代碼邏輯很清晰就不再做具體的分析)
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {String method = req.getMethod(); //返回一個字符串形式的請求方式if (method.equals(METHOD_GET)) { //如果當前客戶端發起的是GET 方式的請求,就調用doGet() 方法long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logicdoGet(req, resp);} else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);if (ifModifiedSince < (lastModified / 1000 * 1000)) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be lessmaybeSetLastModified(resp, lastModified);doGet(req, resp);} else {resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}}} else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals(METHOD_POST)) { //如果客戶端發起的是POST方式的請求,調用doPost() 方法doPost(req, resp);} else if (method.equals(METHOD_PUT)) {doPut(req, resp); } else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}Servlet 的生命周期
Servlet 運行于服務器上的Web 容器中(比如Tomcat 與Jboss 等)。應用服務器中用于管理Java 組件的部分被稱為Servlet 容器。當Servlet 被部署在應用服務器以后,由容器控制Servlet 的生命周期。Servlet 在第一次被請求的時候加載和實例化。Servlet 一旦被加載,當響應結束后會一直駐留在內存中等待下一次請求,直至應用服務器關閉或者重新啟動。所以第一次訪問Servlet 花費的時間要大于以后訪問該Servlet 所用的時間。當容器作內存回收時,Servlet 可能會被刪除。
1. 加載Servlet 類,創建該類的實例。每一個用戶都會產生一個新的線程(所以說Servlet 是線程不安全的)。
2. Servlet 通過init() 方法進行初始化。
3. Servlet 調用service(req,resp) 方法,根據請求方式調用對應的do×××() 方法,來處理客戶端的請求。
4. Servlet 通過destroy() 方法終止。
5. Servlet 被JVM 的垃圾回收機制收集。
Servlet 的調用過程
可參考圖如下(百度百科)
為了更好的理解,這里通過一個例子來具體講述其中的過程。
新建一個Servlet,如下(當客戶端請求該Servlet 時,輸出一個表情符號)
package com.jas.test;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;public class ServletTest extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.getWriter().write("O(?_?)O~");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);} }在web.xml 中配置上面Servlet 的相關信息,如下
PS:Tomcat 7 及以上的版本不需要再做相應配置,通過@WebServlet(“/XXX”) 注解就可以實現配置文件的作用。這里為了演示效果仍然使用配置文件的形式。
效果如下
調用過程分析如下(HTTP 請求報文與響應報文數據摘自IE 瀏覽器),過程中省略了Servlet 實例化的過程。
參考資料:
《JavaEE編程及應用開發》
總結
以上是生活随笔為你收集整理的Servlet 编程基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关云长单刀赴会中吕蒙为什么不安?
- 下一篇: Session 的钝化与活化