Cookie&Session

Cookie&Session

Cookie

一、概念

是一种客户端会话技术,其实就是保存在我们客户端上的一小份数据,以后执行请求就会自动带着这个cookie过去给服务器。 ,针对一次会话的多次请求有效。

Cookie和浏览器缓存有什么区别?

浏览器缓存可以缓存任意内容,上网浏览的任意内容。
Cookie只是缓存服务器需要浏览器缓存的数据。(是浏览器缓存中的一部分)

为什么要有Cookie?

原因是Http协议是无状态协议。 
服务器有时候需要知道发起这次请求的客户端是否是以前的某一次来访的客户端,
以便做出更精确服务。 这时候就需要使用到cookie了。

二、使用

1.创建Cookie对象

第一次请求,客户端发送的请求没有cookie信息,创建Cookie对象:

Cookie cookie = new Cookie(String name,String value);
这里的参数用于存储数据,都必须是String类型。

2.将Cookie对象写回客户端

response.addCookie(cookie);

3.获取Cookie对象

后续的客户端请求,会携带cookie信息。通过request对象获取客户端请求发送过来的请求字段.
返回的是cookies的key的数组

String[] cookies = request.getCookies();

4.其他方法

cookie.setMaxAge(int) : 设置Cookie的最大缓存事件,以秒为单位,超过就销毁
cookie.setPath() : 设置Cookie的有效路径
cookie.getName() : 获取该cookie的名称
cookie.getValue() : 获取该cookie的值

三、Cookie的分类

  • cookie的类型

    1. 临时性cookie

       默认的。没有针对cookie做任何设置,只要关闭了浏览器,Cookie就销毁了。
      
    2. 持久性cookie

       设置有效时长,会保存到磁盘中,在一定的范围内都有效。
      
       如果设置的是 0 表示要删除cookie, 立即删除 , 如果是 -1 ,那么是关闭浏览器后删除
       cookie.setMaxAge(60*60*24 *7); 
      
      
       设置有效路径:
       cookie.setPath(url):
       
       1. cookie.setPath("/day16/demo");
       表示day16项目下,【demo目录】下的所有servlet都可以访问当前cookie。但/day16或/day16/aa不能访问
      
       2. cookie.setPath("/day16");
       表示【day16项目】下的所有servlet都可以访问当前cookie
      
       3. cookie.setPath("/");
       表示【Tomcat下】的所有项目都可以访问当前cookie
      
      
       例
       Cookie cookie = new Cookie("password","admin123");  
       //设置有效期7天。
       cookie.setMaxAge(60*60*24 *7); 
       
       //设置cookie跨域名共享。 domain 域名.   taobao tmall 
       cookie.setDomain(".taobao.com");
       
       //设置当前服务器里面的跨项目共享。
       cookie.setPath("/");
       
       response.addCookie(cookie);
      

Session

一、概念

是一种服务器端会话技术,基于|依赖Cookie存在

  • Cookie 和 Session的对比

    cookie

      数据存放在客户端
    
      数据不安全
    
      减轻服务器压力, 用户磁盘占用比较多。 
    
      存放的数据有限
    

    session

      数据存放在服务器端
    
      数据相对比较安全。
    
      服务器压力大一点。
    
      存放的数据 依赖服务器的内存空间。 
    

    基于 | 依赖cookie的一种会话技术。

二、使用

因为Session是基于Cookie存在的,Cookie随着请求发送到服务器,因此Session也是使用request对象获取。

1.获取Session对象

HttpSession session = request.getSession();//获取到Session的时候会产生一个唯一的ID值

2.Session对象存|取值

session.setAttribute(String name,Object value) : 存值

session.getAttribute(String name) : 取值

session.removeAttribute() : 移除某个值

set和get的name值一致才能取出来。

3.其他方法

session.invalidate() : 销毁Session对象
session.getID() : 获取当前session的的ID值
-------------------------------------

三、Session的背后细节

    //这里获取session的机制是这样的。 
    
    // 第一次来访问,
    
    /*那么session都没有创建,并且咱们的请求对象里面也不带任何的cookie过来。 
    
    那么这个时候会在内存中给你创建一个新的session区域,并且把这个session的id值给我们的浏览器返回。
    
    如果是第二次访问,那么浏览器会把之前的那个cookie给带过来, 服务器收到了cookie,里面有我们上一次给的
    
    sessionid 值, 那么这个时候再调用request.getSesion() , 它先会拿我们待过来的id ,到内存里面去找有没有session的 id值
    跟这个cookie带过来的一样 ,如果有,就直接返回这个内存空间, 否则就创建新的session空间 
    */

    public HttpSession getSession()
    返回与此请求关联的当前会话,如果该请求没有会话,则创建一个会话。 如果有就返回这个会话Session对象

