为了账号安全,请及时绑定邮箱和手机立即绑定

Session详解

标签:
Java

Session

Session简介

Session是一种记录客户状态的机制,不同于Cookie的是Cookie保存在客户端浏览器中,而Session保存在服务器上。
客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。
客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的"通行证"来确定客户身份的话,
那么Session机制就是通过检查服务器上的"客户明细表"来确认客户身份。
Session相当于程序在服务器上建立的一份客户档案,
客户来访的时候只需要查询客户档案表就可以了。

Session机制

一方面,我们可以把客户端浏览器与服务器之间一系列交互的动作称为一个 Session。
从这个语义出发,我们会提到Session持续的时间,会提到在Session过程中进行了什么操作等等。

另一方面,Session指的是服务器端为客户端所开辟的存储空间,该空间保存的信息就是用于保持状态。
从这个语义出发,我们则会提到往Session中存放什么内容,如何根据键值从Session中获取匹配的内容等。

  • 要使用Session,当然是先要创建Session。那么Session在何时创建呢?
  1. Session在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建Session的方法,
    在Java中是通过调用HttpServletRequest的getSession方法(使用true作为参数)创建的。
    创建Session的同时,服务器会为该Session生成唯一的session id
    这个session id在随后的请求中会被用来重新获得已经创建的Session

  2. Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,
    而这些内容只会保存在服务器中,发到客户端的只有session id

  3. 当客户端再次发送请求的时候,会将这个session id带上,
    服务器接受到请求之后就会依据session id找到相应的Session,从而再次使用Session。

Session的生命周期

Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存中。
每个用户都会有一个独立的Session
如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。
因此,Session里的信息应该尽量精简。

Session在用户第一次访问服务器的时候自动创建
需要注意只有访问JSP、Servlet等程序时才会创建Session,
只访问HTML、IMAGE等静态资源并不会创建Session。
如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。

Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。
用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session"活跃(active)"了一次。

Session的有效期

由于会有越来越多的用户访问服务器,因此Session也会越来越多。
为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。
这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。

Session的超时时间为maxInactiveInterval属性,
可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(longinterval)修改。

Session的超时时间也可以在web.xml中修改。
另外,通过调用Session的invalidate()方法可以使Session失效。

Session案例 : 购物车

获取Session

HttpSession getSession(); //request.getSession()

域对象

xxxAttribute  //存放私有数据

域对象生命周期

  • 创建:第一次调用request.getSession()
  • 销毁:
  1. 服务器非正常关闭;

  2. session超时;

默认超时时间:30 min

手动设置超时:setMaxInactiveInterval(int) (单位:秒)

  1. 手动设置;

Session接口中的invalidate()方法

public void invalidate()
  • 核心代码1:将商品添加到购物车
public class CartServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out=response.getWriter();

        //1.获取商品名称
        String name = request.getParameter("name");

        //2.获取购物车,实际上就是存入session的map
        HashMap<String,Integer> map = (HashMap<String, Integer>) request.getSession().getAttribute("cart");

        Integer num = null;

        //3.判断购物车是否为空
        if(map==null){
            //3.1 购物车为空,说明是第一次将商品放入购物车
            //先创建购物车,
            map = new HashMap<>();
            request.getSession().setAttribute("cart",map);
            num = 1;
        }else{
            //3.2 购物车不为空,判断该商品之前是否已经加入购物车
            num = map.get(name);
            if(num == null){
                //num==null,说明该商品之前未加入购物车
                num = 1;
            }else{
                num ++ ;
            }
        }
        map.put(name,num);

        //4.提示信息
        out.print("<center>已经将<b>"+name+"</b>添加到购物车中<hr></center>");
        out.print("<center><a href='"+request.getContextPath()+"/category_list.jsp'>继续购物</a></center><br/>");
        out.print("<center><a href='"+request.getContextPath()+"/cart.jsp'>查看购物车</a><center>");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
  • 显示购物车中信息
