1. 程式人生 > >詳細探討和整理一下 java的會話管理:Cookie和Session

詳細探討和整理一下 java的會話管理:Cookie和Session

java的會話管理:Cookie和Session

1.什麼是會話

此處的是指客戶端(瀏覽器)和服務端之間的資料傳輸。例如使用者登入,購物車等
會話管理就是管理瀏覽器客戶端和服務端之間會話過程產生的會話資料
常用的會話技術
之前學會了域物件的作用,所以在會話管理的時候也可以使用域物件的概念來找到解決方法。
常用的解決方法主要有兩種:
資料儲存在客戶端的Cookie技術
資料儲存在服務端的Session技術

2.Cookie技術

2.1.什麼是Cookie

Cookie是客戶端技術,程式把每個使用者的資料以cookie的形式寫給使用者各自的瀏覽器,當用戶使用瀏覽器再去訪問伺服器中的web資源時,就會帶著各自的資料去。這樣,web資源處理的就是各自使用者自己的資料了
特點

是會話資料儲存在瀏覽器客戶端

2.2.Cookie技術核心API

Cookie類:用於儲存會話資料。常用方法如下:
1.構造Cookie物件

Cookie(java.lang.String name, java.lang.String value)

2.設定cookie

void setPath(java.lang.String uri) :設定cookie的有效訪問路徑
void setMaxAge(int expiry) : 設定cookie的有效時間
void setValue(java.lang.String newValue) :設定cookie的值

3.傳送cookie到瀏覽器端儲存

void response.addCookie(Cookie cookie) : 傳送cookie

4.伺服器端接收cookie

Cookie[] request.getCookies() : 接收cookie

程式碼示例:

/** * 測試Cookie的方法 */
@WebServlet(name = "CookieDemo")
public class CookieDemo extends HttpServlet {

    protectedvoiddoGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1.建立Cookie物件
Cookie cookie = new Cookie("name","eric"); //2.設定Cookie引數 //2.1.設定Cookie的有效路徑 cookie.setPath("/hello");//預設就是web專案的地址 //2.2.設定Cookie的有效時間 cookie.setMaxAge(20);//該cookie只存活20秒,從最後不調該cookie開始計算 cookie.setMaxAge(-1);//該cookie儲存在瀏覽器記憶體中,關閉瀏覽器則銷燬該cookie cookie.setMaxAge(0);//刪除根該cookie同名的cookie //3.把資料傳送到瀏覽器 response.addCookie(cookie); //4.服務端接收來自瀏覽器的cookie //方法1: // String name = request.getHeader("cookie"); // System.out.println(name); //方法2: Cookie[] cookies = request.getCookies(); //注意:判斷null,否則空指標 if(cookies!=null){ //遍歷 for(Cookie c:cookies){ String name = c.getName(); String value = c.getValue(); System.out.println(name+"="+value); } }else{ System.out.println("沒有接收cookie資料"); } } }

2.3.Cookie原理

1.伺服器建立Cookie物件,把會話資料儲存到Cookie物件中

new Cookie("name","value");

2.伺服器傳送cookie資訊到瀏覽器

response.addCookie(cookie);
其實是隱藏傳送了一個set-cookie名稱的響應頭

3.瀏覽器得到伺服器傳送的cookie,然後儲存在瀏覽器端
4.瀏覽器在下次訪問伺服器時,會帶著cookie資訊

包含在http的請求頭裡

5.伺服器接收到瀏覽器帶來的cookie資訊

request.getCookies();

2.4.Cookie的細節

1.void setPath(java.lang.String uri):設定Cookie的有效訪問路徑,有效訪問路徑指的事Cookie的有效路徑儲存在哪裡,那麼瀏覽器在有效路徑下訪問伺服器的時就會帶著Cookie資訊,否則不帶Cookie資訊,預設是在當時錢web專案的路徑下
2.void setMaxAge(int expiry):設定Cookie的有效時間
expiry可以是正整數,負整數,和零
正整數:表示Cookie資料儲存瀏覽器的快取到硬碟中,數值表示儲存的時間
負整數:表示Cookie資料儲存到瀏覽器的記憶體中,瀏覽器關閉Cookie就丟失了
零:表示刪除同名的Cookie資料
3.Cookie資料型別只能儲存非中文字串型別的。可以儲存多個Cookie,但是瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制為4KB。

2.5.Cookie案例:顯示使用者上次訪問的時間

功能實現邏輯:
將時間儲存在Cookie中,每次訪問從Cookie裡面呼叫
第一次訪問:
1.獲取當前時間,顯示到瀏覽器中
2.建立Cookie物件,時間作為cookie值,名為:lastTime
3.把cookie傳送到瀏覽器儲存
第N次訪問:
1.獲取cookie的資料,取出名為lastTime的cookie
2.得到cookie的值(上次訪問時間)
3.顯示上次訪問時間到瀏覽器中
4.更新名為lastTime的cookie。值設定為當前時間
5.把更新後的cookie傳送給瀏覽器儲存

程式碼實現:

/** * 案例-使用者上次訪問的時間 */
@WebServlet("/last")
public class HistServlet extends HttpServlet {

    publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");

        //獲取當前時間
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String curTime = format.format(new Date());


        //取得cookie
        Cookie[] cookies = request.getCookies();
        String lastTime = null;
        
        //第n次訪問
        if(cookies!=null){
            for (Cookie cookie : cookies) {
                if(cookie.getName().equals("lastTime")){
                    //有lastTime的cookie,已經是第n次訪問
                    lastTime = cookie.getValue();//上次訪問的時間
                    //第n次訪問
                    //1.把上次顯示時間顯示到瀏覽器
                    response.getWriter().write("歡迎回來,你上次訪問的時間為:"+lastTime+",當前時間為:"+curTime);
                    //2.更新cookie
                    cookie.setValue(curTime);
                    cookie.setMaxAge(1*30*24*60*60);
                    //3.把更新後的cookie傳送到瀏覽器
                    response.addCookie(cookie);
                    break;
                }
            }
        }

        /**         * 第一次訪問(沒有cookie 或 有cookie,但沒有名為lastTime的cookie)         */
        if(cookies==null || lastTime==null){
            //1.顯示當前時間到瀏覽器
            response.getWriter().write("你是首次訪問本網站,當前時間為:"+curTime);
            //2.建立Cookie物件
            Cookie cookie = new Cookie("lastTime",curTime);
            cookie.setMaxAge(1*30*24*60*60);//儲存一個月
            //3.把cookie傳送到瀏覽器儲存
            response.addCookie(cookie);
        }
    }
}

2.6.Cookie案例:檢視使用者瀏覽過的商品

邏輯圖

這個專案的程式碼較多,按照功能的不同放在不同的包裡面
公司域名的倒寫+專案名字+功能名字
cenyu.hist.entity 存放實體物件
cenyu.hist.dao Data Access Object 資料訪問物件,主要存放實體物件的一些方法(CRUD-create,read,update,delete)
cenyu.hist.servlet 存放servlet程式
cenyu.hist.ytil 存放工具類
cenyu.hist.test 存放測試類
等等
寫的順序:實體物件-->DAO類-->Servlet程式

程式碼:暫無

3.Session技術

3.1.什麼是Session

Session是伺服器端技術,利用這個技術,伺服器在執行時可以為每一個使用者的資料建立一個其獨享的Session物件,由於Session為使用者瀏覽器獨享,所以當用戶在訪問伺服器的web資源時,可以把各自的資料放在各自的Session中,當用戶再去訪問伺服器中的其他的web資源的時候,其他的web資源再從使用者各自的Session中取出資料為使用者服務。

注:

session技術的實現要依賴於cookie技術(即要通過http 協議中的cookie傳播技術)。當然如果客戶端禁止了cookie功能,則必須中URL重寫技術來傳遞JSESSIONID數值了。

3.2.Session的核心技術

Session的類是HttpSession類:用於儲存會話資料
1.建立或得到session物件
HttpSession getSession() 直接建立一個Session物件
HttpSession getSession(boolean create) 接收布林值,設定為true時,在沒有找到匹配Session編號的物件時新建一個Sessionu物件。如果設定false,則當找不到匹配的Session時,返回null,建議不要用
2.設定session物件
void setMaxInactiveInterval(int interval) : 設定session的有效時間
java.lang.String getId() : 得到session編號
void invalidate() : 銷燬session物件
Session物件的方法:
1.setMaxInactiveInterval方法預設30分鐘自動回收Session物件
2.使用setMaxInactiveInterval方法修改銷燬時間
3.在web.xml檔案中全域性修改Session預設回收時間

<!-- 修改session全域性有效時間:分鐘 -->
    <session-config>
        <session-timeout>1</session-timeout>
    </session-config>

4.通過invalidate方法,手動銷燬Session物件

3.儲存會話資料到session物件
void setAttribute(java.lang.String name, java.lang.Object value) : 儲存資料
java.lang.Object getAttribute(java.lang.String name) : 獲取資料
void removeAttribute(java.lang.String name) : 清除資料

