幾乎所有的Web開發語言都支援Session功能,Servlet也不例外。 Servlet/JSP中的Session功能是通過範圍(scope)這個概念來實現的。
範圍分為四種,分別為:
page |
在當前頁面有效(僅用於JSP中) |
request |
在當前請求中有效 |
session |
在當前會話中有效 |
application |
在所有應用程式中有效 |
是不是看不太明白?page因為僅用於JSP中,這裡只講述其他三種範圍。 首先要聲明的一點,所謂“範圍”就是“資訊共用的範圍”, 也就是說一個資訊能夠在多大的範圍內有效。
話說武松一日來到景陽崗,見一旗幟迎風飄揚,旗子上書五個大字“三碗不過崗”。 武松叫道:“店家,拿三碗酒來,再切兩斤熟牛肉!”店小二應聲道:“三碗好酒, 二斤熟牛肉囉~~”裡面廚師趕忙噹噹噹噹切好牛肉,店小二倒上三碗酒,店小二端上前來。
武松咕咚咕咚連幹三碗,叫一聲“好酒!店家,再來三碗!”小二忙又倒上三碗好酒, 武松一飲而盡。就這樣前前後後武松一共喝了十八大腕。付了帳剛要走,店小二道: “客官,這前面山上有大蟲,客官剛剛喝完十八碗酒恐怕過不得崗,不如在小店暫住一夜, 待明天和獵戶一同過崗豈不是好?”
之後武松說什麼就留待各位看官自己去回憶啦。在這段武松打虎中, 大家有沒有看到些熟悉的東西?
•武松:瀏覽器。
•酒館: 伺服器。
•店小二、廚師: Servlet或者JSP。
•來三碗好酒!:瀏覽器向伺服器發出HTTP請求。
•店小二上酒:伺服器的響應。
•武松從進店到離開: 一個HTTP會話(即 Session)。
我們可以看到,Web互動的最基本單位為HTTP請求(‘武松點菜‘)。 每個使用者從進入網站到離開網站這段過程稱為一個HTTP會話 (“武松進店到出店”),一個伺服器的運行過程中會有多個使用者訪問, 就是多個HTTP會話(“酒館當然不可能只接待武松一個客人”)。 那麼範圍就可以理解為:
request |
HTTP請求開始到結束這段時間 |
session |
HTTP會話開始到結束這段時間 |
application |
伺服器啟動到停止這段時間 |
request
一個HTTP請求的處理可能需要多個Servlet合作(“武松點菜時店小二就要吩咐廚房做菜”), 幾個Servlet之間可以通過某種方式傳遞資訊(“店小二就用吆喝的方式通知廚房”), 但這個資訊在請求結束後就無效了(“廚房在做完菜之後就不用再管這道菜的事兒了”)。
Servlet之間的資訊共用是通過HttpServletRequest介面的兩個方法來實現的:
void setAttribute(String name, Object value)
將對象 value 以 name 為名稱儲存到request範圍中。
Object getAttribute(String name)
從request範圍中取得指定名字的資訊。
doGet()、doPost()函數的第一個參數就是 HttpServletRequest 對象, 使用這個對象的 setAttribute 即可傳遞資訊。
那麼設定好資訊之後,如何將資訊傳給其他Servlet? 這就要用到 RequestDispatcher 介面的 forward 方法,將請求轉寄給其他Servlet。
RequestDispatcher ServletContext.getRequestDispatcher(String path)
取得Dispatcher以便轉寄。path為轉寄的目的Servlet。
void RequestDispatcher.forward(ServletRequest request, ServletResponse response)
將request和response轉寄。
因此,只要在當前Servlet中先 setAttribute,然後forward,最後在forward到的Servlet中 getAttribute即可實現資訊傳遞。
PHP的程式員可能不太好理解這一段,因為PHP中沒有轉寄的概念, 一個請求只能由一個PHP檔案來處理,所以PHP中根本沒有request範圍的概念。 而Servlet則不同,請求可以在應用程式中任意轉寄,所以用request範圍在不同Servlet之間傳遞資訊。 需要注意兩點:
1.轉寄不是重新導向,轉寄是在Web應用內部進行的。PHP支援重新導向但沒有轉寄。
2.轉寄對瀏覽器是透明的,也就是說,無論在伺服器上如何轉寄,瀏覽器地址欄中顯示的仍然是最初那個Servlet的地址。
session
session範圍比較容易理解,同一瀏覽器訪問多次,在這多次訪問之間傳遞資訊,就是session範圍。 (武松每次點菜,帳房先生都要記一筆賬,等武松走之前結帳用。 這筆帳在武松吃飯過程中始終有效,即位於session範圍中)
session是通過HttpSession介面實現的。
Object HttpSession.getAttribute(String name)
從session中擷取資訊
void HttpSession.setAttribute(String name, Object value)
向session中儲存資訊
而通過HttpServletRequest.getSession()方法可以獲得HttpSession對象。
HttpSession HttpServletRequest.getSession()
擷取當前請求所在的session的對象。
session的開始容易判斷(瀏覽器發出第一個HTTP請求即可認為會話開始), 但結束就不好判斷了(因為瀏覽器關閉時不會通知伺服器“我關了,會話可以結束了”), 所以只能通過這種方法判斷:如果一定的時間內用戶端沒有反應,則認為會話結束。 Tomcat的預設值為120分鐘,但這個值也可以通過 HttpSession 的 setMaxInactiveInterval() 方法來設定。
void setMaxInactiveInterval(int interval)
設定會話的逾時值。
如果想主動讓會話結束,如使用者單擊“登出”的時候,可以使用HttpSession 的 invalidate() 方法:
void invalidate()
強制結束當前session。
application
application範圍就是伺服器啟動到關閉的整段時間, 在這個範圍內設定的資訊可以被所有應用程式使用。 (餐館打烊後結帳,用到的即是開張到打烊之間的所有資訊。)
還記得上一節提到的ServetContext嗎? application範圍上的資訊傳遞就是通過ServetContext實現的。
Object getAttribute(String name)
從application中擷取資訊。
void setAttribute(String name, Object value)
向application範圍中設定資訊。
總結
可以看到,每個範圍除了實現介面不同、意義不同之外,它們的使用方法和作用都是相同的, 都是通過 getAttribute 和 setAttribute 方法進行資訊傳遞。
範圍 |
意義 |
實現介面 |
request |
HTTP請求內 |
HttpServletRequest |
session |
HTTP會話內 |
HttpSession |
application |
伺服器生命週期內 |
ServletContext |
樣本程式
樣本程式
這一節的樣本程式是一個使用者登入的類比程式。檔案較多。
•login.html 登入表單
•DoLogin.java 處理登入動作的Servlet
•LoginSuccess.java 用於顯示登入成功資訊的Servlet
•SessionTest.java 登入後的處理常式
•DoLogout.java 登出的處理常式
為了示範 request、application、session 各個範圍的使用方法, Servlet之間進行了資料傳遞,資料傳遞方式如下:
資料產生 |
資料接受 |
資料內容 |
範圍 |
DoLogin |
LoginSuccess |
登入時間 |
request |
DoLogin |
SessionTest |
登入使用者名稱 |
session |
DoLogin |
SessionTest |
系統登入次數 |
application |
訪問 http://localhost:8080/LearnJSP/sessiontest, 登入時輸入使用者名稱 charlee 和密碼 123456 即可。
樣本下載:session-test_jb51net.zip