<body>
    <div class="container">
        <a href="${pageContext.request.contextPath}/category_list.jsp">继续购物</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        <a href="${pageContext.request.contextPath}/clearCart">清空购物车</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        <div class="row">
            <div style="margin:0 auto; margin-top:10px;width:950px;">
                <strong style="font-size:16px;margin:5px 0;">订单详情</strong>
                <table class="table table-bordered">
                    <tbody>
                    <tr class="warning" align="center">
                        <th>商品</th>
                        <th>数量</th>
                    </tr>
                    <%
                        HashMap<String,Integer> map = (HashMap<String,Integer>)request.getSession().getAttribute("cart");
                        if(map==null){
                            out.print("<tr><th colspan='2'>亲,购物车空空,先去逛逛~~</th></tr>");
                        }else{
                            for(String name : map.keySet()){
                                out.print("<tr class='active'>");

                                out.print("<td width='30%'>");
                                out.print(name);
                                out.print("</td>");
                                out.print("<td width='20%'>");
                                out.print(map.get(name));
                                out.print("</td>");

                                out.print("</tr>");
                            }
                        }
                    %>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</body>
  • 核心代码2:清空购物车
public class ClearCartServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().invalidate();

        response.sendRedirect(request.getContextPath()+"/cart.jsp");
    }

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

实现会话跟踪的技术

    1. Cookie

向客户端发送Cookie :

Cookie c =new Cookie("name","value"); //创建Cookie 
c.setMaxAge(60*60*24); //设置最大时效,此处设置的最大时效为一天
response.addCookie(c); //把Cookie放入到HTTP响应中

从客户端读取Cookie :

String name ="name"; 
Cookie[]cookies =request.getCookies(); 
if(cookies !=null){ 
   for(int i= 0;i<cookies.length;i++){ 
        Cookie cookie =cookies[i]; 
        if(name.equals(cookis.getName())) 
        //something is here. 
        //you can get the value 
        cookie.getValue(); 
   }
}

优点: 数据可以持久保存,不需要服务器资源,简单,基于文本的Key-Value

缺点: 大小受到限制,用户可以禁用Cookie功能,由于保存在本地,有一定的安全风险。

    1. URL 重写

在URL中添加用户会话的信息作为请求的参数,
或者将唯一的会话ID添加到URL结尾以标识一个会话。

优点: 在Cookie被禁用的时候依然可以使用

缺点: 必须对网站的URL进行编码,所有页面必须动态生成,不能用预先记录下来的URL进行访问。

    1. 隐藏的表单域
<input type="hidden" name ="session" value="..."/>

优点: Cookie被禁时可以使用

缺点: 所有页面必须是表单提交之后的结果。

    1. session

当一个用户第一次访问某个网站时会自动创建 HttpSession,每个用户可以访问他自己的HttpSession

可以通过HttpServletRequest对象的getSession方法获得HttpSession。
通过HttpSession的setAttribute方法可以将一个值放在HttpSession中,
通过调用 HttpSession对象的getAttribute方法,同时传入属性名就可以获取保存在HttpSession中的对象。

与上面三种方式不同的是,HttpSession放在服务器的内存中,因此不要将过大的对象放在里面。
即使目前的Servlet容器可以在内存将满时将 HttpSession 中的对象移到其他存储设备中,但是这样势必影响性能。
添加到 HttpSession 中的值可以是任意Java对象,这个对象最好实现了 Serializable接口,
这样Servlet容器在必要的时候可以将其序列化到文件中,否则在序列化时就会出现异常。

Cookie和Session的的区别

  1. HTTP协议是无状态的协议,服务端需要记录用户的状态,就需要用某种机制来识别具体的用户,这个机制就是Session。
    Session典型的应用场景就是购物车,当点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,
    所以服务端要为特定的用户创建了特定的Session,用于标识这个用户,并且跟踪用户,这样才知道购物车里面的商品情况。
    这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。
    集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,
    用来保存用户会话,这个时候 Session 信息都是放在内存的,此外,一些缓存服务比如Memcached之类的来放 Session。

  2. 服务端使用Cookie来识别特定的客户。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。
    实际上大多数的应用都是用 Cookie 来实现Session跟踪的,
    第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个session id,
    以后每次请求把这个 session id发送到服务器,这样就可以使用对应的Seesion了。
    如果客户端的浏览器禁用了 Cookie 怎么办?
    一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪
    即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。

  3. Cookie其实还可以用在一些方便用户的场景下,
    设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?
    这个信息可以写到Cookie里面,访问网站的时候,
    网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,
    能够方便一下用户。这也是Cookie名称的由来,给用户的一点甜头。

总结:

  • Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中。
  • Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消