servlet詳解(第一篇)
servlet基本概述
生命週期方法:
void init(ServletConfig):出生之後(1次);
void service(ServletRequest request, ServletResponse response):每次處理請求時都會被呼叫;
void destroy():臨死之前(1次);
特性:
單例,一個類只有一個物件;當然可能存在多個Servlet類!
執行緒不案例的,所以它的效率是高的!
Servlet類由我們來寫,但物件由伺服器來建立,並且由伺服器來呼叫相應的方法。
1 什麼是Servlet
Servlet是JavaWeb的三大元件之一,它屬於動態資源。Servlet的作用是處理請求,伺服器會把接收到的請求交給Servlet來處理,在Servlet中通常需要:
接收請求資料;
處理請求;
完成響應。
例如:客戶端發出登入請求,或者輸出註冊請求,這些請求都應該由Servlet來完成處理!Servlet需要我們自己來編寫,每個Servlet必須實現javax.servlet.Servlet介面。
2 實現Servlet的方式(由我們自己來寫!)
實現Servlet有三種方式:
實現javax.servlet.Servlet介面;
繼承javax.servlet.GenericServlet類;
繼承javax.servlet.http.HttpServlet類;
通常我們會去繼承HttpServlet類來完成我們的Servlet,但學習Servlet還要從javax.servlet.Servlet介面開始學習
public interface Servlet [Servlet中的方法大多數不由我們來呼叫,而是由Tomcat來呼叫。並且Servlet的物件也不由我們來建立,由Tomcat來建立!]{
public void init(ServletConfig
public ServletConfig getServletCconfig) throws ServletException;onfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
3 建立helloservlet應用
我們開始第一個Servlet應用吧!首先在webapps目錄下建立helloservlet目錄,它就是我們的應用目錄了,然後在helloservlet目錄中建立準備JavaWeb應用所需內容:
建立/helloservlet/WEB-INF目錄;
建立/helloservlet/WEB-INF/classes目錄;
建立/helloservlet/WEB-INF/lib目錄;
建立/helloservlet/WEB-INF/web.xml檔案;
接下來我們開始準備完成Servlet,完成Servlet需要分為兩步:
編寫Servlet類;
在web.xml檔案中配置Servlet;
HelloServlet.java
public class HelloServlet implements Servlet {
public void init(ServletConfig config) throws ServletException {}
public ServletConfig getServletConfig() {return null;}
public void destroy() {}
public String getServletInfo() {return null;}
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
System.out.println("hello servlet!");
}
}
web.xml
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>cn.itcast.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/helloworld</url-pattern>
</servlet-mapping>
web.xml中配置servlet詳解
在web.xml中配置Servlet的目的其實只有一個,就是把訪問路徑與一個Servlet繫結到一起,上面配置是把訪問路徑:“/helloworld”與“cn.itcast.servlet.HelloServlet”繫結到一起。
<servlet>:指定HelloServlet這個Servlet的名稱為hello;
<servlet-mapping>:指定/helloworld訪問路徑所以訪問的Servlet名為hello。
<servlet>和<servlet-mapping>通過<servlet-name>這個元素關聯在一起了!
接下來,我們編譯HelloServlet,注意,編譯HelloServlet時需要匯入servlet-api.jar,因為Servlet.class等類都在servlet-api.jar中。
javac -classpath F:/tomcat6/lib/servlet-api.jar -d . HelloServlet.java
然後把HelloServlet.class放到/helloworld/WEB-INF/classes/目錄下,然後啟動Tomcat,在瀏覽器中訪問:http://localhost:8080/helloservlet/helloworld即可在控制檯上看到輸出!
/helloservlet/WEB-INF/classes/cn/itcast/servlet/HelloServlet.class;
servlet介面詳解
1Servlet的生命週期
所謂xxx的生命週期,就是說xxx的出生、服務,以及死亡。Servlet生命週期也是如此!與Servlet的生命週期相關的方法有:
void init(ServletConfig);
void service(ServletRequest,ServletResponse);
void destroy();
1.1 Servlet的出生
伺服器會在Servlet第一次被訪問時建立Servlet,或者是在伺服器啟動時建立Servlet。如果伺服器啟動時就建立Servlet,那麼還需要在web.xml檔案中配置。也就是說預設情況下,Servlet是在第一次被訪問時由伺服器建立的。
而且一個Servlet型別,伺服器只建立一個例項物件,例如在我們首次訪問http://localhost:8080/helloservlet/helloworld時,伺服器通過“/helloworld”找到了繫結的Servlet名稱為cn.itcast.servlet.HelloServlet,然後伺服器檢視這個型別的Servlet是否已經建立過,如果沒有建立過,那麼伺服器才會通過反射來建立HelloServlet的例項。當我們再次訪問http://localhost:8080/helloservlet/helloworld時,伺服器就不會再次建立HelloServlet例項了,而是直接使用上次建立的例項。
在Servlet被建立後,伺服器會馬上呼叫Servlet的void init(ServletConfig)方法。請記住, Servlet出生後馬上就會呼叫init()方法,而且一個Servlet的一生。這個方法只會被呼叫一次。這好比小孩子出生後馬上就要去剪臍帶一樣,而且剪臍帶一生只有一次。
我們可以把一些對Servlet的初始化工作放到init方法中!
1.2 Servlet服務
當伺服器每次接收到請求時,都會去呼叫Servlet的service()方法來處理請求。伺服器接收到一次請求,就會呼叫service() 方法一次,所以service()方法是會被呼叫多次的。正因為如此,所以我們才需要把處理請求的程式碼寫到service()方法中!
1.3 Servlet的離去
Servlet是不會輕易離去的,通常都是在伺服器關閉時Servlet才會離去!在伺服器被關閉時,伺服器會去銷燬Servlet,在銷燬Servlet之前伺服器會先去呼叫Servlet的destroy()方法,我們可以把Servlet的臨終遺言放到destroy()方法中,例如對某些資源的釋放等程式碼放到destroy()方法中。
2 Servlet介面相關型別
在Servlet介面中還存在三個我們不熟悉的型別:
ServletRequest:service() 方法的引數,它表示請求物件,它封裝了所有與請求相關的資料,它是由伺服器建立的;
ServletResponse:service()方法的引數,它表示響應物件,在service()方法中完成對客戶端的響應需要使用這個物件;
ServletConfig:init()方法的引數,它表示Servlet配置物件,它對應Servlet的配置資訊,那對應web.xml檔案中的元素。
2.1 ServletRequest和ServletResponse詳解
ServletRequest和ServletResponse是Servlet#service() 方法的兩個引數,一個是請求物件,一個是響應物件,可以從ServletRequest物件中獲取請求資料,可以使用ServletResponse物件完成響應。你以後會發現,這兩個物件就像是一對恩愛的夫妻,永遠不分離,總是成對出現。
ServletRequest和ServletResponse的例項由伺服器建立,然後傳遞給service()方法。如果在service() 方法中希望使用HTTP相關的功能,那麼可以把ServletRequest和ServletResponse強轉成HttpServletRequest和HttpServletResponse。這也說明我們經常需要在service()方法中對ServletRequest和ServletResponse進行強轉,這是很心煩的事情。不過後面會有一個類來幫我們解決這一問題的。
HttpServletRequest方法:
string getParameter(String paramName):獲取指定請求引數的值;
String getMethod():獲取請求方法,例如GET或POST;
String getHeader(String name):獲取指定請求頭的值;
void setCharacterEncoding(String encoding):設定請求體的編
碼!因為GET請求沒有請求體,所以這個方法只只對POST請求有效。當呼叫request.setCharacterEncoding(“utf-8”)之後,再通過getParameter()方法獲取引數值時,那麼引數值都已經通過了轉碼,即轉換成了UTF-8編碼。所以,這個方法必須在呼叫getParameter()方法之前呼叫!
HttpServletResponse方法:
PrintWriter getWriter():獲取字元響應流,使用該流可以向客戶端輸出響應資訊。例如response.getWriter().print(“<h1>Hello JavaWeb!</h1>”);
ServletOutputStream getOutputStream():獲取位元組響應流,當需要向客戶端響應位元組資料時,需要使用這個流,例如要向客戶端響應圖片;
void setCharacterEncoding(String encoding):用來設定字元響應流的編碼,例如在呼叫setCharacterEncoding(“utf-8”);之後,再response.getWriter()獲取字元響應流物件,這時的響應流的編碼為utf-8,使用response.getWriter()輸出的中文都會轉換成utf-8編碼後傳送給客戶端;
void setHeader(String name, String value):向客戶端新增響應頭資訊,例如setHeader(“Refresh”, “3;url=http://www.itcast.cn”),表示3秒後自動重新整理到http://www.itcast.cn;
void setContentType(String contentType):該方法是setHeader(“content-type”, “xxx”)的簡便方法,即用來新增名為content-type響應頭的方法。content-type響應頭用來設定響應資料的MIME型別,例如要向客戶端響應jpg的圖片,那麼可以setContentType(“image/jepg”),如果響應資料為文字型別,那麼還要臺同時設定編碼,例如setContentType(“text/html;chartset=utf-8”)表示響應資料型別為文字型別中的html型別,並且該方法會呼叫setCharacterEncoding(“utf-8”)方法;
void sendError(int code, String errorMsg):向客戶端傳送狀態碼,以及錯誤訊息。例如給客戶端傳送404:response(404, “您要查詢的資源不存在!”)。
2.2 ServletConfig
ServletConfig物件對應web.xml檔案中的元素。例如你想獲取當前Servlet在web.xml檔案中的配置名,那麼可以使用servletConfig.getServletName()方法獲取!
ServletConfig物件是由伺服器建立的,然後傳遞給Servlet的init()方法,你可以在init()方法中使用它!
String getServletName():獲取Servlet在web.xml檔案中的配置名稱,即指定的名稱;
ServletContext getServletContext():用來獲取ServletContext物件,ServletContext會在後面講解;
String getInitParameter(String name):用來獲取在web.xml中配置的初始化引數,通過引數名來獲取引數值;
Enumeration getInitParameterNames():用來獲取在web.xml中配置的所有初始化引數名稱;
GenericServlet
GenericServlet是Servlet介面的實現類,我們可以通過繼承GenericServlet來編寫自己的Servlet。下面是GenericServlet類的原始碼:
GenericServlet.java
public abstract class GenericServlet implements Servlet, ServletConfig,
java.io.Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() {}
@Override
public void destroy() {}
@Override
public String getInitParameter(String name) {
return getServletConfig().getInitParameter(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return getServletConfig().getInitParameterNames();
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public ServletContext getServletContext() {
return getServletConfig().getServletContext();
}
@Override
public String getServletInfo() {
return "";
}
@Override
public void init[實現了Servlet的init(ServletConfig)方法,把引數config賦給了本類的成員config,然後再呼叫本類自己的無參的init()方法。](ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init[這個方法是GenericServlet自己的方法,而不是從Servlet繼承下來的。當我們自定義Servlet時,如果想完成初始化作用就不要再重複init(ServletConfig)方法了,而是應該去重寫init()方法。因為在GenericServlet中的init(ServletConfig)方法中儲存了ServletConfig物件,如果覆蓋了儲存ServletConfig的程式碼,那麼就不能再使用ServletConfig了。]() throws ServletException {}
public void log(String msg) {
getServletContext().log(getServletName() + ": " + msg);
}
public void log(String message, Throwable t) {
getServletContext().log(getServletName() + ": " + message, t);
}
@Override
public abstract void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
@Override
public String getServletName() {
return config.getServletName();
}
}
2 GenericServlet的init()方法
在GenericServlet中,定義了一個ServletConfig config例項變數,並在init(ServletConfig)方法中把引數ServletConfig賦給了例項變數。然後在該類的很多方法中使用了例項變數config。
如果子類覆蓋了GenericServlet的init(StringConfig)方法,那麼this.config=config這一條語句就會被覆蓋了,也就是說GenericServlet的例項變數config的值為null,那麼所有依賴config的方法都不能使用了。如果真的希望完成一些初始化操作,那麼去覆蓋GenericServlet提供的init()方法,它是沒有引數的init()方法,它會在init(ServletConfig)方法中被呼叫。
3 實現了ServletConfig介面
GenericServlet還實現了ServletConfig介面,所以可以直接呼叫getInitParameter()、getServletContext()等ServletConfig的方法。
HttpServlet(從事javaweb開發的重點)
上面說了servlet介面和GenericServlet都只是httpservlet的父類和父介面,從事web網站開發的人大部分用到的是httpservlrt這個類,下面是這個類的詳解
1 HttpServlet概述
HttpServlet類是GenericServlet的子類,它提供了對HTTP請求的特殊支援,所以通常我們都會通過繼承HttpServlet來完成自定義的Servlet。
2 HttpServlet覆蓋了service()方法
HttpServlet類中提供service(HttpServletRequest,HttpServletResponse)方法,這個方法是HttpServlet自己的方法,不是從Servlet繼承來的。在HttpServlet的service(ServletRequest,ServletResponse)方法中會把ServletRequest和ServletResponse強轉成HttpServletRequest和HttpServletResponse,然後呼叫service(HttpServletRequest,HttpServletResponse)方法,這說明子類可以去覆蓋service(HttpServletRequest,HttpServletResponse)方法即可,這就不用自己去強轉請求和響應物件了。
3 doGet()和doPost()
在HttpServlet的service(HttpServletRequest,HttpServletResponse)方法會去判斷當前請求是GET還是POST,如果是GET請求,那麼會去呼叫本類的doGet()方法,如果是POST請求會去呼叫doPost()方法,這說明我們在子類中去覆蓋doGet()或doPost()方法即可。
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("hello doGet()...");
}
}
public class BServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("hello doPost()...");
}
}
Servlet其他細節
不要在Servlet中建立成員!建立區域性變數即可!
可以建立無狀態成員!
可以建立有狀態的成員,但狀態必須為只讀的!
1 Servlet與執行緒安全
因為一個型別的Servlet只有一個例項物件,那麼就有可能會現時出一個Servlet同時處理多個請求,那麼Servlet是否為執行緒安全的呢?答案是:“不是執行緒安全的”。這說明Servlet的工作效率很高,但也存線上程安全問題!
所以我們不應該在Servlet中便宜建立成員變數,因為可能會存在一個執行緒對這個成員變數進行寫操作,另一個執行緒對這個成員變數進行讀操作。
2 讓伺服器在啟動時就建立Servlet
預設情況下,伺服器會在某個Servlet第一次收到請求時建立它。也可以在web.xml中對Servlet進行配置,使伺服器啟動時就建立Servlet。
<servlet>
<servlet-name>hello1</servlet-name>
<servlet-class>cn.itcast.servlet.Hello1Servlet</servlet-class>
<load-on-startup>0</load-on-startup>[在<servlet>中配置<load-on-startup>,其中給出一個非負整數!]
</servlet>
<servlet-mapping>
<servlet-name>hello1</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>hello2</servlet-name>
<servlet-class>cn.itcast.servlet.Hello2Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello2</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>hello3</servlet-name>
<servlet-class>cn.itcast.servlet.Hello3Servlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello3</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
在<servlet>元素中配置<load-on-startup>元素可以讓伺服器在啟動時就建立該Servlet,其中<load-on-startup>元素的值必須是大於等於的整數,它的使用是伺服器啟動時建立Servlet的順序。上例中,根據<load-on-startup>的值可以得知伺服器建立Servlet的順序為Hello1Servlet、Hello2Servlet、Hello3Servlet。
3url-pattern>
是的子元素,用來指定Servlet的訪問路徑,即URL。它必須是以“/”開頭!
1)可以在中給出多個,例如:
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
<url-pattern>/BServlet</url-pattern>
</servlet-mapping>
那麼這說明一個Servlet綁定了兩個URL,無論訪問/AServlet還是/BServlet,訪問的都是AServlet。
2)還可以在中使用萬用字元,所謂萬用字元就是星號“*”,星號可以匹配任何URL字首或字尾,使用萬用字元可以命名一個Servlet繫結一組URL,例如:
<url-pattern>/servlet/*[路徑匹配]<url-patter>:/servlet/a、/servlet/b,都匹配/servlet/*;
<url-pattern>*.do[副檔名匹配]</url-pattern>:/abc/def/ghi.do、/a.do,都匹配*.do;
<url-pattern>/*[啥都匹配]<url-pattern>:匹配所有URL;
請注意,萬用字元要麼為字首,要麼為字尾,不能出現在URL中間位置,也不能只有萬用字元。例如:/.do就是錯誤的,因為星號出現在URL的中間位置上了。.*也是不對的,因為一個URL中最多隻能出現一個萬用字元。
4 web.xml檔案的繼承(瞭解)
在${CATALINA_HOME}\conf\web.xml中的內容,相當於寫到了每個專案的web.xml中,它是所有web.xml的父檔案。
每個完整的JavaWeb應用中都需要有web.xml,但我們不知道所有的web.xml檔案都有一個共同的父檔案,它在Tomcat的conf/web.xml路徑。
conf/web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<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>default[它的優先順序最低,如果一個請求沒有人處理,那麼它來處理!它顯示404。]</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet[當訪問路徑不存在時,會執行該Servlet!其實我們在訪問index.html時也是在執行這個Servlet。 ]</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>[匹配所有URL,也就是說使用者訪問的URL路徑沒有匹配的頁面時,那麼執行的就是名為default的Servlet,即org.apache.catalina.servlets.DefaultServlet]
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>[任何URL字尾為jsp的訪問,都會執行名為jsp的Servlet,即org.apache.jasper.servlet.JspServlet]
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>[session的預設超時時間為30分鐘,後面講session時再深入。]
</session-config>
<!-- 這裡省略了大概4000多行的MIME型別的定義,這裡只給出兩種MIME型別的定義 -->
<mime-mapping>
<extension>bmp</extension>
<mime-type>image/bmp</mime-type>
</mime-mapping>
<mime-mapping>
<extension>htm</extension>
<mime-type>text/html</mime-type>
</mime-mapping>[MIME型別用來標識網路上資源的媒體型別,這裡舉例為bmp和html兩種MIME型別。]
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>[在應用的web.xml中如果沒有對<welcome-file-list>進行覆蓋,那麼預設主頁為index.html、index.html、index.jsp]
</web-app>
ServletContext(重要)
一個專案只有一個ServletContext物件!
我們可以在N多個Servlet中來獲取這個唯一的物件,使用它可以給多個Servlet傳遞資料!
與天地同壽!!!這個物件在Tomcat啟動時就建立,在Tomcat關閉時才會死去!
1 ServletContext概述
伺服器會為每個應用建立一個ServletContext物件:
ServletContext物件的建立是在伺服器啟動時完成的;
ServletContext物件的銷燬是在伺服器關閉時完成的。
ServletContext物件的作用是在整個Web應用的動態資源之間共享資料!例如在AServlet中向ServletContext物件中儲存一個值,然後在BServlet中就可以獲取這個值,這就是共享資料了。
2 獲取ServletContext
ServletConfig#getServletContext();
GenericServlet#getServletContext();
HttpSession#getServletContext()
ServletContextEvent#getServletContext()
在Servlet中獲取ServletContext物件:
在void init(ServletConfig config)中:ServletContext context = config.getServletContext();,ServletConfig類的getServletContext()方法可以用來獲取ServletContext物件;
在GenericeServlet或HttpServlet中獲取ServletContext物件:
GenericServlet類有getServletContext()方法,所以可以直接使用this.getServletContext()來獲取;
public class MyServlet implements Servlet {
public void init(ServletConfig config) {
ServletContext context = config.getServletContext();
}
…
}
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) {
ServletContext context = this.getServletContext();
}
}
3 域[域物件就是用來在多個Servlet中傳遞資料
域物件必須有要存資料功能
域物件必須要有取資料功能
域物件內部其實有一個Map]物件的功能
ServletContext是JavaWeb四大域物件之一:
PageContext;
ServletRequest;
HttpSession;
ServletContext;
所有域物件都有存取資料的功能,因為域物件內部有一個Map,用來儲存資料,下面是ServletContext物件用來操作資料的方法:
void setAttribute(String name, Object value):用來儲存一個物件,也可以稱之為儲存一個域屬性,例如:servletContext.setAttribute(“xxx”, “XXX”),在ServletContext中儲存了一個域屬性,域屬性名稱為xxx,域屬性的值為XXX。請注意,如果多次呼叫該方法,並且使用相同的name,那麼會覆蓋上一次的值,這一特性與Map相同;
Object getAttribute(String name):用來獲取ServletContext中的資料,當前在獲取之前需要先去儲存才行,例如:String value = (String)servletContext.getAttribute(“xxx”);,獲取名為xxx的域屬性;
void removeAttribute(String name):用來移除ServletContext中的域屬性,如果引數name指定的域屬性不存在,那麼本方法什麼都不做;
Enumeration getAttributeNames():獲取所有域屬性的名稱;
4 獲取應用初始化引數
Servlet也可以獲取初始化引數,但它是區域性的引數;也就是說,一個Servlet只能獲取自己的初始化引數,不能獲取別人的,即初始化引數只為一個Servlet準備!
可以配置公共的初始化引數,為所有Servlet而用!這需要使用ServletContext才能使用!
還可以使用ServletContext來獲取在web.xml檔案中配置的應用初始化引數!注意,應用初始化引數與Servlet初始化引數不同:
ServletContext context = this.getServletContext();[獲取ServletContext物件]
String value1 = context.getInitParameter("paramName1");
String value2 = context.getInitParameter("paramName2");
[通過引數名,獲取引數值] System.out.println(value1 + ", " + value2);
Enumeration names = context.getInitParameterNames();[獲取所有應用初始化引數名稱]
while(names.hasMoreElements()) {
System.out.println(names.nextElement());
}