JavaWeb學習筆記之Servlet基礎

Servlet基礎上

1什麼是Servlet

Servlet是JavaWeb應用中最核心的組件,屬於動態資源。本質上Servlet是一個實現瞭javax.servlet.Servlet接口的Java類,且Servlet類運行在Servlet容器中,其對象由Servlet容器創建,通過該對象,可以訪問Servelt容器提供的其他資源。

2Servlet作用

Servlet容器接收客戶端請求,並交給Servlet處理。其作用如下:

動態生成HTML文檔;

將請求轉發給同一個Web應用中其他Servlet組件;

將請求轉發給其他Web應用中的Servlet組件;

讀取客戶端的Cookie,以及向客戶端寫入Cookie;

訪問其他服務器資源(如數據庫)。

3Servlet特點

l Servlet類是由程式員編寫,對象由Servlet容器創建,且Servlet容器調用相應方法。

l 一個Web應用中可以存在很多Servlet類,但每個Servlet類隻有一個對象(即Servlet類單例)。servlet-name.

l Servlet類線程不安全,效率較高。

4第一個Servlet程式

step01- 編寫一個Java類實現Servlet接口

public class FirstServlet implements Servlet{

@Override

public void destroy() {

}

@Override

public ServletConfig getServletConfig() {

return null;

}

@Override

public String getServletInfo() {

return null;

}

@Override

public void init(ServletConfig arg0) throws ServletException {

}

@Override

public void service(ServletRequest arg0, ServletResponse arg1)

throws ServletException, IOException {

PrintWriter out = arg1.getWriter();

out.println("my first Servelt program");

}

}

step02- 導入servlet.jar包

> set classpath=%classpath%;c:\tomcat7\lib\servlet-api.jar

step03- 編譯帶包的類

> javac -d . FirstServlet.java

step04- 在webapps中創建web應用

hello

WEB-INF

classes

FirstServlet全路徑名(包名+類名)

web.xml

且在WEB-INF中存放編譯的class档案和web.xml档案。

step05- 配置web.xml档案中

firstServlet

com.hao.demo01.FirstServlet

firstServlet

/first

step06- 打開瀏覽器,訪問https://localhost:8080/hello/first

Servlet執行流程分析

1)根據URL:https://localhost:8080,解析出主機及web服務器。

2)根據/hello/first,解析出上下文路徑及訪問資源

3)根據/first,查找web.xml中對應的, 根據再查找值

註意:tomcat加載web應用時,會先把web.xml档案讀入到內存中,當需要參考web.xml档案時,實際隻需要從內存中讀取相關數據就行,無需再到档案系統中讀取web.xml。

4)根據包名和類名,反射創建FirstServelt對象,調用init方法

Servlet servlet = (Servlet)servletCache.get(firstServlet);

if(servlet == null){

//Servle對象一創建,就初始化

servlet = (Servlet)Class.forName(com.hao.demo01.FirstServlet).newInstance();

servlet.init();//Servlet對象一旦創建,即初始化

servletCache.put(firstServlet, servlet);

}

5)根據客戶請求(request),調用service方法,並根據response對象,將” myfirst servlet program”發送給瀏覽器。

servlet.service(res, resp)

5用MyEclipse開發第一個Servlet

在MyEclipse中創建web project。

src包中創建一個java類實現Servlet接口

webroot\WEB-INF\web.xml做servlet映射

啟動tomcat,將工程發佈到tomcat服務器

瀏覽器訪問。

6Servlet細節

關於URL映射配置

關於Servlet進行URL映射

Servlet規范之所以規定對Servlet進行URL映射,有兩點原因?

a.可以為一個Servlet映射多個URL。

https://localhost:8080/myapp/login.do

https://localhost:8080/myapp/loginout.do

https://localhost:8080/myapp/checkout.do

使用以上訪問,全部都有ActionServlet處理。