下图说明:

![Session的创建.png](http://upload-images.jianshu.io/upload_images/5303154-45eddd26e2728700.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

四、作用域&生命周期

  • 作用域

    在一次会话的多次请求中有效

  • 生命周期

    • 何时创建 :

        在第一次调用request.getSession()时创建
      
    • 何时销毁 :

        1. 服务器非正常关闭时销毁。 服务器正常关闭时序列化(钝化)
        2. Session对象超时。默认30分钟。(从最后一次请求开始算起)
        3. 调用session.invalidate()方法手动销毁
      

有关Session的一个问题:

1. 浏览器关闭后,之前的Session对象会销毁吗?这个时候getSession()获得的Session对象还是之前的那个吗?

2. 如果不是的话,为什么?还能取到之前setAttribute()存进去的值吗?

3. 如果不能取到,但是我就是想要获取到之前的Session对象该怎么做?

解答:

1. 不会销毁。因为Session对象是服务器开辟的一个内存空间,与客户端浏览器的关闭与否没有关系。
在关闭浏览器后重新发起请求时获取的Session对象就不是之前的那个了,因为Session的定位是依靠
请求发送到服务器的Cookie:JESSIONID的,关闭后Cookie对象消失了,它的ID也就没了,因此就找不
之前的Session对象了。

2. 既然获取的Session对象与之前的Session对象不是同一个对象,那么自然就获取不到之前存入的值了。


3. 自己取那个sessionid ,然后自己存到cookie里面,并且给cookie设置有效期。 

    注意: cookie的那个name不能乱写。 JSESSIONID :  

五、三个域的对比

1. ServletContex

  • 作用域

      当前ServletContex对象的整个项目
    
  • 生命周期

      何时创建:
          服务器启动(这里是被托管的项目的ServletContext创建) | 项目部署
    
      何时销毁:
          服务器关闭 | 项目移除
    
  • 作用

      1. 存 | 取值
      2. 获取全局参数   (web.xml的Context-Param中的全局参数)
      3. 获取项目下的任意位置的资源
    

2. Session

  • 作用域

      一次会话的多次请求有效
    
  • 生命周期

      何时创建:
          第一次调用request.getSession()时创建
    
      何时销毁:
          1. 服务器非正常关闭时销毁  服务器正常关闭时序列化(钝化)
          2. Session对象等待超时
          3. 手动调用session.invalidate()销毁
    
  • 作用

3. Request

  • 作用域

      一次请求中有效
    
  • 生命周期

      何时创建:
          每次请求都会创建一个Request和一个Response对象
    
      何时销毁:
          服务器对客户端做出了响应后
    
  • 作用

六、案例

案例一:简易的访问时间的案例(Cookie)

需求:
    A:写一个用户登录页面,用户填写账号密码后,校验是否成功登陆
        校验失败:告知用户登录失败,2秒后回到登录页面重新登陆
        校验成功,登陆成功。

    B:获取用户客户端的Cookie。用于获取用户上一次登陆的时间
        如果存在Cookie值,遍历获取到存储上次访问时间的Cokkie对象,输出到客户端,并存储当前访问时间到客户端
        如果不存在Cookie对象,欢迎用户登录,存储访问时间写回到客户端

代码实现:

public class LastVisitedTimeDemo extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 利用Cookie存储访问时间,在访问时输出上次访问时间在控制台。
        
        response.setContentType("text/html;charset=UTF-8");// 告诉服务器和客户端都以UTF-8编解码

        // 获取用户的提交的表单参数,如果账号密码正确登陆成功
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        
        PrintWriter out = response.getWriter();//获取输出流

        if (username.equals("admin") && password.equals("123")) {
            // 获取Cookie对象,判断是否是新用户
            Cookie[] cookies = request.getCookies();
            if (cookies != null) { // 不是新用户
                // 获取存储时间的cookie对象
                for (int i = 0; i < cookies.length; i++) {
                    if (cookies[i].getName().equals("LastVisitedTime")) {
                        
                        // 获取cookie的值
                        String value = cookies[i].getValue();
                        // 将毫秒值转换成有意义的日期
                        String localDate = new Date(Long.parseLong(value)).toLocaleString();
                        // 输出最后一次访问时间在浏览器
                        out.write("<h3>欢迎用户:"+username+"回来,您上次访问的时间是:" + localDate+"<h3>");
                    }
                }
            }else { //是新用户
                out.println("<h3>欢迎用户:"+username+"</h3>");
            }
            //无论是否是有cookie缓存的用户,最后都要记录当前的毫秒值添加进cookie写回客户端保存
            //创建Cookie对象
            Cookie cookie = new Cookie("LastVisitedTime", ""+System.currentTimeMillis());
            //将cookie对象写回客户端保存
            response.addCookie(cookie);
        }else {
            out.println("<h3>登录失败,请重新登录</h3>");
            response.setHeader("refresh", "2;"+getServletContext().getContextPath()+"/Login.html");
        }
    }

