Java Servlet 技術是Java體系中用於開發 Web 應用的底層技術。
Servlet 是運行在 Servlet 容器(如 Tomcat)中的Java程序,而 Servlet 容器或 Servlet 引擎至關於一個 Web 服務器,可是能夠產生動態內容,而不只是靜態資源。一個 Servlet 是一個 Java 程序,一個 Servlet 應用包含了一個或多個 Servlet,一個 JSP 頁面會被翻譯並編譯成一個 Servlet。
Servlet 應用運行在一個 Servlet 容器中,它沒法獨立運行。Servlet 容器未來自用戶的請求傳遞給 Servlet 應用,並將 Servlet 應用的響應返回給用戶。html
Servlet API 有如下4個Java包:java
Servlet 技術的核心是 Servlet,它是全部 Servlet 類必須直接或間接實現的一個接口。
Servlet 接口定義了Servlet 與 Servlet 容器之間的契約。這個契約歸結起來就是,Servlet 容器將 Servlet 類載入內存,並在 Servlet 實例上調用具體的方法。在一個應用程序中,每種 Servlet 類型只能有一個實例。web
用戶請求導致 Servlet 容器調用 Servlet 的 service 方法,並傳入一個 ServletRequest 實例和一個 ServletResponse 實例。ServletRequest 中封裝了當前的HTTP請求,ServletResponse 表示當前用戶的HTTP響應。
對於每個應用程序,Servlet 容器還會建立一個 ServletContext 實例。這個對象中封裝了上下文(應用程序)的環境詳情。每一個上下文只有一個 ServletContext。每一個 Servlet 實例也都有一個封裝 Servlet 配置的 ServletConfig。apache
Servlet 接口中定義瞭如下5個方法:數組
public void init (ServletConfig config) throws ServletException; public ServletConfig getServletConfig(); public void service (ServletRequest req, ServletResponse res) throws ServletException, IOException; public String getServletInfo(); public void destroy();
3個 Servlet 生命週期方法:瀏覽器
2個非生命週期方法:tomcat
在 eclipse EE + Tomcat 環境下編寫一個簡單的 Servlet 實例服務器
1. 下載 Tomcat
下載完成後解壓壓縮包,參考文件夾下的`RUNNIG.txt`配置環境變量。
其中`"CATALINA_HOME"`是必選項,指向 Tomcat 的根目錄。
2. 將 eclipse 與 Tomcat 關聯
Window->Preferences->Server->Runtime Enviroments 點擊 add 選擇下載的 Tomcat 版本,next 後能夠選擇 Tomcat 的名字,路徑和 JRE 版本。Finish 完成建立。
Window->Show View->Other 能夠選擇 Servers 窗口查看 Tomcat,雙擊能夠進一步配置 Tomcat,選擇端口號等等。cookie
1. 建立一個 Dynamic Web Project 在這個頁面下打勾,eclipse 會爲咱們自動建立一個 web.xml 文件。app
2. 右鍵 Project,配置 Build Path,點擊 add Library,選擇 Server Runtime,導入 Tomcat 中的 Servlet 類庫。
編寫 Servlet 類有3種方式:
以實現 Servlet 接口爲例,建立 HelloServlet 類
1 package com.JL916; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.Servlet; 7 import javax.servlet.ServletConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest; 10 import javax.servlet.ServletResponse; 11 import javax.servlet.annotation.WebServlet; 12 13 @WebServlet(name = "servlet", urlPatterns = {"/hi"}) 14 public class HelloServlet implements Servlet { 15 16 @Override 17 public void destroy() {} 18 19 @Override 20 public ServletConfig getServletConfig() { return null; } 21 22 @Override 23 public String getServletInfo() { return "hello"; } 24 25 @Override 26 public void init(ServletConfig arg0) throws ServletException {} 27 28 @Override 29 public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { 30 arg1.setContentType("text/html"); 31 PrintWriter writer = arg1.getWriter(); 32 writer.print("<html><head></head><body>Hello Servlet</body></html>"); 33 } 34 }
配置 Servlet 有兩種方式,一種是使用註解配置,即
@WebServlet(name = "servlet", urlPatterns = {"/hi"})
另外一種是在 web.xml 文件的 web-app 元素中添加 servlet 元素 和 servlet-mapping 元素,以下所示:
<servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.JL916.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/hi</url-pattern> </servlet-mapping>
注意:url樣式必須用一個'/'開頭
在瀏覽器中輸入 http://localhost:8080(Tomcat 端口號)/項目名稱/(url-pattern)
對於每個HTTP請求,Servlet容器都會建立一個 ServletRequest 實例,並將它傳給 Servlet 的 service 方法。ServletRequest 封裝了關於這個請求的信息。
主要方法:
public int getContentLength(); // 返回請求主體的字節數 public String getContentType(); // 返回請求主體的MIME類型 public String getParameter(String name); // 返回指定請求參數的值 經常使用於返回表單的值或查詢字符串的值 public String getProtocol(); // 返回請求的協議名稱和版本
ServletResponse 接口表示一個 Servlet 響應。在調用 Servlet 的 service 方法前,Servlet 容器首先建立一個 ServletResponse,並將它做爲第2個參數傳給 service 方法。
在 ServletResponse 中定義的方法之一是 getWriter 方法,它返回了一個能夠向客戶端發送文本的 java.io.PrintWriter。默認狀況下,PrintWriter 對象使用 ISO-8859-1 編碼。
在發送任何HTML標籤前,應該先調用 setContentType 方法,設置響應的內容類型,並將"text/html"做爲一個參數傳入。
當 Servlet 容器初始化 Servlet 時,Servlet 容器會給 Servlet 的 init 方法傳入一個 ServletConfig。
ServletConfig 封裝能夠經過`@WebServlet`或者部署描述符傳給 Servlet 的配置信息。這樣,傳入的每一條信息就叫一個初始參數。一個初始參數有 key 和 value 兩個元件。
爲了從 Servlet 內部獲取到初始參數的值,要在 Servlet 容器傳給 Servlet 的 init 方法的 ServletConfig 中調用 getlnitParameter 方法。
String getInitParameter(String name)
@WebServlet(name = "servlet", urlPatterns = {"/configtest"}, initParams = { @WebInitParam(name = "admin", value = "JL916"), @WebInitParam(name = "email", value = "admin@example.com") })
ServletContext 表示 Servlet 應用程序。每一個 Web 應用程序只有一個上下文。在將一個應用程序同時部署到多個容器的分佈式環境中時,每臺Java虛擬機只有一個 ServletContext 對象。 經過在 ServletConfig 中調用 getServletContext 方法,能夠得到 ServletContext。
有了 ServletContext,就能夠共享能夠從應用程序中的全部資料處訪問到的信息,而且能夠動態註冊 Web 對象。前者將對象保存在 ServletContext中的一個內部 Map 中。保存在ServletContext 中的對象稱做屬性。
ServletContext中的下列方法負責處理屬性:
public Object getAttribute(String name); public Enumeration<String> getAttributeNames(); public void setAttribute(String name, Object object); public void removeAttribute(String name);
GenericServlet 是一個抽象類,實現了 Servlet,ServletConfig,java.io.Serializable 接口,爲 Servlet 接口中的除 service 外的方法提供默認實現。
// 將 config 對象保存起來 public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } // 子類能夠覆蓋沒有參數的 init() 方法,ServletConfig 仍然由 GenericServlet 實例保存 public void init() throws ServletException { }
javax.servlet.http 中的許多類型覆蓋了 javax.servlet 中的類型。
主要類型以下;
HttpServlet 是一個抽象類,繼承自 GenericServlet。
HttpServlet 實現了 service 方法,將 ServletRequest 對象和 ServletResponse 對象轉換類型,再調用重載的service方法,獲取 request 的 method,再分別調用 doXXX 方法,所以無需再覆蓋 service 方法,只要覆蓋經常使用的 doGet 方法和 doPost 方法便可。
@Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; if (!(req instanceof HttpServletRequest && res instanceof HttpServletResponse)) { throw new ServletException("non-HTTP request or response"); } request = (HttpServletRequest) req; response = (HttpServletResponse) res; service(request, response); } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { // ... doGet(req, resp); } else if (method.equals(METHOD_HEAD)) { // ... doHead(req, resp); } else if (method.equals(METHOD_POST)) { 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 { // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // ... resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
HttpServletRequest 繼承自 ServletRequest,新增部分方法:
public String getMethod(); // 返回生成這個請求的HTTP方法名稱 public String getQueryString(); // 返回請求URL中的查詢字符串 public HttpSession getSession(); // 返回與這個請求相關的會話對象 若是沒有 將建立一個 public Cookie[] getCookies(); // 返回Cookie對象數組
HttpServletResponse 繼承自 ServletResponse,新增部分方法:
public void addCookie(Cookie cookie); // 添加一個Cookie public void sendRedirect(String location) throws IOException; // 發送一條響應碼 將瀏覽器跳轉到指定位置
使用部署描述符,若是須要修改配置值,如Servlet路徑,則不須要從新編譯Servlet類。
此外,能夠將初始參數傳給一個Servlet,而且不須要從新編譯Servlet類,就能夠對它們進行編輯。
部署描述符還容許覆蓋在 Servlet 標註中定義的值。Servlet 上的 @WebServlet 註解若是同時也在部署描述符中進行聲明,那麼它將不起做用。
參考資料:《Spring MVC 學習指南》 Paul Deck 著