Servlet基礎
Jsp的本質即為Servlet,jsp頁面部署到web容器中後會被編譯為Servlet。Servlet使用輸出流輸出html標籤,開發過程複雜且難以進行設計。
Servlet是一個完整的java類,jsp是對Servlet的簡化。Servlet中沒有jsp的內建物件,jsp內建物件需要Servlet顯式建立。 在MVC架構中,Servlet已不再作為檢視僅僅作為控制器使用。
這裡介紹了Servlet開發中所涉及的基礎知識以及區域性應用範例,Servlet作為控制器的應用介紹請見《Servlet作為控制器》。
1. Hello World
(1) 在IDEA中建立一個Java Enterprise專案 -> Web Application,選擇Java EE版本和Sever, 然後在Src目錄下建立一個新的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;
public class FirstServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
}
Servlet介面定義了兩個預設實現類,分別為:GenericServlet、HttpServlet。
HttpServlet指能夠處理HTTP請求的servlet,它在原有Servlet介面上新增了一些與HTTP協議處理方法,它比Servlet介面的功能更為強大。因此在編寫Servlet時,通常應繼承這個類,而避免直接去實現Servlet介面。
HttpServlet在實現Servlet介面時,重寫了service方法,該方法內的程式碼會自動判斷使用者的請求方式,如為GET請求,則呼叫HttpServlet的doGet方法,如為Post請求,則呼叫doPost方法。因此,在編寫Servlet時,通常只需要重寫doGet或doPost方法,而不要去重寫service方法。此外,還可以根據需要重寫doPut和doDelete方法,但這兩種請求使用並不頻繁。
通常,無需重寫init和destory方法;若要在初始化Servlet時需要初始化某些資源(建立資料庫連線),則可重寫init(ServletConfig config)方法,並在重寫的第一行使用 super.init(config);呼叫HttpServlet的init方法。注意,是重寫init()方法,無需定義構造器。若要在Servlet銷燬前完成某些資源的回收(如關閉資料庫連線),則需重寫destory方法。
(2)編寫web.xml配置檔案
IDEA會自動完成大部分配置,只需完成<servlet-mapping>配置:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/demo</url-pattern> </servlet-mapping> </web-app>
(3) 部署到Tomcat
將原始碼目錄裡包含index.jsp的web目錄拷貝到tomcat的webapps目錄下,重新命名為應用的名字:servlet-demo。
在idea中編譯工程後,在out目錄下有編譯好的.class檔案, 我們將專案產出目錄out\production\ServletDemo下的.class檔案拷貝到webapps\WEB-INF\classes目錄中。classes的目錄結構必須與包一致。WEB-INF\lib目錄下也可以部署.jar包。
(4) 啟動Tomcat,在http://localhost:8080/servlet-demo/demo路徑下訪問Servlet
2. Servlet原理與配置
Servlet是執行於伺服器端的程式,用於處理和響應客戶端的請求,Servlet執行過程:
(1)裝載並建立該Servlet的一個例項物件。
(2)呼叫Servlet例項物件的init()方法。
(3)建立一個用於封裝HTTP請求訊息的HttpServletRequest物件和一個代表HTTP響應訊息的HttpServletResponse物件,然後呼叫Servlet的service()方法並將請求和響應物件作為引數傳遞進去。
(4)WEB應用程式被停止或重新啟動之前,Servlet引擎將解除安裝Servlet,並在解除安裝之前呼叫Servlet的destroy()方法。
Servlet容器的建立與銷燬由Web容器控制,大部分Servlet例項在客戶端第一次請求Servlet時建立。另外一些Servlet在Web應用啟動時建立,即load-on-startup Servlet,它們通常是提供後臺服務或,或者需要攔截很多請求的Servlet。
load-on-startup可以在web.xml的<servlet>元素的<load-on-stratup>子元素中進行配置,或通過@WebServlet Annotation的loadOnStartup屬性指定。它們都接受一個無符號整型值(>= 0)作為引數,表示Servlet載入的順序,值越小越先被載入。<load-on-startup>1</load-on-startup>或@WebServlet(loadOnStartup=1) class ...。
配置Servlet
配置Servlet時還可以增加額外的配置引數。配置引數可以實現更好的可移植性,避免將配置資訊寫死在原始碼中。為Servlet配置引數可以使用web.xml的<servlet>元素的<init-param .../>子元素來指定,或者使用@WebServlet(initParams = )來指定。
JSP內建物件的config就是ServletConfig。ServletConfig的 getInitParameter(String name)方法用於獲取初始化引數。
使用initParams配置資料庫連線池:
@WebServlet(
initParams = {
@WebInitParam(name = "driver", value = "com.mysqi.jdbc.Driver"),
@WebInitParam(name = "url", value = "jdbc:mysqi://localhost/test"),
@WebInitParam(name = "user", value = "username"),
@WebInitParam(name = "pass", value = "passwd2333"),
})
class FirstServlet extends HttpServlet {
public void init(ServletConfig config) {
super.init(config);
try {
String driver = config.getInitParamter("driver");
String url = config.getInitParamter("url");
String user = config.getInitParamter("user");
String pass = config.getInitParamter("pass");
Class.forName(driver);
Connection connect = DriverManager.getConnection(url, user, pass);
}
catch (Exception e) {
e.PrintStackTrace();
}
}
}
用Properties檔案進行配置
不過更常用的方法是通過.properties檔案進行配置設定。Properties類繼承自Hashtable類並且實現了Map介面,是一種使用字串鍵值對進行儲存的屬性集。
load(InputStream inStream)可以從.properties屬性檔案對應的檔案輸入流中,載入屬性列表到Properties類物件。
Properties pro = new Properties();
FileInputStream in = new FileInputStream("a.properties");
pro.load(in);
in.close();
store(OutputStream out, String comments)將類物件的屬性集寫入輸出流中。
FileOutputStream oFile = new FileOutputStream(file, "a.properties");
pro.store(oFile, "Comment");
oFile.close();
如果comments不為空,儲存後的屬性檔案第一行會是#comments,表示註釋資訊;如果為空則沒有註釋資訊。註釋資訊後面是屬性檔案的當前儲存時間資訊。
getProperty(String key)方法用於得到屬性值,setProperties(String key, String value)方法則用來設定屬性值。
3. 請求與響應HttpServletRequest和HttpServletReponse
HttpServletRequest繼承自ServletRequest.客戶端瀏覽器發出的請求被封裝成為一個HttpServletRequest物件。HttpServletRequest使用鍵-值對的方式封裝包括請求的地址,請求的引數,提交的資料,cookie以及客戶端的ip甚至客戶端作業系統都包含在其內的資訊。除了這些資訊外,控制器在轉發請求的時候可以使用setAttribute(String, Object)方法來新增/設定資訊。
HttpServletresponse繼承自ServletRequest,主要封裝了Http響應頭,cookies,狀態碼和響應資料。
HttpServletRequest與HttpServletResponse類都提供了一系列setter和getter方法用於設定和取得響應屬性。
詳細的說明見《Servlet的Request與Response》。
4. 會話管理Session與Cookie
(1) Session
session物件代表了瀏覽器/客戶端與伺服器之間的一次會話,這個過程可以是連續的也可以出現中斷。實際上,HttpSession物件是一個容器,儲存了會話過程中request/response物件。
當伺服器端執行HttpSession session = request.getSession();時session物件才被建立,如果JSP沒有顯式地使用 <% @page session="false"%> 關閉session,則JSP檔案在編譯成Servlet時將會自動加上這一條語句,這也是JSP中隱含的 session物件的來源。
連續一定時間伺服器沒有收到該Session所對應客戶端的請求,並且這個時間超過了伺服器設定的Session超時的最大時間時session物件將會被關閉;伺服器端呼叫HttpSession.invalidate()或伺服器程式停止也會關閉session。
session物件存放在伺服器端記憶體中,不會因為瀏覽器的行為(瀏覽器關閉,關閉網頁)而關閉。由於session會消耗記憶體資源,因此,如果不打算使用session,應該在所有的JSP中關閉它。
session物件擁有一個ID作為唯一標識,session.getId()例項方法可以得到這個ID。在session有效期間,瀏覽器再次傳送請求時會將這個唯一標識新增到請求頭中,從而繼續會話。session也以鍵值對的方式儲存屬性,與request的屬性不同的是在session有效期間屬性一直有效。
session常用的方法包括:
public void setAttribute(String name,Object value)
以鍵值對的方式將屬性值寫入session.
public object getAttribute(String name)
取得name的屬性值,如果屬性不存在則返回null
public void removeAttribute(String name)
從會話中刪除name屬性,如果不存在不會執行,也不會丟擲異常.
public Enumeration getAttributeNames()
返回和會話有關的列舉值
public void invalidate()
使會話失效,同時刪除屬性物件
public Boolean isNew()
用於檢測當前客戶是否為新的會話
public long getCreationTime()
返回會話建立時間
public long getLastAccessedTime()
返回在會話時間內web容器接收到客戶最後發出的請求的時間
public int getMaxInactiveInterval()
返回在會話期間內客戶請求的最長時間為秒
public void setMaxInactiveInterval(int seconds)
允許客戶客戶請求的最長時間
ServletContext getServletContext()
返回當前會話的上下文環境,ServletContext物件可以使Servlet與web容器進行通訊
public String getId()
返回會話期間的識別號
(2)Cookie
與Session類似Cookies也是一種儲存訪問歷史,以進行會話管理的技術(如自動登入)。Cookies是儲存在客戶端的文字檔案,相對於Session一般具有更長的生存期。一個Cookie本身就是一個鍵值對,這些鍵值對的集合通過Cookie陣列來管理。
javax.servlet.http.Cookie類封裝了Cookie, Cookie[] cookies = request.getCookies();可以得到隨客戶端請求一同傳送的cookie陣列。
Cookie cookie = new Cookie(String name, String value);建立新的Cookie。response.addCookie(cookie);將其加入response中傳送到客戶端,更新客戶端的Cookie陣列。
Cookie提供了一系列API來進行設定:
public String getName()
例項方法,取得Cookie的名字
public String getValue()
例項方法,取得Cookie的值
public void setValue(String newValue)
例項方法,設定Cookie的值
public void setMaxAge(int expiry)
例項方法,獲取/設定Cookie過期之前的時間,以秒計。如果不設定該值,則Cookie只在當前會話內有效,即在使用者關閉瀏覽器之前有效,而且這些Cookie不會儲存到磁碟上。若生存時間為負值,代表瀏覽器關閉Cookie即消失。生存時間為0,代表刪除Cookie,生存時間為正數,代表Cookie存在的秒數。
public int getMaxAge()
例項方法,得到Cookie的 最大生存時間。
public void setPath(String uri)
設定cookie的有效路徑,比如把cookie的有效路徑設定為"/xdp",那麼瀏覽器訪問"xdp"目錄下的web資源時,都會帶上cookie,再比如把cookie的有效路徑設定為"/xdp/gacl",那麼瀏覽器只有在訪問"xdp"目錄下的"gacl"這個目錄裡面的web資源時才會帶上cookie一起訪問,而當訪問"xdp"目錄下的web資源時,瀏覽器是不帶cookie。
public String getPath()
例項方法,得到Cookie的路徑。
public void setDomain(String pattern)
獲取/設定Cookie適用的域。一般地,Cookie只返回給與傳送它的伺服器名字完全相同的伺服器。使用這裡的方法可以指示瀏覽器把Cookie返回給同一域內的其他伺服器。注意域必須以點開始(例如.sitename.com),非國家類的域(如.com,.edu,.gov)必須包含兩個點,國家類的域(如.com.cn,.edu.uk)必須包含三個點。
public String getDomain()
例項方法,得到Cookie的適用的域。
5. 上下文Servlet Context
上下文(context)是一系列屬性的集合,Servlet中存在不同作用域的上下文儲存不同作用域下的屬性配置。
Servlet中的上下文可以分為四級作用域:
1. PageContext-Page級上下文,JSP頁面被請求時建立,請求被轉發或返回response時銷燬。
2. Request - 當收到客戶端請求時建立,返回response時銷燬。
3. SessionContext - 會話級上下文
4. ServletContext - Web應用級上下文,可在不同Servlet之間互動
(1) ServletContext
ServletContext,是一個全域性的儲存資訊的空間,伺服器開始時被建立,伺服器關閉時被銷燬。ServletContext用於設定應用程式中所有Servlet共有的資訊,Web容器負責提供servlet容器內ServletContext介面的實現。 由於一個WEB應用中的所有Servlet共享同一個ServletContext物件,因此Servlet物件之間可以通過ServletContext物件來實現通訊。
ServletContext context = this.getServletContext();獲取ServletContext物件
context.setAttribute(String,Object ); 設定屬性
context.getAttribute("name");獲得屬性
removeAttribute(String name)移除屬性
java.util.Enumeration<java.lang.String> getAttributeNames()
得到全部屬性名
獲取WEB應用的初始化引數:
getInitParameter(String)