4.如何避免瀏覽器的JSESSIONID的cookie隨著瀏覽器關閉而丟失的問題:
解決方法是手動傳送一個硬碟保護的cookie給瀏覽器
程式碼見案例:

/** * 測試Session的方法 */
@WebServlet(name = "SessionServletDemo")
public class SessionServletDemo extends HttpServlet {
    protectedvoiddoGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1.建立Session物件
        HttpSession session = request.getSession();

        //2.儲存會話資料
        session.setAttribute("name","eric");

        //3.取出會話資料
        String name = (String)session.getAttribute("name");
        System.out.println(name);

        //4.
        //拿到Session的id
        System.out.println(session.getId());
        //修改Session有效時間
        session.setMaxInactiveInterval(20);
        //銷燬session
        if (session!=null){
            session.invalidate();
        }
        //手動傳送一個硬碟儲存的cookie給瀏覽器
        Cookie c = new Cookie("JSESSION", session.getId());
        c.setMaxAge(60*60);
        response.addCookie(c);
    }
}

3.3.Session原理

程式碼解讀:HttpSession session = request.getSession();
偽碼分析執行過程
1.第一次訪問建立Session物件,給Session物件分配一個唯一的ID,叫JSESSIONID。

new HttpSession();

2.把JSESSIONID作為Cookie的值傳送給瀏覽器儲存

Cookie cookie = new Cookie("JSESSIONID", sessionID);
response.addCookie(cookie);

3.第二次訪問的時候,瀏覽器帶著JSESSIONID的cookie訪問伺服器
4.伺服器得到JSESSIONID,在伺服器的記憶體中搜索是否存放對應編號的session物件
5.如果找到對應編號的session物件,直接返回該物件
6.如果找不到對應編號session物件,建立新的session物件,繼續走1的流程

結論通過JSESSION的cookie值在伺服器找session物件

3.4.Session案例:使用者登入效果

需求:實現使用者登入效果,如果登入成功顯示:歡迎回來,×××。如果失敗,顯示登入失敗
使用Session區分不同的使用者來實現,整個程式碼實現分為三塊,登入表單提交之後的處理邏輯,登入邏輯,登出邏輯:
預設登入介面。index.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>登入頁面</title>
    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <form action="/day12/LoginServlet" method="post">
        使用者名稱:<input type="text" name="userName"/>
        <br/>
        密碼:<input type="text" name="userPwd"/>
        <br/>
        <input type="submit" value="登入"/>
    </form>
  </body>
</html>

登入失敗頁面:fail.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>資訊提示頁面</title>
    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <font color='red' size='3'>親, 你的使用者名稱或密碼輸入有誤!請重新輸入!</font><br/>
    <a href="/day12/login.html">返回登入頁面</a>
  </body>
</html>

表單提交之後的主處理邏輯:IndexServlet.java

/** * 使用者主頁的邏輯 * */
public class IndexServlet extends HttpServlet {

    publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        
        
        String html = "";
        
        /**         * 接收request域物件的資料         */
        /*        String loginName = (String)request.getAttribute("loginName");        */
        
        /**         * 二、在使用者主頁,判斷session不為空且存在指定的屬性才視為登入成功!才能訪問資源。         * 從session域中獲取會話資料         */
        //1.得到session物件
        HttpSession session = request.getSession(false);
        if(session==null){
            //沒有登入成功,跳轉到登入頁面
            response.sendRedirect(request.getContextPath()+"/login.html");
            return;
        }
        //2.取出會話資料
        String loginName = (String)session.getAttribute("loginName");
        if(loginName==null){
            //沒有登入成功,跳轉到登入頁面
            response.sendRedirect(request.getContextPath()+"/login.html");
            return;
        }
        
        html = "<html><body>歡迎回來,"+loginName+",<a href='"+request.getContextPath()+"/LogoutServlet'>安全退出</a></body></html>";
        
        
        writer.write(html);
    }

    publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

登入處理邏輯:LoginServlet.java

/** * 處理登入的邏輯 * */
public class LoginServlet extends HttpServlet {

    publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        //1.接收引數
        String userName = request.getParameter("userName");
        String userPwd = request.getParameter("userPwd");
        
        //2.判斷邏輯
        if("eric".equals(userName)
                 && "123456".equals(userPwd)){
            //登入成功
            /**             * 分析:             *    context域物件:不合適,可能會覆蓋資料。             *    request域物