(轉)JavaWeb學習之Servlet(四)----ServletConfig獲取配置信息、ServletContext的應用
【聲明】
歡迎轉載,但請保留文章原始出處→_→
文章來源:http://www.cnblogs.com/smyhvae/p/4140877.html
【正文】
一、ServletConfig:代表當前Servlet在web.xml中的配置信息(用的不多)
- String getServletName() -- 獲取當前Servlet在web.xml中配置的名字
- String getInitParameter(String name) -- 獲取當前Servlet指定名稱的初始化參數的值
- Enumeration getInitParameterNames() -- 獲取當前Servlet所有初始化參數的名字組成的枚舉
- ServletContext getServletContext() -- 獲取代表當前web應用的ServletContext對象
在Servlet的配置文件中,可以使用一個或多個<init-param>標簽為servlet配置一些初始化參數。
當servlet配置了初始化參數後,web容器在創建servlet實例對象時,會自動將這些初始化參數封裝到ServletConfig對象中,並在調用servlet的init方法時,將ServletConfig對象傳遞給servlet。進而,程序員通過ServletConfig對象就可以得到當前servlet的初始化參數信息。
這樣做的好處是:如果將數據庫信息、編碼方式等配置信息放在web.xml中,如果以後數據庫的用戶名、密碼改變了,則直接很方便地修改web.xml就行了,避免了直接修改源代碼的麻煩
代碼舉例:
新建一個名為ServletConfigTest的Servlet,然後在web.xml中的<servlet>標簽下,通過<init-param>標簽為這個servlet配置兩個初始化參數:
<servlet> <servlet-name>ServletConfigTest</servlet-name> <servlet-class>com.vae.servlet.ServletConfigTest</servlet-class> <init-param> <param-name>name1</param-name> <param-value>value1</param-value> </init-param> <init-param> <param-name>encode</param-name> <param-value>utf-8</param-value> </init-param></servlet>
然後在代碼中獲取上面的兩個參數。代碼實現如下:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 import java.util.Enumeration; 5 6 import javax.servlet.ServletConfig; 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 public class ServletConfigTest extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 17 ServletConfig config = this.getServletConfig(); //拿到init方法中的ServletConfig對象 18 19 // --獲取當前Servlet 在web.xml中配置的名稱(用的不多) 20 String sName = config.getServletName(); 21 System.out.println("當前Servlet 在web.xml中配置的名稱:"+sName); 22 23 // --獲取當前Servlet中配置的初始化參數(只能獲取一個)經常用到 24 // String value = config.getInitParameter("name2"); 25 // System.out.println(value); 26 27 // --獲取當前Servlet中配置的初始化參數(全部獲取)經常用到 28 Enumeration enumration = config.getInitParameterNames(); 29 while(enumration.hasMoreElements()){ 30 String name = (String) enumration.nextElement(); 31 String value = config.getInitParameter(name); 32 System.out.println(name+":"+value); 33 } 34 } 35 36 public void doPost(HttpServletRequest request, HttpServletResponse response) 37 throws ServletException, IOException { 38 doGet(request, response); 39 } 40 }
核心代碼是第17行,通過this.getServletConfig()方法拿到init方法中的ServletConfig對象,然後獲取配置信息。
運行程序,後臺打印日誌如下:
二、ServletContext:代表當前web應用(非常重要)
WEB容器在啟動時,它會為每個WEB應用程序都創建一個對應的ServletContext對象,它代表當前web應用。
ServletConfig對象中維護了ServletContext對象的引用,開發人員在編寫servlet時,可以通過ServletConfig.getServletContext方法獲得ServletContext對象。
由於一個WEB應用中的所有Servlet共享同一個ServletContext對象,因此Servlet對象之間可以通過ServletContext對象來實現通訊。ServletContext對象通常也被稱之為context域對象。
ServletContext的應用:
1.做為域對象可以在整個web應用範圍內共享數據。
這裏涉及到一些概念:
- 域對象:在一個可以被看見的範圍內共享數據用到對象
- 作用範圍:整個web應用範圍內共享數據
- 生命周期:當服務器啟動web應用加載後創建出ServletContext對象後,域產生。當web應用被移除出容器或服務器關閉,隨著web應用的銷毀域銷毀。
代碼舉例:
ServletTest01.java:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletContext; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 public class ServletTest01 extends HttpServlet { 12 13 public void doGet(HttpServletRequest request, HttpServletResponse response) 14 throws ServletException, IOException { 15 ServletContext context = this.getServletContext(); 16 context.setAttribute("name", "smyhvae"); 17 } 18 19 public void doPost(HttpServletRequest request, HttpServletResponse response) 20 throws ServletException, IOException { 21 doGet(request, response); 22 } 23 24 }
ServletTest02.java:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletContext; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 public class ServletTest02 extends HttpServlet { 12 13 public void doGet(HttpServletRequest request, HttpServletResponse response) 14 throws ServletException, IOException { 15 ServletContext context = this.getServletContext(); 16 String myName = (String) context.getAttribute("name"); 17 System.out.println(myName); 18 } 19 20 public void doPost(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 doGet(request, response); 23 } 24 25 }
我們在ServletTest01中給Context加一個參數name(16行),然後就能在ServletTest02中得到這個參數了(16行)。
context中常用的方法有:
- void setAttribute(String,Object);
- Object getAttribute(String);
- void removeAttribute(String);
2、獲取WEB應用的初始化參數
我們在第一段中,通過<init-param>標簽為某一個單獨的servlet加配置信息,這種配置信息在其他的Servlet中是無法訪問到的。可如果我們使用<context-param>標簽(與Servlet標簽並列)為整個Web應用配置屬性的話,那所有的Servlet就都能訪問裏面的參數了。例如:可以把數據庫的配置信息放在這裏。
這裏涉及到一些概念不要混淆:
- 請求參數 parameter --- 瀏覽器發送過來的請求中的參數信息
- 初始化參數 initparameter --- 在web.xml中為Servlet或ServletContext配置的初始化時帶有的基本參數
- 域屬性 attribute --- 四大作用域中存取的鍵值對
代碼舉例:
在web.xml中為整個web應用添加初始化參數:用戶名、密碼。代碼位置如下:
然後接下來我們在代碼中來獲取這些參數。代碼如下:
ServletTest03.java:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 import java.util.Enumeration; 5 6 import javax.servlet.ServletContext; 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 public class ServletTest03 extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 ServletContext context = this.getServletContext(); // 得到上下文對象 17 18 // 獲取單個的Context裏面的初始化參數 19 String value1 = context.getInitParameter("username"); 20 String value2 = context.getInitParameter("password"); 21 System.out.println(value1 + ";" + value2); 22 System.out.println(); 23 24 // 一次性獲取Context裏所有的初始化參數 25 Enumeration enumeration = context.getInitParameterNames(); 26 while (enumeration.hasMoreElements()) { 27 String name = (String) enumeration.nextElement(); 28 String value = context.getInitParameter(name); 29 System.out.println(name + ";" + value); 30 31 } 32 33 } 34 35 public void doPost(HttpServletRequest request, HttpServletResponse response) 36 throws ServletException, IOException { 37 doGet(request, response); 38 } 39 40 }
上面的代碼可以看到,我們可以通過context.getInitParameter()方法獲得初始化參數。
運行效果如下:
3、實現Servlet的轉發
這裏涉及到一些概念要區分:
- 請求重定向:302+Location(兩次請求兩次響應)
- 請求轉發:服務器內不進行資源流轉 (一次請求一次響應,來實現資源流轉)
註:上方括號中的內容是二者的區別。打個比方,假如你找我借錢,如果是請求重定向的話,那你再去找別人借;如果是請求轉發的話,那我去找別人借,然後再借給你。
代碼舉例:
ServletTest04.java實現請求轉發:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.RequestDispatcher; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 /** 12 * ServletContext實現請求轉發 13 */ 14 public class ServletTest04 extends HttpServlet { 15 16 public void doGet(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 RequestDispatcher dispatcher = this.getServletContext() 19 .getRequestDispatcher("/servlet/ServletTest05");// 參數中寫虛擬路徑 20 dispatcher.forward(request, response); // 執行完這一行代碼後,將會跳到ServletTest05中去執行。 21 22 } 23 24 public void doPost(HttpServletRequest request, HttpServletResponse response) 25 throws ServletException, IOException { 26 doGet(request, response); 27 } 28 29 }
通過19行代碼拿到轉發器dispatcher,這個轉發器指向ServletTest05(參數中寫虛擬路徑),然後一旦執行完20行代碼,就會跳到ServletTest05中去執行。
那麽ServletTest05.java的代碼如下:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 /** 11 * ServletContext實現請求轉發 12 */ 13 public class ServletTest05 extends HttpServlet { 14 15 public void doGet(HttpServletRequest request, HttpServletResponse response) 16 throws ServletException, IOException { 17 response.getWriter().write("10000yuan"); 18 } 19 20 public void doPost(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 doGet(request, response); 23 } 24 25 }
在瀏覽器中輸入url,效果如下:
4.加載資源文件:
我們先在WebRoot的根目錄下新建一個資源文件config.properties,這裏有一個問題需要註意:
4.1在Servlet中讀取資源文件時:
如果寫相對路徑或絕對路徑,這個路徑指的是【當前程序啟動的目錄下】裏面的路徑。所以,在web環境下,就是tomcat啟動的目錄即tomcat/bin,所以找不到資源。效果如下:
如果寫硬盤的路徑D:\\apache-tomcat-7.0.57\\webapps\\WebTest\\config.properties,可以找到資源,但是只要一換發布環境,這個硬盤路徑很可能是錯誤的,同樣不行。
為了解決這樣的問題,ServletContext提供了getRealPath方法,在這個方法中傳入一個路徑,這個方法的底層會在傳入的路徑的前面拼接當前web應用的硬盤路徑,從而得到當前資源的硬盤路徑,這種方式即使換了發布環境,方法的底層也能得到正確的web應用的路徑從而永遠都是正確的資源的路徑。代碼如下:
this.getServletContext().getRealPath("config.properties")
代碼舉例:
先在WebRoot的根目錄下新建一個文件為config.properties,裏面的參數如下:
config.properties:
username=smyhvae password=007
緊接著,新建一個Servlet,代碼如下:
ServletTest06.java:
1 package com.vae.servlet; 2 3 import java.io.FileReader; 4 import java.io.IOException; 5 import java.util.Properties; 6 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 public class ServletTest06 extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 Properties prop = new Properties(); // 註意導的包是import java.util.Properties; 17 prop.load(new FileReader(this.getServletContext().getRealPath("config.properties"))); 18 19 System.out.println(prop.getProperty("username")); 20 System.out.println(prop.getProperty("password")); 21 22 } 23 24 public void doPost(HttpServletRequest request, HttpServletResponse response) 25 throws ServletException, IOException { 26 doGet(request, response); 27 } 28 29 }
核心代碼是第17行中的this.getServletContext().getRealPath("config.properties")。
運行效果如下:
4.2 在很多情況下,Servlet中並不會處理大量的邏輯,而是直接調用其他的java代碼,那就涉及到了下面的這個問題:
如果在非Servlet環境下要讀取資源文件時可以采用類加載器加載文件的方式讀取資源:MyService.class.getClassLoader().getResource("../../../config.properties").getPath()
那現在getResource()裏面的路徑該怎麽寫呢?只要記住一句話:類加載器從哪裏加載類,就從哪裏加載資源。這句話有點抽象,我們還是通過代碼來看吧:
新建一個Servlet類:
ServletTest07.java:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 import com.vae.service.MyService; 11 12 public class ServletTest07 extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 MyService service = new MyService(); 17 service.method(); 18 } 19 20 public void doPost(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 doGet(request, response); 23 } 24 25 }
在16、17行代碼中,調用了MyService類中的方法。下面來定義MyService類,在裏面加載資源文件。
MyService.java:
1 package com.vae.service; 2 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.util.Properties; 7 8 public class MyService { 9 10 public void method() throws FileNotFoundException, IOException{ 11 //在沒有ServletContext的環境下,如果想要讀取資源,可以使用類加載器以加載類的方式加載資源, 12 //這裏要註意,類加載器從哪個目錄加載類,就從哪個目錄加載資源, 13 //所以此處的路徑一定要給一個相對於類加載目錄的路徑 14 Properties prop = new Properties(); 15 prop.load(new FileReader(MyService.class.getClassLoader().getResource("config.properties").getPath())); 16 System.out.println(prop.getProperty("username")); 17 System.out.println(prop.getProperty("password")); 18 } 19 20 }
在瀏覽器輸入url後,後臺輸出如下:
【特別註意】第15行代碼中getResource()裏面的路徑。
類加載器從哪個目錄加載類,就從哪個目錄加載資源,所以此處的路徑一定要給一個相對於類加載目錄的路徑
我們先看一下這個工程發布到tomcat裏面的目錄:
進入WEB-INF目錄下,是下面的樣子:
上圖中的classes目錄和工程文件的src目錄等價。
(1)如果config.properties文件放在src目錄下,那路徑為:getResource("config.properties")
(2)如果config.properties文件的位置如下:
那路徑和上面的代碼一樣:getResource("com/vae/servlet/config.properties")
(3)如果config.properties文件和MyService.java文件並列,那路徑為:getResource("com/vae/service/config.properties")
(4)如果config.properties文件的位置如下:
此時config.properties文件和classes文件並列:
那路徑為:getResource("../config.properties") 註:"../"表示上一級目錄。
(5)如果config.properties文件放在整個工程文件的根目錄下,是無效的,因為此時文件並沒有發布到Tomcat。
【工程文件】
鏈接:http://pan.baidu.com/s/1ntBPHd3 密碼:5qr2(轉)JavaWeb學習之Servlet(四)----ServletConfig獲取配置信息、ServletContext的應用