JavaWeb基礎(chǔ)之Cookie與Session

Cookie:
Cookie是客戶端技術(shù)双谆,程序把每個用戶的數(shù)據(jù)以cookie的形式寫給用戶各自的瀏覽器狸捅。當(dāng)用戶使用瀏覽器再去訪問服務(wù)器中的web資源時偎巢,就會帶著各自的數(shù)據(jù)去微王。這樣屡限,web資源處理的就是用戶各自的數(shù)據(jù)了。
Session:
Session是服務(wù)器端技術(shù)骂远,利用這個技術(shù)囚霸,服務(wù)器在運行時可以為每一個用戶的瀏覽器創(chuàng)建一個其獨享的session對象,由于session為用戶瀏覽器獨享激才,所以用戶在訪問服務(wù)器的web資源時拓型,可以把各自的數(shù)據(jù)放在各自的session中,當(dāng)用戶再去訪問服務(wù)器中的其它web資源時瘸恼,其它web資源再從用戶各自的session中取出數(shù)據(jù)為用戶服務(wù)劣挫。

本文內(nèi)容

1.javax.servlet.http.Cookie

Java提供操作Cookie的API

1.1 演示Cookie的創(chuàng)建與使用

public class CookieDemo1 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.創(chuàng)建Cookie對象
        Cookie cookie1 = new Cookie("name","eric");
        
        
        /**
         * 1)設(shè)置cookie的有效路徑。默認情況:有效路徑在當(dāng)前web應(yīng)用下东帅。 /demo
               *有效路徑指的是cookie的有效路徑保存在哪里压固,那么瀏覽器在有效路徑下
              *訪問服務(wù)器時就會帶著cookie信息,否則不帶cookie信息靠闭。
         */
        //cookie1.setPath("/demo");
        
        /**
         * 2)設(shè)置cookie的有效時間
         * 正整數(shù):表示cookie數(shù)據(jù)保存瀏覽器的緩存目錄(硬盤中)帐我,數(shù)值表示保存的時間。
            負整數(shù):表示cookie數(shù)據(jù)保存瀏覽器的內(nèi)存中愧膀。瀏覽器關(guān)閉cookie就丟失了@辜!
            零:表示刪除同名的cookie數(shù)據(jù)

         */
        //cookie1.setMaxAge(20); //20秒檩淋,從最后不調(diào)用cookie開始計算
        cookie1.setMaxAge(-1); //cookie保存在瀏覽器內(nèi)存(會話cookie)
        //cookie1.setMaxAge(0);
        
        
        //2.把cookie數(shù)據(jù)發(fā)送到瀏覽器(通過響應(yīng)頭發(fā)送: set-cookie名稱)
        //response.setHeader("set-cookie", cookie.getName()+"="+cookie.getValue()+",email=eric@qq.com");
        //推薦使用這種方法芬为,避免手動發(fā)送cookie信息
        response.addCookie(cookie1);
        

        
        //3.接收瀏覽器發(fā)送的cookie信息
        /*String name = request.getHeader("cookie");
        System.out.println(name);*/
        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數(shù)據(jù)");
        }
        
    }

}

1.2. Cookie的使用實例,用戶上次訪問時間

public class HistServlet extends HttpServlet {

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

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

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

        /**
         * 第一次訪問(沒有cookie 或 有cookie氧敢,但沒有名為lastTime的cookie)
         */
        if (cookies == null || lastTime == null) {
            // 1.顯示當(dāng)前時間到瀏覽器
            response.getWriter().write("你是首次訪問本網(wǎng)站,當(dāng)前時間為:" + curTime);
            // 2.創(chuàng)建Cookie對象
            Cookie cookie = new Cookie("lastTime", curTime);
            cookie.setPath("/CookieDemo");
            cookie.setMaxAge(-1);// 設(shè)置瀏覽器關(guān)閉cookie就丟失
            // cookie.setMaxAge(1*30*24*60*60);//保存一個月
            // 3.把cookie發(fā)送到瀏覽器保存
            response.addCookie(cookie);
        }
    }

}

效果如下:


**第一次訪問時效果如下询张,可以看到請求頭里沒有帶任何Cookie信息孙乖,而響應(yīng)頭里面設(shè)置了Cookie的信息**
**當(dāng)?shù)诙渭昂竺娴脑L問時,請求頭里面都會帶有保存上次訪問的Cookie信息瑞侮,響應(yīng)頭里面會對這個信息進行更新的圆。**
**同時我們也可以在瀏覽器里看到該Cookie的詳細信息**