註意:* 為通配符。映射Servlet路徑時,可以使用 /* 或 *.擴展名 兩種形式。兩者不能同時使用,/*具有較高的優先級。(/servlet/*也可以,但不可以/*.do或*.*)

一個還可以對應多個元素

b.簡化Servlet的URL,且可以向客戶端隱藏Web應用實現細節

在URL中暴露Servlet的完整類名,復雜,不容易理解和記憶。對Servlet進行URL映射,可以提供一個簡潔易懂的URL。

load-on-startup元素

元素下可以配置子元素。

配置方式如下:

1

用於指定Servlet容器啟動Web應用時,加載各個Servlet的次序。如果值為0或正數,Servlet容器先加載數值小的Servlet,再依次加載數值大的Servlet;如果值為負數或沒有設定,Servlet容器將在客戶端首次訪問Servlet時加載它

tomcat\conf\web.xml

服務器下所有web應用中的web.xml都會自動繼承該档案中所有的配置信息。

http:localhost:8080/hello/a.html

上面的URL資源名(a.html)在web.xml档案中並沒有配置,此時訪問時,先訪問缺省的Servlet,在tomcat\conf\web.xml档案中配置瞭一個缺省的DefaultServlet。DefaultServlet幫我們去web應用下讀取a.html,並響應給瀏覽器。如果沒有,發送404。也就是說,我們通過IE訪問服務器訪問的都是Servlet。

//優先級最低,如果請求無人處理或不存在,則它來處

default//理,否則顯示404

org.apache.catalina.servlets.DefaultServlet

debug

0

listings

false

1

jsp

org.apache.jasper.servlet.JspServlet

fork

false

xpoweredBy

false

3

default

//以下匹配所有URL,即訪問URL沒有匹配頁面,則執行//DefaultServlet

/

//以下表示任何URL後綴為JSP訪問時,都是執行名稱為jsp的Servlet,即JspServlet

jsp

*.jsp

*.jspx

//默認session超時為30分鐘

30

//定義瞭很多MIME類型

bmp

image/bmp

htm

text/html

//在Web應用的web.xml中如果沒有對下面標簽進行覆蓋,默認主頁為index.html, index.htm, index.jsp

index.html

index.htm

index.jsp

7Servlet相關接口和類的關系及詳細分析

a)Servlet API

i.ServletAPI主要由兩個包組成:javax.servlet和javax.servlet.http。在javax.servlet包中定義瞭Servlet接口及相關的通用接口和類;在javax.servlet.http包中主要定義瞭與HTTP協議相關的類與接口。

javax.servlet包中的接口和類:

ServletDispatcher接口

ServletContext接口

ServletConfig接口

Servlet接口

ServletRequest接口

ServletResponse接口

GenericServlet抽象類

javax.servlet.http包中的接口和類:

HttpServlet抽象類

HttpServletRequest接口

HttpServletResponse接口

ii.ServleltAPI中主要的接口與類關系

b)Servlet接口(查看源代碼)

Servlet接口是Servlet API的核心,所有Servlet類都必須實現該接口。

Servlet接口定義瞭5個方法:

以下三個方法由Servlet容器在Servlet生命周期不同階段調用相應方法。

1-init(ServletConfig config):負責初始化Servlet對象。容器在創建好Servlet對象後,就調用該方法。

2-service(ServletRequestrequest, ServletResponse response):負責響應客戶的請求,為客戶提供相應服務。當容器接收到客戶端要求訪問特定Servlet對象的請求時,就調用該Servlet對象的service方法

3-destroy():負責釋放Servlet對象占用的資源。Servlet對象生命周期結束前,容器調用該方法。

以下兩個方法返回Servlet相關信息的方法。Web應用中的程式代碼可以訪問Servlet這兩個方法,獲得Servlet的配置信息及其他相關信息。

4-getServletConfig():返回一個ServletConfig對象,該對象中包含Servlet初始化參數信息。

5-getServletInfo():返回一個字符串,該字符串中包含瞭Servlet的創建者,版本和版權等信息。

c)GenericServlet抽象類(查看源代碼)

GenericServlet抽象類為Servlet接口提供瞭通用實現,它與任何網絡應用層協議無關。GenericServlet實現瞭Servlet接口,ServletConfig接口,Serializable接口。

//GenericServlet實現瞭ServletConfig中所有的方法,其子類可以直接調用這些方法

publicabstractclassGenericServletimplements Servlet, ServletConfig,

java.io.Serializable {

privatestaticfinallongserialVersionUID = 1L;

privatetransient ServletConfig config;

public GenericServlet() {}

//具體子類可以覆蓋該方法,在銷毀Servlet對象前釋放所占資源如關閉IO流對象,數據庫連接

@Override

publicvoid destroy() {}

@Override

public String getInitParameter(String name) {

return getServletConfig().getInitParameter(name);

}

@Override

public Enumeration getInitParameterNames() {

return getServletConfig().getInitParameterNames();

}

@Override

public ServletConfig getServletConfig() {

returnconfig;

}

@Override

public ServletContext getServletContext() {

return getServletConfig().getServletContext();

}

@Override

public String getServletInfo() {

return"";

}

@Override

publicvoid init(ServletConfig config) throws ServletException {

this.config = config;

this.init();

}

publicvoid init() throws ServletException {}

publicvoid log(String msg) {

getServletContext().log(getServletName() + ": " + msg);

}

publicvoid log(String message, Throwable t) {

getServletContext().log(getServletName() + ": " + message, t);

}

//子類必須實現該方法,為特定客戶請求提供具體服務。

@Override

publicabstractvoid service(ServletRequest req, ServletResponse res)

throws ServletException, IOException;

@Override

public String getServletName() {

returnconfig.getServletName();

}

}

GenericServlet實現瞭Servlet接口和ServletConfig接口。主要身份是Servlet,運用瞭裝飾設計模式,且為自己附加瞭ServletConfig裝飾身份。具體實現中,GenericServlet類包裝瞭一個ServletConfig接口的實例,通過該實例來實現ServletConfig接口中的方法。

實現ServletConfig接口,且在類中創建ServletConfig對象。返回各個方法。

d)HttpServlet抽象類(查看源代碼)

HttpServlet類是GenericServlet類的子類。HttpServlet類為Servlet接口提供瞭與HTTP協議相關的通用實現,即HttpServlet對象適合運行在與客戶端采用HTTP協議通信的Servlet容器或者Web服務器中。

開發JavaWeb應用時,自定義的Servlet類一般都擴展HttpServlet類。

HTTP協議把客戶請求分p為GET,POST, PUT, DELETE等多種方式。HttpServlet類針對每一種請求方式都提供瞭相應的服務方法,如doGet,doPost, doPut, doDelete等方法。

publicabstractclassHttpServletextends GenericServlet {

privatestaticfinallongserialVersionUID = 1L;

privatestaticfinal String METHOD_GET = "GET";

privatestaticfinal String METHOD_POST = "POST";

public HttpServlet() {}

protectedvoid doGet(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException

{

String protocol = req.getProtocol();

String msg = lStrings.getString("http.method_get_not_supported");

if (protocol.endsWith("1.1")) {

resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);

} else {

resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);

}

}

protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

String protocol = req.getProtocol();

String msg = lStrings.getString("http.method_post_not_supported");

if (protocol.endsWith("1.1")) {

resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);

} else {

resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);

}

}

protectedvoid service(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

String method = req.getMethod();

if (method.equals(METHOD_GET)) {

long lastModified = getLastModified(req);

if (lastModified == -1) {

doGet(req, resp);

} else {

long ifModifiedSince;

try {

ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);

} catch (IllegalArgumentException iae) {

ifModifiedSince = -1;

}

if (ifModifiedSince < (lastModified / 1000 * 1000)) {

maybeSetLastModified(resp, lastModified);

doGet(req, resp);

} else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

}

}

} elseif (method.equals(METHOD_HEAD)) {

long lastModified = getLastModified(req);

maybeSetLastModified(resp, lastModified);

doHead(req, resp);

} elseif (method.equals(METHOD_POST)) {

doPost(req, resp);

} elseif (method.equals(METHOD_PUT)) {

doPut(req, resp);

} elseif (method.equals(METHOD_DELETE)) {

doDelete(req, resp);

} elseif (method.equals(METHOD_OPTIONS)) {

doOptions(req,resp);

} elseif (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);

}

}

@Override

publicvoid service(ServletRequest req, ServletResponse res)

throws ServletException, IOException {

HttpServletRequest request;

HttpServletResponse response;

try {

request = (HttpServletRequest) req;

response = (HttpServletResponse) res;

} catch (ClassCastException e) {

thrownew ServletException("non-HTTP request or response");

}

service(request, response);

}

}

實際使用中,HttpServlet具體子類,會針對客戶端的特定請求方式,來重寫HttpServlet父類中對應的doXxx()方法。為瞭doXxx方法能被Servlet容器訪問,訪問修飾符應該為public。

客戶端按照GET,POST方式請求訪問HelloServlet,且兩種方式下HelloServlet提供同樣服務,則在HelloServlet類中如下方式實現。

publicclassHelloServletextends HttpServlet{

@Override

protectedvoid doGet(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

//提供具體的實現代碼

}

@Override

protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

doGet(req, resp);

}

}

以上類與接口關系

e)ServletRequest接口

Servlet接口的service(ServletRequestreq, ServletResponse resp),含有ServletRequest類型。表示客戶端的請求。

當Servlet容器接收到客戶端要求訪問特定Servlet請求時,容器會先解析客戶端的原始請求數據,把它包裝成一個ServletRequest對象,當容器調用Servlet對象的service()方法時,可以把ServletRequest對象作為參數傳給service()方法。

ServletRequest接口提供瞭訪問客戶端請求數據的方法。(查看API)

1-getContentLength:返回請求正文長度,如果正文長度未知,則返回-1

2-getContentType:獲得請求正文的MIME類型。如果請求正文未知,返回null

3-getInputStream: 返回用於讀取請求正文的輸入流

4-getLocalAddr:返回服務器IP地址

5-getLocalName:返回服務器端主機名

6-getLocalPort:返回服務器端的HTTP端口號

7-getParameter(String name):根據請求參數名,返回來自客戶請求中匹配的請求參數值。

8-getProtocal: 返回客戶端與服務器端通信所有協議名稱及版本號

9-getReader:返回用於讀取字符串形式的請求正文的BufferedReader對象。

10-getRemoteAddr:返回客戶端IP地址

11-getRemoteHost:返回客戶端主機名

12-getRemotePort:返回客戶端HTTP端口號

13-setCharacterEncoding

請求范圍內存取共享數據

13-setAttribute(String name, Object obj):請求范圍內保存一個屬性,參數name表示屬性名,參數obj表示屬性值

14-getAttribute(String name):根據name參數給定的屬性名,返回請求范圍內匹配的屬性值.

15-removeAttribute(String name):從請求范圍內刪除一個屬性。

f)HttpServletRequest接口

HttpServletRequest接口是ServletRequest接口的子接口。HttpServlet類重載service方法及doGet,doPost都有一個該類型參數。

HttpServletRequest接口提供瞭用於讀取HTTP請求中相關信息的方法

以https://localhost:8080/helloapp/infoname=jack為例

1-getContextPath: 返回客戶端所請求訪問的web應用的URL入口。即/helloapp

2-getCookies():返回HTTP請求中所有Cookie

3-getHeader(String name):返回HTTP請求頭部的特定項

4-getHeaderNames():返回一個Enumeration對象,包含瞭HTTP請求頭部所有項目名

5-getMethod:返回HTTP請求方式

6-getRequestURI():返回HTTP請求的頭部的第一行中的URI。/helloapp/infoname=jack

7-getQueryString():返回HTTP請求中的查詢字符串。即name=jack

案例:使用以上方法

g)ServletResponse接口

Servlet接口的service(ServletRequestreq, ServletResponse resp),含有ServletResponse類型。Servlet通過ServletResponse對象生成響應結果(主要生成HTTP響應結果的正文部分)。

Servlet容器接收到客戶端要求訪問特定Servlet請求時,容器會創建一個ServletResponse對象,並把它作為參數傳給Servlet的service方法。

ServletResponse接口定義瞭一系列與生成響應結果相關的方法。

1-setCharacterEncoding(String charset): 設置響應正文的字符編碼。默認響應正文字符編碼為ISO-8859-1

2-setContentLength(int len): 設置響應正文的長度

3-setContentType(String type):設置響應正文的MIME類型

4-getCharacterEncoding():返回響應正文的字符編碼

5-getContentType():返回響應正文的MIME類型

6-setBufferSize(int size):設置用於存放響應正文數據的緩沖區大小

7-getBufferSize():獲得用於存放響應正文數據的緩沖區大小

8-reset():清空緩沖區內的正文數據,並且清空響應狀態代碼及響應頭

9-resetBuffer():僅僅清空緩沖區內的響應正文數據,不清空響應狀態代碼及響應頭

10-flushBuffer():強制性把緩沖區內的響應正文數據發送到客戶端

11-isCommitted():返回一個boolean類型的值。true表示緩沖區內的數據已經提交給客戶。即數據已經發送到客戶端。

12-getOutputStream():返回一個ServletOutputStream對象,Servlet用它輸出二進制的正文數據

13-getWriter():返回一個PrintWriter對象,servlet用它輸出字符串形式的正文數據。

註意:

1-提高輸出數據效率,ServletOutputStream和PrintWriter先把數據寫到緩沖區內。tomcat在調用完Servlet的service方法後,會關閉以上兩個對象,確保Servlet輸出的所有數據被提交給客戶。

2-ServletResponse響應正文默認MIME類型為text/plain(純文本類型)。HttpServletResponse響應正文默認的MIME類型為text/html(html文檔類型)。

3-設置響應正文的MIME類型和字符編碼時,必須先調用setContentType()和setCharacterEncoding方法,然後再調用ServletResponse的getOutputStream或getWriter方法,或提交緩沖區內的正文數據。滿足這樣順序,設置才能生效。

h)HttpServletResponse接口

HttpServletResponse接口是ServletResponse接口的子接口。HttpServlet類重載service方法及doGet,doPost都有一個該類型參數。

HttpServletResponse接口提供瞭與HTTP協議相關的方法。Servlet可通過這些方法設置HTTP響應頭或向客戶端寫Cookie。

1-addHeader(String name, String value):向HTTP響應頭加入一項內容

2-sendError(int sc):向客戶端發送一個代表特定錯誤的HTTP響應狀態代碼

3-sendError(int sc, String msg):向客戶端發送一個代表特定錯誤的HTTP響應狀態代碼,並且發送具體錯誤信息

4-setHeader(String name, String value):設置HTTP響應頭中一項內容。如果響應頭已經存在這項內容,原設置將被覆蓋

5-setStatus(int sc):設置HTTP響應的狀態代碼

6-addCookie(Cookie cookie):向HTTP響應中加入一個Cookie。

案例演示:

註意:設置HTTP響應正文的MIME類型及字符編碼三種方式

1 response.setContentType(“text/html;charset=GB2312”);

2 response.setContentType(“text/html”);

response.setContentType(“GB2312”);或setCharacterEncoding(“GBK”);

3 response.setHeader(“Content-type”,“text/html;charset=GB2312”);

i)ServletConfig接口

Servlet接口的init(ServletConfigconfig)方法含有ServletConfig類型的參數。

Servlet容器初始化一個Servlet對象時,會為該Servlet對象創建一個ServletConfig對象。Servlet容器在調用Servlet對象的init(ServletConfigconfig)方法時,會把ServletConfig對象作為參數傳給Servlet對象。init(ServletConfig config)方法使得當前Servlet對象與ServletConfig對象之間建立關聯關系。

ServletConfig對象中包含瞭Servlet初始化參數信息,此外該對象與當前Web應用的ServletContext對象關聯。1、獲得Servlet初始化參數信息;2、得到ServletContext對象

ServletConfig接口定義的方法

1-getInitParameter(String name)根據給定的初始化參數名,返回匹配的初始化參數值

2-getInitParameterNames():返回一個Enumeration對象,裡面包含瞭所有的初始化參數名。

3-getServletContext():返回一個ServletContext對象。

4-getServletName():返回Servlet的名字,即web.xml档案中相應的的值。如果沒有配置,則返回Servlet類的名字

在中,通過元素設置初始化參數。設置參數名,設置參數值

HttpServlet類繼承GenericServlet類,GenericServlet類實現瞭ServletConfig接口,因此在HttpServlet或GenericServlet類及其子類中可以直接調用ServletConfig方法。

j)ServletContext接口

ServletContext是Servlet與Servlet容器之間直接通信的接口。

ServletContext在容器在啟動一個Web應用時,會為它創建一個ServletContext對象。

每個Web應用有且僅有一個ServletContext對象,同一個Web應用中的所有Servlet對象都共享該對象。可以通過該對象訪問容器中的各種資源。

ServletContext接口提供以下幾種類型方法

在web應用范圍內存取共享數據的方法:

1-setAttribute(String name, Object object):把一個Java對象與一個屬性名綁定,並把它存入到ServletContext中。name為屬性名,object表示共享數據

2-getAttribute(String name):根據屬性名,返回一個Object類型的對象。不存在,返回null。

3-getAttributeNames():返回一個Enumeration對象,該對象包含瞭所有存放在ServletContext中的屬性名。

4-removeAttribute(String name): 根據參數指定的屬性名,從ServletContext中刪除匹配的屬性。

訪問當前Web應用的資源

1-getContextPath():返回當前Web應用的URL入口 /hello

2-getInitParameter(String name):根據給定的參數名,返回Web應用范圍內的匹配的初始化參數值。在web.xml中,直接在根元素下定義的元素表示應用范圍內的初始化參數。

3-getInitParameterNames():返回一個Enumeration對象,包含瞭Web應用范圍內的所有初始化參數名

4-getServletContextName():返回Web應用的名字。即在web.xml中元素的值。

5-getRequestDispatcher(String path): 返回一個用於向其他Web組件轉發請求的RequestDispatcher對象

訪問Servlet容器中其他Web應用

1-getContext(String uripath):根據參數指定URI,返回當前Servlet容器中其他Web應用的ServletContext對象

訪問Servlet容器的相關信息

1-getMajorVersion():返回Servlet容器支援的Java Servlet API的主版本號。

2-getMinorVersion():返回Servlet容器支援的Java Servlet API的次版本號

3-getServletInfo():返回Servlet容器的名字和版本。

訪問服務器端的档案系統資源

1-getRealPath(String path):根據參數指定的虛擬路徑,返回档案系統中一個資源的真實的路徑。

如webapps下有hello應用,hello應用中有db.conf档案。通過該方法path=/db.conf。可以獲得絕對路徑…/webapps/hello/db.conf此時/表示當前web應用。

path=/WEB-INF/web.xml /表示當前應用。

2-getResource(String path):返回一個映射到參數指定的路徑的URI

3-getResourceAsStream(String path): 返回一個用於讀取參數指定的档案的輸入流。比如path=”/WEB-INF/web.xml” /表示當前web應用入口,對象可以讀取指定档案的數據。

4-getMimeType(String file):返回參數指定的档案的MIME類型

輸出日志

1-log(String msg):向Servlet日志档案中寫日志

2-log(String message, Throwable throwable):向Servlet的日志档案中寫錯誤日志,以及異常的堆棧信息

在HttpServlet,GenericServlet類及其子類中可以直接調用getServletContext()方法得到當前Web應用的ServletContext對象。

案例:以流的形式獲取資源的方法總結

在實際操作中,經常以IO流的方式讀取档案系統中的档案信息。除瞭IO流,還有其他方式在JavaSE或JavaWeb中可以使用。

以流的形式讀取档案系統中的資源,最主要的是指定的路徑能被讀取對象找到。

javaSE

//1- 直接使用IO流對象讀取即可。

//2- 通過getResourceAsStream方法 以下使用的都是相對路徑

// 路徑 /xxx档案。 表示當前相對位置bin目錄。

//InputStream is1 = Test.class.getResourceAsStream("/web.xml");

//當前目錄 與當前類對應的.class所在的目錄相同。

//InputStream is11 = Test.class.getResourceAsStream("web.xml");

//3- 不能以/開頭, 如下所示, 當前目錄就是bin目錄。

InputStream is2 = Test.class.getClassLoader().getResourceAsStream("web.xml");

javaWeb (開發中經常遇到,加載classes下的、WebRoot下的以及當前類档案夾下的配置档案,需熟悉)

//相對的目錄時classes。

//InputStream is1 = Test.class.getResourceAsStream("/web.xml");

//當前目錄為與當前類的.class档案所在目錄相同。

InputStream is2 = Test.class.getResourceAsStream("web.xml");

//相對目錄是classes

InputStream is3 = Test.class.getClassLoader().getResourceAsStream("web.xml");

//相對目錄為當前Web應用的入口。

InputStream is4 = this.getServletContext().getResourceAsStream("/WEB-INF/classes/web.xml");

JavaWe應用的生命周期

JavaWeb應用的生命周期是由Servlet容器控制。包括啟動階段,運行時階段,終止階段。

a.啟動階段

Servlet容器啟動JavaWeb應用時,完成以下任務

(1)把web.xml档案中數據加載到內存中

(2)為JavaWeb應用創建一個ServletContext對象

(3)對所有的Filter進行初始化(以後講解)

(4)對需要在Web應用啟動時就被初始化的Servlet進行初始化。配置

b.運行時階段

JavaWeb應用最主要的生命階段。隨時響應客戶端的特定請求,提供相應服務。如果請求的Servlet對象還不存在,Servlet容器會先初始化Servlet,然後再調用它的service服務方法。

c.終止階段

Servlet容器在終止JavaWeb應用時,完成以下任務:

(a)銷毀JavaWeb應用中所有處於運行時狀態的Servlet。

(b)銷毀JavaWeb應用中所有處於運行時狀態的Filter。

(c)銷毀所有與JavaWeb應用相關的對象。如ServletContext對象,且釋放Web應用所占用的相關資源。

Web應用隨著Servlet容器啟動而啟動,運行而運行,終止而終止。Tomcat作為Servlet容器的具體實現,提供瞭一個管理平臺,用戶可以手動管理單個Web應用的生命周期。

演示:用Tomcat管理平臺管理Web應用的生命周期

步驟:配置tomcat-users.xml,啟動tomcat,訪問進入管理平臺。

註意:元素有一個reloadable屬性,如果為true,Tomcat在運行時會監視Web應用中WEN-INF/classes,WEB-INF/lib目錄下類档案的改動以及監視Web應用的WEB-INF/web.xml档案的改動。如果監測到類档案或web.xml档案被更新,tomcat則會重新啟動Web應用。該屬性默認為false。一般在Web應用的開發和調試階段,為瞭方便Web應用的調試,reloadable設置true。Web應用正式發佈階段,設置false,降低tomcat運行負荷,提高Tomcat的運行性能。

2Servlet生命周期,(面試題!)

JavaWeb應用的生命周期由Servlet容器控制,而Servlet作為JavaWeb應用的最核心組件,其生命周期也由Servlet容器控制。

Servlet生命周期分為三個階段:初始化階段,運行時階段,銷毀階段。在Servlet接口中定義瞭三個方法init, service, destroy,分別在Servlet不同階段被Servlet容器調用。

a.初始化階段

(1)Servlet容器加載Servlet類,把它的.class档案中的數據讀入到內存中。

(2)Servlet容器創建ServletConfig對象。建立ServletConfig對象與當前Web應用的ServletContext對象關聯。

(3)Servlet容器創建Servlet對象

(4)Servlet容器調用Servlet對象的init(ServletConfig config)方法。建立Servlet對象與ServletConfig對象的關聯關系

以下情況下,Servlet進入初始化階段

當前Web應用處於運行時階段,特定Servlet被客戶端首次請求訪問。多數Servlet都會在這種情況下被Servlet容器初始化。

如果在web.xml档案中為一個servlet設置瞭元素,那麼當Servlet容器啟動Servlet所屬的Web應用時,就會初始化這個Servlet。

當Web應用被重新啟動時,Web應用中的所有Servlet都會在特定時刻重新初始化。

b.運行時階段

Servlet生命周期最重要的階段。此時Servlet可以隨時響應客戶端請求。當Servlet容器接收到要求訪問特定Servlet的客戶請求時,Servlet容器會創建針對這個請求的ServletRequest對象和ServletResponse對象,然後調用相應Servlet對象的service()方法。service()方法從ServletRequest對象中獲得客戶請求信息並處理該請求,再通過ServletResponse對象生成響應結果。當Servlet容器把Servlet生成的響應結果發送給客戶,Servlet容器就會銷毀ServletRequest對象和ServletResponse對象。

c.銷毀階段

當Web應用被終止時,Servlet容器會先調用Web應用中所有Servlet對象的destroy()方法,然後再銷毀這些Servlet對象。容器還會銷毀與Servlet對象關聯的ServletConfig對象。

一般在destroy()方法中,可以釋放Servlet占用的資源,比如關閉档案輸入流和輸出流,關閉與數據庫的連接等。

演示Servlet生命周期

在Servlet生命周期中,Servlet初始化,銷毀隻發生一次,因此init()和destroy()方法隻會被Servlet容器調用一次,而service()方法可能會被Servlet容器調用多次,取決於客戶端請求訪問Servlet次數。

3ServletContext與Web應用范圍共享

ServletContext對象與Web應用的生命周期相同,且ServletContext對象可以被Web應用中的所有Web組件共享,因此可以使用ServletContext對象實現Web應用范圍內的共享數據。

ServletContext接口中用於存取共享數據的方法:

setAttribute(String name, Object object):向WEB應用范圍內存入共享數據。

共享數據存放在object,且該對象生命周期依附於ServletContext對象的生命周期,且Web組件可以通過ServletContext對象訪問。

removeAttribute(String name):根據參數給定屬性名,從Web應用范圍內刪除匹配的共享數據。

getAttribute(String name):根據參數給定的屬性名,返回Web應用范圍內匹配的共享數據

案例:web應用范圍內存放共享數據

4ServletContextListener監聽器

ServletContextListener接口,能夠監聽ServletContext對象的生命周期,實際也是監聽Web應用的生命周期

當Servlet容器啟動或終止Web應用時,會觸發ServletContextEvent事件,該事件由ServletContextListener處理。

ServletContextListener接口定義瞭處理ServletContextEvent事件的兩個方法:

contextInitialized(ServletContextEvent sce):Servlet容器啟動Web應用時調用該方法。該方法調用完後,容器再對Filter初始化,且對Web啟動時就需要被初始化的Servlet進行初始化。

contextDestroyed(ServletContextEvent sce): 當Servlet容器終止Web應用時,調用該方法。在調用該方法之前,容器會先銷毀所有的Servlet和Filter。

每次,如果重新啟動Web應用,計數器都會重新從1開始統計訪問次數。實際應用中,往往需要統計自Web應用發佈後,網頁被客戶端訪問的次數。這需要Web應用每次被終止時,計數器數值被永久存儲在一個档案或數據庫中,等到Web重新啟動時,先從档案或數據庫中讀取計數器的值,再繼續計數。

案例演示:

可以看出Web應用啟動時,Servlet容器先調用MyServletContextListener的contextInitialized方法,再創建,初始化Servlet對象;Web應用終止時,Servlet容器先調用Servlet的destroy方法,再調用MyServletContextListener的contextDestroyed方法。由此可知,Web應用的生命周期中,ServletContext對象最早創建,最晚銷毀。

5Servlet服務方法拋出異常

Servlet接口的service方法完整定義如下:

publicvoid service(ServletRequest req, ServletResponse res)

throws ServletException, IOException;

該方法聲明拋出兩個異常:

ServletException:表示當Servlet進行常規操作時出現的異常

IOException:表示當Servlet進行IO操作時出現的異常

UnavailableException:ServletException子類,表示無法訪問當前Servlet異常。如果Servlet由於一些系統級別原因(內存不足或無法訪問第三方服務器(DB服務器))不能響應客戶請求,就拋出該異常。

Servlet的service()方法拋出的異常由Servlet容器捕獲,Servlet容器在捕獲到異常後,會向客戶端發送相應錯誤信息。

6防止頁面被客戶端緩存(***重要***)

客戶端緩存:瀏覽器為瞭能快速向用戶展示請求頁面,會將服務器端的網頁存放到客戶端緩存中。多次請求訪問服務器端同一網頁,隻需從緩存中獲取該網頁即可。

瀏覽器緩存技術適用於保存服務器端的靜態網頁,以及不含敏感數據的網頁。下面兩種情形,服務器不希望網頁被客戶端緩存。

網頁包含隨時被更新的動態內容。此時如果瀏覽器讀取緩存網頁,可能展示的是過期網頁。

網頁中含有敏感數據。比如銀行賬號信息或電子郵件內容,如果瀏覽器把網頁保存在本地緩存中,可能被其他未授權的用戶訪問。

服務器端禁止瀏覽器緩存網頁,可通過HttpServletResponse對象設置特定HTTP響應頭實現。

response.addHeader(“Pragma”, “no-cache”);

response.setHeader(“Cache-Control”, “no-cache”);

response.setHeader(“Expires”, “0”);

註意:

“Pragma”適用於采用HTTP1.0瀏覽器。

“Cache-Control” 在HTTP1.1中用來決定客戶端是否可以緩存網頁,如果取值no-cache,客戶端不會把Servlet生成的網頁保存在本地緩存。

“Expires” HTTP1.0和HTTP1.1都支援,因此所有瀏覽器都識別該選項。Expires用於設置網頁過期時間,如果為0,表示立即過期。用戶每次重復請求訪問該網頁,瀏覽器每次都從服務器端獲取最新的網頁。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。