Author:相忠良
Email: ugoood@163.com
起始於:April 14, 2018
最後更新日期:April 18, 2018css
聲明:本筆記依據傳智播客方立勳老師 Java Web 的授課視頻內容記錄而成,中間加入了本身的理解。本筆記目的是強化本身學習所用。如有疏漏或不當之處,請在評論區指出。謝謝。
涉及的圖片,文檔寫完後,一次性更新。html
Servelet 是動態 web 資源開發技術。html 是靜態 web 資源開發技術。Jsp 是另外一種動態web資源開發技術,但 jsp 裏面就是 Servelet。因此應先搞明白 Servelet。java
sun公司提供了一個servlet接口,用戶若想開發一個動態web資源,需完整下面2個步驟:mysql
快速入門:用servlet向瀏覽器輸出"hello servlet"。
閱讀 J2EE 的 servlet api 文檔,解決2個問題:程序員
查看 api 後,作實驗。
過程以下:
1.在tomcat webapps 中新建 day05 目錄, 而後再web應用中創建WEB-INF/classes
目錄;
2.在classes目錄中新建一個FirstServlet.java
;web
package cn.wk; import java.io.*; import javax.servlet.*; // GenericServlet已經覆蓋了Servlet接口中的方法,繼承它,用起來方便 public class FirstServlet extends GenericServlet{ // 服務器接受客戶請求並給出響應,咱們需重寫 service 方法 public void service(ServletRequest req, ServletResponse res) throws ServletException,java.io.IOException{ // 向瀏覽器輸出的流 OutputStream out = res.getOutputStream(); //OutputStream是字節流,故用getBytes()把字符轉字節 out.write("hello servlet!!!".getBytes()); } }
注意到,servlet 程序是跑在 web 服務器中,受 web 服務器調用的。服務器會給 servlet 程序的service
方法送來一個客戶發來的 request, 向客戶發 「hello servelt!!!」響應的話,應由servlet程序中service
方法中的ServletResponse
對象去處理。我猜想OutputStream
輸出流由servlet程序發給web服務器,再由web服務器封裝後,輸出給客戶的瀏覽器。sql
3.編譯servlet程序FirstServlet.java
。其中需在cmd下將servlet-api.jar
添加到classpath中。我機器例子:C:\apache-tomcat-8.5.9\webapps\day05\WEB-INF\classes>set classpath=%classpath%;C:\apache-tomcat-8.5.9\lib\servlet-api.jar
而後編譯:C:\apache-tomcat-8.5.9\webapps\day05\WEB-INF\classes>javac -d . FirstServlet.java
數據庫
4.在WEB-INF目錄中新建web.xml文件,並配置servlet的對外訪問路徑,內容抄自C:\apache-tomcat-8.5.9\conf\web.xml
文件,並作修改。以下:apache
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <servlet> <!-- 名字 --> <servlet-name>FirstServlet</servlet-name> <!-- 位置 --> <servlet-class>cn.wk.FirstServlet</servlet-class> </servlet> <!-- 配置servlet的對外訪問路徑 --> <servlet-mapping> <!-- 名字 --> <servlet-name>FirstServlet</servlet-name> <!-- 對外路徑 --> <url-pattern>/FirstServlet</url-pattern> </servlet-mapping> </web-app>
5.啓動tomcat,開啓瀏覽器,訪問http://localhost:8080/day05/FirstServlet
查看結果。windows
生命週期:servlet第一次被訪問時被建立一個實例對象,web服務器會調用init方法完成對象初始化,service方法會執行,用來響應客戶端的請求,當web服務器關閉時或者當前web應用被刪掉時,web服務器會調用destroy方法,從web容器中移除該servlet對象。
步驟:
1.新建一個 Web Project,不直接點 Finish,點下一步勾選上 web.xml;
2.src目錄下新建一個ServletDemo1
的類並繼承GenericServlet
實現類;
3.把apache-tomcat-8.5.9-src
源碼attached到項目中去,而後在ServletDemo1
中寫入:
public class ServletDemo1 extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { res.getOutputStream().write("hello servlet!!!!!".getBytes()); } }
4.這個servlet程序外界沒法訪問,需用web.xml
配置對外訪問路徑,添加以下內容:
注意:要想得到這種類名cn.wk.ServletDemo1
,需將ServletDemo1.java
點開,而後右鍵點擊類名,再點 copy qualified name 按鈕獲取類全名!
<servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>cn.wk.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/ServletDemo1</url-pattern> </servlet-mapping>
5.想發佈這個web應用,需先爲Eclipse集成一個tomcat服務器(我用的是 tomcat 8),以下:
windows->preference->myeclipse->servers->tomcat->tomcat 8.x
而後選擇 tomcat 8 所在目錄,再點 Enable,其餘默認,點肯定便可。
6.點擊屏幕上方的 Deploy MyEclipse J2EE Project to Server 按鈕,把本工程部署到服務器;
7.點擊屏幕上方的啓動服務器按鈕(選擇tomcat 8.x);
8.瀏覽器中輸入http://localhost:8080/day05/ServletDemo1
查看結果。
實際開發中要想建 servlet 程序,直接右鍵 new 一個 servlet 便可,Eclipse 直接在 web.xml 中把<servlet>
元素和<servlet-mapping>
元素寫好了!
寫sevlet程序繼承HttpServlet
就好了,再根據想處理的請求複寫doGet()
或者doPost()
等方法就能夠了,沒必要再複寫service()
方法了,讀api看下HttpServlet
就會徹底明白了!
實驗,在day05項目中cn.wk包下直接創建名爲ServletDemo2
的servlet程序,以下:
public class ServletDemo2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream().write("Hello, HttpServlet!!!!".getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
web.xml中對於該資源的外部訪問路徑就不用配了,Eclipse 已經給咱配好了。
瀏覽器中輸入http://localhost:8080/day05/servlet/ServletDemo2
查看結果。
注意:servlet程序重命名後(按F2重命名,而不能在程序中改!),相關引用該類的程序也自動修改,但web.xml中的名字沒改,得手動修改!!!方立勳老師特地強調:寫servlet程序要當心,寫錯名字的話,web.xml中的內容有不少地方需修改,工程很大的話,就是災難了!
可在MyEclipse目錄下查找
Servlet.java
修改模板,使得doGet和doPost方法變清爽,但我沒成功。
拷貝別人的工程後,可能涉及到修改web訪問路徑。方法:Eclipse中右擊點屬性->MyEclipse->找Web->修改Web Context-root
。
配置servlet程序的訪問地址URL:
一個servlet程序能夠有多個URL,還涉及到通配符:
例子,修改day05工程下的 web.xml 以下:
<!-- servlet註冊 --> <servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>cn.wk.ServletDemo1</servlet-class> </servlet> <servlet> <servlet-name>ServletDemo2</servlet-name> <servlet-class>cn.wk.ServletDemo2</servlet-class> </servlet> <!-- servlet URL 映射 --> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/ServletDemo1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo2</servlet-name> <url-pattern>/servlet/ServletDemo2</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo2</servlet-name> <url-pattern>/1.html</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo2</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo2</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
多個通配符表達的url,涉及到具體匹配哪個servlet程序的問題(瞭解):
Servlet 引擎: Web 服務器中用來調 servlet 程序的那個程序。 Servlet 程序不能單獨運行。
servlet程序的init()和destroy():
實驗,新建立了一個ServletDemo3.java
的 servlet 程序,並覆蓋了init()
和destroy()
。結果顯示客戶 第一次訪問 該servlet程序時,web容器執行init()
,當 服務器關閉或該servlet程序從web容器被移除 時,web容器執行該servlet程序的destroy()
:
public class ServletDemo3 extends HttpServlet { @Override public void init() throws ServletException { super.init(); System.out.println("init"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream().write("Hello ServletDemo3!!!".getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } @Override public void destroy() { super.destroy(); System.out.println("destroy"); } }
爲ServletDemo3
設置啓動服務器就建立對象並執行init()
方法。在 web.xml的<servlet>
元素裏設置<load-on-startup>
元素,並設置其內容爲1
,以下:
<servlet> <servlet-name>ServletDemo3</servlet-name> <servlet-class>cn.wk.ServletDemo3</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
<load-on-startup>1</load-on-startup>
裏的1表示優先級,越小優先級越高,但必須是正整數。
該技術用在隨服務器的啓動,啓動某些框架上。
缺省的 Servlet 程序:
<servlet-mapping> <servlet-name>ServletDemo3</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
注意上面代碼<url-pattern>/</url-pattern>
中只有/
,意味着其餘servlet都不支持的 url 由這個缺省的ServletDemo3
servlet程序來處理!即 處理別人都不處理的請求!
注意:即便咱們沒配置該web應用的缺省servlet程序,web容器也會爲咱們弄一個缺省的servlet程序。若是咱們配置了,服務器爲咱們準備的缺省servlet程序會被覆蓋。程序員本身不要把某個servlet弄成缺省的,由於html文件將沒法訪問。如:http://localhost:8080/day05/1.html
將訪問本身設置的缺省servlet程序。
靜態成員變量要慎用,可能致使 線程安全問題 或 內存溢出,如:
public class Person{ public static List<String> list = new ArrayList<String>(); }
若 Person 類隨服務器啓動而加載,另外一個 Demo 類訪問 Person 類,當有不少用戶用 Demo 類代碼訪問 Person 類時均向list
添加數據,靜態成員list
會無限變大,最終可能致使內存溢出,Demo 代碼以下:
public class Demo{ public static void main(String[] args) { Person p = new Person(); p.list.add("aaa"); } }
下面代碼有線程安全問題:
// 線程安全問題 public class ServletDemo4 extends HttpServlet { int i = 0; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Thread.sleep(1000 * 3); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } i++; response.getOutputStream().write((i + "").getBytes()); } }
開兩個瀏覽器窗口,同時訪問http://localhost:8080/day05/servlet/ServletDemo4
會出線程安全問題。
加上同步鎖,解決了線程安全問題,代碼以下:
// 線程安全問題 public class ServletDemo4 extends HttpServlet { int i = 0; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream().write((i + "").getBytes()); i++; try { Thread.sleep(1000 * 5); } catch (InterruptedException e) { e.printStackTrace(); } response.getOutputStream().write((i + "").getBytes()); } }
加同步鎖解決線程安全問題:
// 加同步鎖 public class ServletDemo4 extends HttpServlet { int i = 0; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { synchronized (this) { response.getOutputStream().write((i + "").getBytes()); i++; try { Thread.sleep(1000 * 5); } catch (InterruptedException e) { e.printStackTrace(); } response.getOutputStream().write((i + "").getBytes()); } } }
以上線程安全問題的解決方案是不行的,最後一個用戶訪問這個頁面等1年?
接口中沒有任何定義,這種接口是標記接口,如:Serializable
,Cloneable
以及本節所涉及的SingleThreadModel
。
但這試驗我沒作出來,達不到開2個ie窗口,都顯示結果爲1的效果,代碼以下:
public class ServletDemo4 extends HttpServlet implements SingleThreadModel { int i = 0; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { i++; try { Thread.sleep(1000 * 8); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } response.getOutputStream().write((i + "").getBytes()); } }
Java中的諺語:子類在覆蓋父類的方法時,不能拋出比父類更多的異常。想法是:子類比父類強。
Web 服務器會給 Servlet 傳各類對象,咱們編寫的 Servlet 程序接收這些對象後,解析它,再搞對應的操做,如圖:
認識 ServletConfig 對象:
問題:爲何要在 web.xml 這個配置文件裏添加 servlet 所需的數據,而不是在 servlet 程序裏寫入數據?
實際開發中,有一些東西不適合在 servlet 程序中寫死,這類數據就能夠經過 配置的方式 配給 servlet 程序,例如:
舉實際的例子,ServletDemo5
以下:
// ServletConfig 對象:用於封裝 servlet 的配置信息 public class ServletDemo5 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲得指定的 String value = this.getServletConfig().getInitParameter("config"); System.out.println(value); // 獲得全部的 Enumeration e = this.getServletConfig().getInitParameterNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); String value_ = this.getServletConfig().getInitParameter(name); System.out.println(name + " = " + value_); } } }
修改 web.xml,想該 servlet 註冊中添加配置數據,以下:
<servlet> <servlet-name>ServletDemo5</servlet-name> <servlet-class>cn.wk.ServletDemo5</servlet-class> <!-- 配置 ServletConfig --> <init-param> <param-name>charset</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <!-- 配置數據庫鏈接地址 --> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/test</param-value> </init-param> <init-param> <param-name>username</param-name> <param-value>root</param-value> </init-param> <init-param> <param-name>password</param-name> <param-value>root</param-value> </init-param> <init-param> <!-- 本 servlet 讀哪一個配置文件 --> <param-name>config</param-name> <param-value>/struts-config.xml</param-value> </init-param> </servlet>
瀏覽器中輸入http://localhost:8080/day05/servlet/ServletDemo5
,則控制檯中輸出結果爲:
config = /struts-config.xml username = root charset = UTF-8 config = /struts-config.xml password = root url = jdbc:mysql://localhost:3306/test
產生:web 服務器有多少 web 應用,服務器就建立多少個 ServletContext 容器!
銷燬:停服務器或者刪除了某 web 應用,對應的 Context 容器們或容器會被銷燬。
ServletContext 用來操做整個該 servlet 程序所在的 web 應用全局性資源的。
獲取 ServletContext 對象:
// ServletContext 示例 public class ServletDemo6 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲取 ServletContext 對象 ServletContext context = this.getServletContext(); } }
ServletContext 域,表達瞭如下幾點意思:
下面的例子,實現了 day05 這個 web 應用範圍內的,ServletDemo7
和ServletDemo8
這2個servlet程序的數據共享。
public class ServletDemo7 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data = "aaa"; // 向 Context 容器內添加 全web應用域 都能共享的數據 this.getServletContext().setAttribute("data", data); } }
public class ServletDemo8 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲取 ServletContext 對象 ServletContext context = this.getServletContext(); // 獲取 Context 容器內的數據 String value = (String) context.getAttribute("data"); // 向瀏覽器輸出 response.getOutputStream().write(value.getBytes()); } }
瀏覽器中輸入http://localhost:8080/day05/servlet/ServletDemo7
,再開一個小窗,地址欄中輸入http://localhost:8080/day05/servlet/ServletDemo8
,在當前的這個瀏覽器中會出現ServletDemo7
輸出到ServletContext
域中的共享數據aaa
。
咱們能夠在 web.xml 文件中寫<context-param>
爲整個 web 應用作配置,以下:
<!-- 爲當前整個web應用作的配置 --> <!-- 全部servlet均可經過ServletContext容器訪問下面的數據 --> <context-param> <param-name>data</param-name> <param-value>xxxx</param-value> </context-param>
而後建一個servlet程序,輸出Context容器中內容便可,String value = this.getServletContext.getAttribute("data")
,輸出這個value
便可。
問題:什麼狀況下,需爲整個 web 應用配置初始化參數?
上百個 servlet 都需連數據庫的話,難道上百個servlet配置都用ServletConfig
來配?這時就得用這個 表明全局的ServletContext
容器來配置。
Servlet的轉發和重定向
轉發:你向我借錢,我沒有,我幫你去找他;
重定向:你向我借錢,我沒有,你本身去找他!
Servlet 只適合產生數據,不適合美化輸出,輸出得靠html和css。這時就用到轉發,既servlet產生的數據轉發到 jsp,由 jsp 負責輸出數據,這時將大量使用到轉發。
例子,ServletDemo10
產生的數據轉發到1.jsp
:
// 經過 ServletContext 實現請求轉發 public class ServletDemo10 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data = "aaaaaaaaa"; // 把數據帶給1.jsp(只是演示,正常的話不能用context域,要經過request域) this.getServletContext().setAttribute("data", data); RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/1.jsp"); rd.forward(request, response); } }
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP '1.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <!-- 這裏開始寫代碼 --> <h1> <font color="red"> <% String data = (String)application.getAttribute("data"); out.write(data); %> </font> </h1> <!-- 結束 --> </body> </html>
打開瀏覽器輸入http://localhost:8080/day05/servlet/ServletDemo10
查看結果。
通常無論理servlet程序,管理的是 web 應用的其餘資源文件。
實際應用場景:
衆多servlet程序要訪問數據庫,則通常來講,數據庫相關信息要用資源文件保存。
有兩種文件用來保存數據庫配置信息:
.properties
文件(信息無關聯用這個)和.xml
文件(信息有關聯用這個)。
鏈接數據庫的這種信息,認爲是平行信息(無關聯信息),故應用.properties
文件保存。
試驗,涉及2文件,ServletDemo11
和db.properties
(該文件在/src
目錄下):
db.properties
內容以下:
url=jdbc:mysql://localhost:3306/test username=root password=root
ServletDemo11內容以下:
注意:
讀取.properties
文件是重點,且不要用FileInputStream
對象讀,由於它默認的相對路徑起始處爲 java 虛擬機所在的位置。
注意觀察路徑:/WEB-INF/classes/db.properties
。
當ServletDemo11
執行時,工程裏的src/db.properties
文件早已部署到/WEB-INF/classes/db.properties
了,因此應寫這個路徑!
// 經過 ServletContext 讀取資源文件 方法1 public class ServletDemo11 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // FileInputStream 這麼用是不行滴 // FileInputStream in = new // FileInputStream("/WEB-INF/classes/db.properties"); // 此處最好不要用 FileInputStream 對象,需好用 ServletContext 去讀 InputStream in = this.getServletContext().getResourceAsStream( "/WEB-INF/classes/db.properties"); Properties props = new Properties(); // map props.load(in); String url = props.getProperty("url"); String username = props.getProperty("username"); String password = props.getProperty("password"); System.out.println(url); System.out.println(username); System.out.println(password); } }
瀏覽器輸入http://localhost:8080/day05/servlet/ServletDemo11
,則控制檯輸出結果爲:
jdbc:mysql://localhost:3306/test root root
也能夠這樣讀取:
// 經過 ServletContext 讀取資源文件 方法2 public class ServletDemo11 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲取資源絕對路徑後,可用 FileInputStream String path = this.getServletContext().getRealPath( "/WEB-INF/classes/db.properties"); // 獲取文件名 String filename = path.substring(path.lastIndexOf("\\") + 1); System.out.println("當前讀取到的資源名稱是: " + filename); FileInputStream in = new FileInputStream(path); Properties props = new Properties(); // map props.load(in); String url = props.getProperty("url"); String username = props.getProperty("username"); String password = props.getProperty("password"); System.out.println("當前讀取到的資源數據是:"); System.out.println(url); System.out.println(username); System.out.println(password); } }
故事:若 servlet 程序想訪問數據庫,正常狀況應經過 dao 層訪問,而不是直接訪問。而 dao 層的類基本上是普通 java 程序,而不是 servlet 程序。問題是:普通的 java 程序,如何訪問當前 web 應用中的某個 web 資源(如:想訪問 src/db.properties
)?
這就要經過類裝載器來完成。
類裝載器:當前web應用有一個類裝載器,裝載了全部當前web應用下的類的字節碼文件。可經過該web應用下的任意java程序,得到這個類裝載器。經過這個類裝載器,找到要訪問的資源,得到對應的輸入流對象!
試驗,涉及3個文件:要訪問的資源src/db.properties
(與上節內容相同),ServletDemo12.java
和一個普通 java 程序UserDao.java
。
ServletDemo12.java
以下:
// servlet調用其餘普通java程序,這個普通java程序需經過 類加載器 讀取web資源文件 public class ServletDemo12 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { UserDao dao = new UserDao(); dao.update(); } }
UserDao.java
位於cn.wk.dao
包裏,涉及到靜態代碼塊和類加載器,代碼以下:
package cn.wk.dao; import java.io.InputStream; import java.util.Properties; public class UserDao { private static Properties dbconfig = new Properties(); // 類加載時 就得到資源 static { try { // 類加載器 InputStream in = UserDao.class.getClassLoader() .getResourceAsStream("db.properties"); dbconfig.load(in); } catch (Exception e) { // 認爲訪問不到資源,是重大錯誤,而不是異常,故拋出錯誤 throw new ExceptionInInitializerError(e); } } public void update() { System.out.println(dbconfig.getProperty("url")); // map } }
瀏覽器輸入http://localhost:8080/day05/servlet/ServletDemo12
,而後在控制檯查看結果。
故事:服務器開啓後,當有人修改了db.properties
資源文件後,再經過類裝載器直接得到資源時,沒法得到最新的,緣由是類裝載器裏的字節碼文件隨服務器啓動後只加載1次。以下代碼:
public class UserDao { public void update() throws IOException { // 如下代碼雖然能夠讀取資源文件的數據,但沒法獲取更新後的數據 Properties dbconfig = new Properties(); InputStream in = UserDao.class.getClassLoader().getResourceAsStream( "db.properties"); dbconfig.load(in); System.out.println(dbconfig.getProperty("url")); // map } }
正確姿式:
public class UserDao { public void update() throws IOException { // 經過類裝載的方式獲得資源文件的位置,再經過傳統方式讀取資源文件的數據 // 這樣能夠讀取資源更新後的數據 String path = UserDao.class.getClassLoader() .getResource("db.properties").getPath(); FileInputStream in = new FileInputStream(path); Properties dbconfig = new Properties(); dbconfig.load(in); System.out.println(dbconfig.getProperty("url")); // map } }