[转载]关于request和session详解
在網上經常看到有人對request.getSession(false)提出疑問,我第一次也很迷惑,看了一下J2EE1.3API,看一下官網是怎么解釋的。?
【官方解釋】
?getSession?
public HttpSessiongetSession(boolean?create)
Returns the current HttpSessionassociated with this request or, if if there is no current sessionand create is true, returns a new session.
If create is false and therequest has no valid HttpSession, this method returnsnull.
To make sure the session isproperly maintained, you must call this method before the responseis committed. If the container is using cookies to maintain sessionintegrity and is asked to create a new session when the response iscommitted, an IllegalStateException is thrown.
Parameters:true - to create anew session for this request if necessary; false to return null ifthere's no current session
Returns: theHttpSession associated with this request or null if create is falseand the request has no valid session
譯:
getSession(boolean?create)意思是返回當前reqeust中的HttpSession,如果當前reqeust中的HttpSession為null,當create為true,就創建一個新的Session,否則返回null;
簡而言之:
HttpServletRequest.getSession(ture) 等同于HttpServletRequest.getSession()
HttpServletRequest.getSession(false) 等同于如果當前Session沒有就為null;
【問題和bug】:
我周圍很多同事是這樣寫的;
HttpSession?session?=?request.getSession();???//?a?new?session?created?if?no?session?exists,?哈哈!完蛋啦!如果session不存在的話你又創建了一個!??String?user_name?=?session.getAttribute("user_name");?? HttpSession session = request.getSession(); // a new sessioncreated if no session exists, 哈哈!完蛋啦!如果session不存在的話你又創建了一個! Stringuser_name = session.getAttribute("user_name");需要注意的地方是request.getSession() 等同于request.getSession(true),除非我們確認session一定存在或者sesson不存在時明確有創建session的需要,否則盡量使用request.getSession(false)。在使用request.getSession()函數,通常在action中檢查是否有某個變量/標記存放在session中。這個場景中可能出現沒有session存在的情況,正常的判斷應該是這樣:
HttpSession?session?=?request.getSession(false);??if?(session?!=?null)?{?????String?user_name?=?session.getAttribute("user_name");??}?? HttpSession session = request.getSession(false); if (session !=null) { String user_name = session.getAttribute("user_name"); }
【投機取巧】:
如果項目中用到了Spring(其實只要是Java的稍大的項目,Spring是一個很好的選擇),對session的操作就方便多了。如果需要在Session中取值,可以用WebUtils工具(org.springframework.web.util.WebUtils)的getSessionAttribute(HttpServletRequest request, Stringname)方法,看看高手寫的源碼吧:哈哈。。
?public?static?Object?getSessionAttribute(HttpServletRequest?request,?String?name)?{?????Assert.notNull(request,?"Request?must?not?be?null");?????HttpSession?session?=?request.getSession(false);?????return?(session?!=?null???session.getAttribute(name)?:?null);??}?? public static Object getSessionAttribute(HttpServletRequestrequest, String name) { Assert.notNull(request, "Request must notbe null"); HttpSession session = request.getSession(false); return(session != null ? session.getAttribute(name) : null); }注:Assert是Spring工具包中的一個工具,用來判斷一些驗證操作,本例中用來判斷reqeust是否為空,若為空就拋異常。
上面的代碼又可以簡潔一下啦,看吧:
HttpSession?session?=?request.getSession(false);??String?user_name?=?WebUtils.getSessionAttribute(reqeust,?"user_name");?
?
2.9.8 session對象
session對象也是一個非常常用的對象,這個對象代表一次用戶會話。一次用戶會話的含義是:從客戶端瀏覽器連接服務器開始,到客戶端瀏覽器與服務器斷開為止,這個過程就是一次會話。
session通常用于跟蹤用戶的會話信息,如判斷用戶是否登錄系統,或者在購物車應用中,用于跟蹤用戶購買的商品等。
session范圍內的屬性可以在多個頁面的跳轉之間共享。一旦關閉瀏覽器,即session結束,session范圍內的屬性將全部丟失。
session對象是HttpSession的實例,HttpSession有如下兩個常用的方法:
setAttribute(String attName , ObjectattValue):設置session范圍內attName屬性的值為attValue。
getAttribute(String attName):返回session范圍內attName屬性的值。
下面的示例演示了一個購物車應用,以下是陳列商品的JSP頁面代碼。
程序清單:codes22.9jspObjectshop.jsp
| <%@ pagecontentType="text/html; charset=gb2312" language="java"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0Transitional//EN"> <HTML> <HEAD> <TITLE>選擇物品購買</TITLE> </HEAD> <BODY> <FORM METHOD=POSTACTION="processBuy.jsp"> 書籍:<INPUT TYPE="checkbox" NAME="item"value="book"><br> 電腦:<INPUT TYPE="checkbox" NAME="item"value="computer"><br> 汽車:<INPUT TYPE="checkbox" NAME="item"value="car"><br> <INPUT TYPE="submit"value="購買"> </FORM> </BODY> </HTML> |
這個頁面幾乎沒有動態的JSP部分,全部是靜態的HTML內容。該頁面包含一個表單,表單里包含3個復選按鈕,用于選擇想購買的物品,表單由processBuy.jsp頁面處理,其頁面的代碼如下:
程序清單:codes22.9jspObjectprocessBuy.jsp
| <%@ pagecontentType="text/html; charset=gb2312" language="java"import="java. util.*"%> <% //取出session范圍的itemMap屬性 Map<String,Integer> itemMap =(Map<String,Integer>)session .getAttribute("itemMap"); //如果Map對象為空,則初始化Map對象 if (itemMap == null) { itemMap = newHashMap<String,Integer>(); itemMap.put("書籍" , 0); itemMap.put("電腦" , 0); itemMap.put("汽車" , 0); } //獲取上個頁面的請求參數 String[] buys = request.getParameterValues("item"); //遍歷數組的各元素 for (String item : buys) { //如果item為book,表示選擇購買書籍 if(item.equals("book")) { int num1 = itemMap.get("書籍").intValue(); //將書籍key對應的數量加1 itemMap.put("書籍" , num1 + 1); } //如果item為computer,表示選擇購買電腦 else if (item.equals("computer")) { int num2 = itemMap.get("電腦").intValue(); //將電腦key對應的數量加1 itemMap.put("電腦" , num2 + 1); } //如果item為car,表示選擇購買汽車 else if (item.equals("car")) { int num3 = itemMap.get("汽車").intValue(); //將汽車key對應的數量加1 itemMap.put("汽車" , num3 + 1); } } //將itemMap對象放到設置成session范圍的itemMap屬性 session.setAttribute("itemMap" , itemMap); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0Transitional//EN"> <HTML> <HEAD> <TITLE>購買的物品列表</TITLE> </HEAD> <BODY> 您所購買的物品:<br> 書籍:<%=itemMap.get("書籍")%>本<br> 電腦:<%=itemMap.get("電腦")%>臺<br> 汽車:<%=itemMap.get("汽車")%>輛<p> <ahref="shop.jsp">再次購買</a> </BODY> </HTML> |
上面頁面中粗體字代碼使用session來保證itemMap對象在一次會話中有效,這使得該購物車系統可以反復購買,只要瀏覽器不關閉,購買的物品信息就不會丟失,圖2.31顯示的是多次購買后的效果。
| ? |
| 圖2.31?利用session記錄購物車信息 |
考慮session本身的目的,通常只應該把與用戶會話狀態相關的信息放入session范圍內。不要僅僅為了2個頁面之間交換信息,就將該信息放入session范圍內。如果僅僅為了2個頁面交換信息,可以將該信息放入request范圍內,然后forward請求即可。
關于session還有一點需要指出,session機制通常用于保存客戶端的狀態信息,這些狀態信息需要保存到Web服務器的硬盤上,所以要求session里的屬性值必須是可序列化的,否則將會引發不可序列化的異常。
session的屬性值可以是任何可序列化的Java對象。
?
9.3.1 單例模式
有些時候,允許自由創建某個類的實例沒有意義,還可能造成系統性能下降(因為創建對象所帶來的系統開銷問題)。例如整個系統只有一個窗口管理器,只有一個假脫機打印設備;在JavaEE應用中可能只需要一個數據庫引擎訪問點,Hibernate訪問時只需要一個SessionFactory實例,如果在系統中為它們創建多個實例就沒有太大的意義。
如果一個類始終只能創建一個實例,則這個類被稱為單例類,這種模式就被稱為單例模式。
對Spring框架而言,可以在配置Bean實例時指定scope="singleton"來配置單例模式。不僅如此,如果配置<bean.../>元素時沒有指定scope屬性,則該Bean實例默認是單例的行為方式。
Spring推薦將所有業務邏輯組件、DAO組件、數據源組件等配置成單例的行為方式,因為這些組件無須保存任何用戶狀態,故所有客戶端都可共享這些業務邏輯組件、DAO組件,因此推薦將這些組件配置成單例模式的行為方式。
如果不借助Spring框架,我們也可手動實現單例模式。為了保證該類只能產生一個實例,程序不能允許自由創建該類的對象,而是只允許為該類創建一個對象。為了避免程序自由創建該類的實例,我們使用private修飾該類的構造器,從而將該類的構造器隱藏起來。
將該類的構造器隱藏起來,則需要提供一個public方法作為該類的訪問點,用于創建該類的對象,且該方法必須使用static修飾(因為調用該方法之前還不存在對象,因此調用該方法的不可能是對象,只能是類)。
除此之外,該類還必須緩存已經創建的對象,否則該類無法知道是否曾經創建過實例,也就無法保證只創建一個實例。為此該類需要使用一個靜態屬性來保存曾經創建的實例,且該屬性需要被靜態方法訪問,所以該屬性也應使用static修飾。
基于上面的介紹,下面程序創建了一個單例類。
程序清單:codes99.3SingletonTestSingleton.java
| class Singleton { //使用一個變量來緩存曾經創建的實例 private static Singleton instance; //將構造器使用private修飾,隱藏該構造器 private Singleton(){} //提供一個靜態方法,用于返回Singleton實例 //該方法可以加入自定義的控制,保證只產生一個Singleton對象 public static Singleton getInstance() { //如果instance為null,表明還不曾創建Singleton對象 //如果instance不為null,則表明已經創建了Singleton對象,將不會執行該方法 if (instance == null) { //創建一個Singleton對象,并將其緩存起來 instance = new Singleton(); } return instance; } } public class TestSingleton { public static void main(String[] args) { //創建Singleton對象不能通過構造器,只能通過getInstance方法 Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); //將輸出true System.out.println(s1 == s2); } } |
上面程序中第一行粗體字代碼使用了一個靜態屬性來保存已創建的Singleton實例,程序第二段粗體字代碼用于判斷系統是否已經創建過Singleton實例——如果已經創建過Singleton實例,則直接返回該Singleton實例即可。
正是通過上面第二段粗體字代碼提供的控制邏輯,從而保證了Singleton類只能產生一個實例。所以在TestSingleton類的main方法中看到兩次產生的Singleton對象實際上是同一個對象。
在JavaEE應用中,單例模式是一種應用非常廣泛的設計模式,應用中許多組件都只需要單個實例,下面介紹的工廠模式里的工廠也只需要單個實例……
使用單例模式主要有如下兩個優勢:
減少創建Java實例所帶來的系統開銷。
便于系統跟蹤單個Java實例的生命周期、實例狀態等。
?
1. Object getAttribute( String name ) ;
獲取與指定名字相關聯的session屬性值。
2. Enumeration getAttributeNames() ;
取得session內所有屬性的集合。
3. long getCreationTime() ;
返回session的創建時間,最小單位千分之一秒。
4. String getId() ;
取得session標識。
5. long getLastAccessedTime() ;
返回與當前session相關的客戶端最后一次訪問的時間,由1970-01-01算起,單位毫秒。
6. int getMaxInactiveInterval( int interval ) ;
返回總時間,以秒為單位,表示session的有效時間(session不活動時間)。-1為永不過期。
7. ServletContext getServletContext() ;
返回一個該JSP頁面對應的ServletContext對象實例。
8. HttpSessionContext getSessionContext() ;
9. Object getValue( String name ) ;
取得指定名稱的session變量值,不推薦使用。
10. String[] getValueNames() ;
取得所有session變量的名稱的集合,不推薦使用。
11. void invalidate() ;
銷毀這個session對象。
12. boolean isNew() ;
判斷一個session是否由服務器產生,但是客戶端并沒有使用。
13. void pubValue( String name, Object value ) ;
添加一個session變量,不推薦使用。
14. void removeValue( String name ) ;
移除一個session變量的值,不推薦使用。
15. void setAttribute( String name, String value ) ;
設置指定名稱的session屬性值。
16. void setMaxInactiveInterval( int interval ) ;
設置session的有效期。
17. void removeAttribute( String name ) ;
移除指定名稱的session屬性。
?
在回答問題之前,跟你簡單介紹Session的工作原理:
不需要寫手動寫SessionID:
代碼如下:
HttpSession sesion = Request.getSesion();
if(session!=null){
//如果sessionID不等于空,則說明是第二次訪問
//寫第二次訪問時的代碼
}else{
//寫第一次訪問的代碼
}
javaweb怎么通過sessionid得到session這個我們不需要了解,就是第二次客戶端發出請求時,將sessionid也發給了服務器,服務器根據這個唯一的ID找到相應的session(session都是保存在服務器的數據庫中,每個session用唯一一個ID所標識),就像是數據庫中根據關鍵字查找數據一樣,找到之后就可以直接用這個session里面的數據了。
?
?
小弟現在做一個身份認證的程序,為了避免一個用戶同時登陸多次,想這個用戶第二次登陸時把他第一次登陸時建立的session失效,所以要得到他第一次登陸時的session對象,?
我這樣做的: ?
String ?SessionId ?=?"";//"從數據庫中得到"; ?
HttpSessionContext ?SessCon=?request.getSession(false).getSessionContext();?
HttpSession ?Sess ?=?SessCon.getSession(SessionId);?
Sess.InValidate();//這個函數的具體名字在發問的時候忘了 ?
?
上面的代碼在jsp中運行,出現錯誤,說我使用了該批判的method?getSession(String?id),我不知道該如何是好。大家幫幫忙吧,你們做過類似項目沒有?你們是如何實現這個問題的??
?
---------------------------------------------------------------?
?
在第一次登時,建立session ?如 ?
session.putValue("UID", ?XXXXX);?
在以后登錄時,可先檢查session ?
int ?curUid ?=?new?Integer((String)session.getValue("UID")).intValue();?
session失效很簡單 ?
session.invalidate(); ?
---------------------------------------------------------------?
?
這個要用到applications ?
自己去查查資料吧 ?
很好做的 ?
---------------------------------------------------------------?
?
好像是辦不到的。你可以通過從session內取值,判斷這個session是不是你所找的session,然后將session.invalidate();?
---------------------------------------------------------------?
?
什么叫作便利所有的Session阿,Session只有一個啊,里面存放了一些你想要的數據比如用戶的ID因此你可以判斷Session中的用戶ID是否為空來判斷阿
?
總結
以上是生活随笔為你收集整理的[转载]关于request和session详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HttpServlet中的service
- 下一篇: JSP+Servlet + JDBC 实