案例二:简易的购物车(Session)

需求:
    在商品界面点击商品,将其添加至购物车。跳转页面:
        继续购物:
            返回到之前的商品选择页面。

        购物结算:
            获取到用户点击

思路:

购物车案例思路.png

代码实现

商品购物页面

<a href="cart?id=0">苹果8</a><br/>
<a href="cart?id=1">华为10</a><br/>
<a href="cart?id=2">vivo9</a><br/>
<a href="cart?id=3">魅族6</a><br/>
<a href="cart?id=4">小米7</a><br/>
<a href="cart?id=5">oppoR9s</a><br/>

通过携带参数id用于区分不同的商品

业务处理Servlet

//商品数组
private static String[] phones = {"苹果8","华为10","vivo9","魅族6","小米7","oppoR9s"};

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.获取Session对象
    //寻找客户端是否有携带JSESSIONID的Cookie过来,如果有,通过这个ID找到ID对应Session对象并返回,如果没有就重新创建一个新的Session对象
    HttpSession session = request.getSession();
    
    //获取存储在session中的购物车cartMap
    Map<String, Integer> cartMap = (Map<String, Integer>) session.getAttribute("cartMap");

    //2.判断cartMap是否为空
    if(cartMap == null) { //如果购物车为空,说明用户第一次访问,为其创建购物车Map对象
         cartMap = new HashMap<>();
    }
    
    //3.获取到发送请求的商品的ID值,并将String类型转换为int类型
    int id = Integer.parseInt(request.getParameter("id"));
    //通过id值获取到对应的商品名称
    String phone = phones[id];
    
    //4.判断cartMap中是否包含该商品
    if(cartMap.containsKey(phone)) {    //如果包含当前商品,重新设置键值对
        cartMap.put(phone, cartMap.get(phone)+1);
    }else { //如果不包含当前商品,设置键值对:商品名:1
        cartMap.put(phone, 1);
    }
    //5.将购物车添加至服务器Session对象存储
    session.setAttribute("cartMap", cartMap);
    
    //为了让关闭浏览器之后重新访问还能找到之前的Session对象,获取到该SessionID添加到Cookie里面返回给客户端
    //Cookie的key一定要写成JSESSIONID才能找到
    String sessionId = session.getId();
    Cookie cookie = new Cookie("JSESSIONID", sessionId);
    cookie.setMaxAge(60*24);//让该Cookie有效期为一天
    response.addCookie(cookie);
    
    //6.分发跳转,跳转到中转页面,用户选择继续购物或是结算商品
    response.sendRedirect("select.html");//由于是用session存值,同一会话的多次请求有效,用请求转发和重定向都可以
}

中转选择页面

<p><a href="list.html"><h4>继续购物</h4></a></p>
<a href="result.jsp"><h4>购物结算</h4></a>

商品结算页面

<body>
    <!-- 在这里取出购物车 -->
    <%
        //这里的session就是CartServlet的session,通过这个session取得购物车cartMap集合
        Map<String, Integer> cartMap = (Map<String, Integer>) session.getAttribute("cartMap");
        //keySet()获取到Map集合中所有key的集合
        Set<String> names = cartMap.keySet();
        //遍历集合取得所有的key和value写成页面
        %>
        <b>商品名称</b>  <b>数量</b><br/>
        <% 
        for (String name : names) {
            int number = cartMap.get(name);
    %>
        <b><%=name+" : " %></b>  <b><%=number%></b><br/>
    <%
        }
    %>
</body>

结果显示:

结果展示

~~~欢迎指正与交流。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容