注意:瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie半火,每個Cookie的大小限制為4KB越妈。

2. javax.servlet.http.HttpSession

Java提供操作Session的API,服務(wù)器在瀏覽器第一次訪問時如果創(chuàng)建了一個Session對象就會給該對象分配一個id并以Cookie的形式保存在瀏覽器中,以后在有效期內(nèi)瀏覽器訪問服務(wù)器時就會帶著該id,服務(wù)器通過該id就能匹配到存儲在服務(wù)器中對應(yīng)的信息钮糖。

2.1 Sesision的存儲原理

Demo:

public class SessionDemo1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setCharacterEncoding("UTF=8");
        response.setContentType("text/html;charset=UTF-8");
        // 使用request對象的getSession()獲取session梅掠,如果session不存在則創(chuàng)建一個
        HttpSession session = request.getSession();
        // 將數(shù)據(jù)存儲到session中
        session.setAttribute("data", "acamy");
        // 獲取session的Id
        String sessionId = session.getId();
        // 判斷session是不是新創(chuàng)建的
        response.getWriter().println(new Date());
        if (session.isNew()) {
            response.getWriter().print("session創(chuàng)建成功,session的id是:" + sessionId);
        } else {
            response.getWriter().print(
                    "服務(wù)器已經(jīng)存在該session了店归,session的id是:" + sessionId);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

效果如下:


可以看到第一次訪問時瀏覽器會創(chuàng)建一個Session對象阎抒,給該對象分配一個id,并以JSESSIONID作為鍵消痛,id作為值以Cookie的形式保存在瀏覽器中
第二次訪問時瀏覽器發(fā)起請求時就會在Cookie里面帶著該id信息且叁,服務(wù)器就能根據(jù)這個id匹配存儲在服務(wù)器的里面的信息

2.2.瀏覽器禁用Cookie后的session處理

當(dāng)我們想實現(xiàn)提供用戶瀏覽過的商品時,利用上面的Cookie和Session思想很容易實現(xiàn)秩伞,但是如果瀏覽器作了上圖中的設(shè)置逞带,也就是禁用了Cookie,我們又該如何實現(xiàn)呢,這就需要用到URL重寫:

用于對sendRedirect方法后的url地址進行重寫纱新。
**response.encodeRedirectURL(java.lang.String url) **

//用于對表單action和超鏈接的url地址進行重寫
response.encodeURL(java.lang.String url)

String javax.servlet.http.HttpServletResponse.encodeURL(String url)
Encodes the specified URL by including the session ID in it, or, if encoding is not needed, returns the URL unchanged. The implementation of this method includes the logic to determine whether the session ID needs to be encoded in the URL. For example, if the browser supports cookies, or session tracking is turned off, URL encoding is unnecessary.
看了上面官方對該方法的解釋就是對特定的URL添加session ID進行編碼展氓,如果不需要的話就不會對URL作任何改變。所有對該方法的實現(xiàn)應(yīng)該包含判斷session ID的信息是否需要添加到URL里面對URL作改變的邏輯脸爱。例如遇汞,如果瀏覽器支持cookies,或者session跟蹤關(guān)了的話,就不對URL作改變簿废。

下面看實例源碼:

IndexServlet:首頁空入,列出所有書

public class IndexServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        // 創(chuàng)建Session
        request.getSession();

        out.write("本網(wǎng)站有如下書:<br/>");
        Set<Map.Entry<String, Book>> set = DB.getAll().entrySet();
        for (Map.Entry<String, Book> me : set) {
            Book book = me.getValue();
            String url = request.getContextPath() + "/buyServlet?id="
                    + book.getId();
            // response. encodeURL(java.lang.String
            // url)用于對表單action和超鏈接的url地址進行重寫,通過此方法帶上JSESSSIONID
            url = response.encodeURL(url);// 將超鏈接的url地址進行重寫
            out.println(book.getName() + "   <a href='" + url + "'>購買</a><br/>");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

/**
 * @author gacl 模擬數(shù)據(jù)庫
 */
class DB {
    private static Map<String, Book> map = new LinkedHashMap<String, Book>();
    static {
        map.put("1", new Book("1", "javaweb開發(fā)"));
        map.put("2", new Book("2", "spring開發(fā)"));
        map.put("3", new Book("3", "hibernate開發(fā)"));
        map.put("4", new Book("4", "struts開發(fā)"));
        map.put("5", new Book("5", "ajax開發(fā)"));
    }

    public static Map<String, Book> getAll() {
        return map;
    }
}

class Book {

    private String id;
    private String name;

    public Book() {
        super();
    }

    public Book(String id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

BuyServlet:點擊購買后的邏輯

public class BuyServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String id = request.getParameter("id");
        Book book = DB.getAll().get(id); // 得到用戶想買的書
        HttpSession session = request.getSession();

        HashSet<Book> set = (HashSet) session.getAttribute("set"); // 得到用戶用于保存所有書的容器
        if (set == null) {
            set = new HashSet<Book>();
            session.setAttribute("set", set);
        }
        set.add(book);
        // response. encodeRedirectURL(java.lang.String
        // url)用于對sendRedirect方法后的url地址進行重寫
        String url = request.getContextPath() + "/listCartServlet";
        url = response.encodeRedirectURL(url);//通過此方法帶上JSESSSIONID
        System.out.println(url);
        response.sendRedirect(url);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

ListCartServlet:購物車頁面

public class ListCartServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        HttpSession session = request.getSession();

        HashSet<Book> set = (HashSet) session.getAttribute("set");
        if (set == null || set.size() == 0) {
            out.write("對不起族檬,您還沒有購買任何商品!!");
            return;
        }

        // 顯示用戶買過的商品
        out.write("您買過如下商品:<br>");
        for (Book book : set) {
            out.write(book.getName() + "<br/>");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

查看首頁源碼如下:

每個超鏈接都被encode加上了JSESSSIONID的信息歪赢,所以在訪問BuyServlet帶著此信息就相當(dāng)于帶著session信息,而BuyServlet在跳轉(zhuǎn)到ListCartServlet也會把url encode一下帶上JSESSSIONID导梆,三個Servlet由此實現(xiàn)了session共享轨淌。

但當(dāng)我們刷新列表頁時會發(fā)現(xiàn)URL里面帶的JSESSSIONID已經(jīng)改變,購物車頁面也會清空看尼,所以并不能實現(xiàn)完全沒禁用Cookie效果递鹉。

當(dāng)我們開啟Cookie時,只有在第一次訪問列表頁面時會有JSESSSIONID的信息,但我們刷新列表頁面時藏斩,購物車頁面沒有清空躏结,頁面源碼如下所示,沒有了JSESSSIONID的信息狰域,證明了encode方法的智能性媳拴。

2.3 session對象的銷毀時機

session對象默認30分鐘沒有使用,則服務(wù)器會自動銷毀session兆览,在web.xml文件中可以手工配置session的失效時間屈溉,例如:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <!-- 設(shè)置Session的有效時間:以分鐘為單位-->
    <session-config>
        <session-timeout>15</session-timeout>
    </session-config>

</web-app>

當(dāng)需要在程序中手動設(shè)置Session失效時,可以手工調(diào)用session.invalidate方法抬探,摧毀session子巾。

HttpSession session = request.getSession();
//手工調(diào)用session.invalidate方法,摧毀session
session.invalidate();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末小压,一起剝皮案震驚了整個濱河市线梗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怠益,老刑警劉巖仪搔,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蜻牢,居然都是意外死亡烤咧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門孩饼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來髓削,“玉大人,你說我怎么就攤上這事镀娶×⑻牛” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵宝泵,是天一觀的道長。 經(jīng)常有香客問我轩娶,道長,這世上最難降的妖魔是什么鳄抒? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任椰弊,我火速辦了婚禮瓤鼻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茬祷。我一直安慰自己清焕,他們只是感情好祭犯,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沃粗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪最盅。 梳的紋絲不亂的頭發(fā)上影晓,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音檩禾,去河邊找鬼挂签。 笑死,一個胖子當(dāng)著我的面吹牛盼产,可吹牛的內(nèi)容都是我干的饵婆。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼戏售,長吁一口氣:“原來是場噩夢啊……” “哼侨核!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起灌灾,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤搓译,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后锋喜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體些己,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年嘿般,在試婚紗的時候發(fā)現(xiàn)自己被綠了段标。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡炉奴,死狀恐怖逼庞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞻赶,我是刑警寧澤赛糟,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布派任,位于F島的核電站,受9級特大地震影響璧南,放射性物質(zhì)發(fā)生泄漏吨瞎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一穆咐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧字旭,春花似錦对湃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至屈暗,卻和暖如春拆讯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背养叛。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工弃甥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人淆攻。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓瓶珊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忘苛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容