HttpSession详解(简称session)

session概述

  • Session表示会话,不止是在javaweb中存在,只要是web开发,都有会话这种机制。
  • 在java中会话对应的类型是:javax.servlet.http.HttpSession,简称session/会话
  • 在java web中session是一个存储在WEB服务器端的java对象,该对象代表用户和WEB服务器的一次会话。

那什么才叫一次会话呢?

  • 一般多数情况下,是这样描述的:用户打开浏览器,在浏览器上进行一些操作,然后将浏览器关闭,表示一次会话结束。
  • 本质上的描述:从session对象的创建,到最终session对象超时之后销毁,这个才是真正意义的一次完整会话。
  • Cookie可以将会话状态保存在浏览器客户端,HttpSession可以将会话状态保存在WEB服务器端。
  • 在会话进行过程中,web服务器一直为当前这个用户维护者一个会话对象/HttpSession
  • 在WEB容器中,WEB容器维护者大量的HttpSession对象,换句话说,在WEB容器中应该有一个“session列表”
    • 也就是说张三访问WEB服务器,服务器会生成一个张三的session对象,李四去访问WEB服务器,服务器会生成一个李四的session对象。
    • 系统为每一个访问者都设立了独立的session对象,用以存取数据,并且各个访问者的session对象互不干扰。
  • session与cookie是紧密相关的
    • Cookie可以将会话状态保存在客户端,HttpSession可以将会话状态保存在服务器端。
    • session的使用要求用户浏览器必须支持cookie,如果浏览器不支持使用cookie,或者设置为禁用cookie,那么将不能使用session。

思考以下问题???

假设有两个用户,一个是北京的张三,一个是南京的李四,都在访问京东商城购物网站,那么在京东WEB服务器中一定会有两个购物车,一个是张三的购物车,一个是属于李四的购物车,大家思考:一个WEB服务器,两个浏览器客户端,为什么张三在购物的时候向购物车中放入的商品一定是放到张三的购物车中,而不会存放到李四的购物车中,也就是说session是怎么实现和某个特定用户绑定的?

  • 下面使用图形描述session的工作原理:
    在这里插入图片描述

session的工作原理:

 1. 打开浏览器,在浏览器上发送首次请求
 2. 服务器会创建一个HttpSession对象,该对象代表一次会话
 3. 同时生成HttpSession对象对应的Cookie对象,并且Cookie对象的name是jsessionid,Cookie的value是32位长度的字符串(jsessionid=xxxx)
 4. 服务器将Cookie的value和HttpSession对象绑定到session列表中
 5. 服务器将Cookie完整发送给浏览器客户端
 6. 浏览器客户端将Cookie保存到缓存中
 7. 只要浏览器不关闭,Cookie就不会消失
 8. 当再次发送请求的时候,会自动提交缓存中当的Cookie
 9. 服务器接收到Cookie,验证该Cookie的name是否是jsessionid,然后获取该Cookie的value
 10. 通过Cookie的value去session列表中检索对应的HttpSession对象 
  • 要注意的是
  • 当浏览器关闭之后,缓存中的cookie消失,这样客户端下次再访问服务器的时候就无法获取到服务器端的session对象了。这就意味着会话已经结束,但是并不代表服务器端的session对象马上被回收,session对象仍然在session列表中存储,当长时间没有用户访问这个session对象了,我们称作session超时,此时web服务器才会回收session对象。

1、浏览器关闭之后,服务器对应的session对象会被销毁吗?

  • 浏览器关闭之后,服务器不会销毁session对象
  • 因为B/S架构的系统基于HTTP协议,而HTTP协议是一种无连接/无状态的协议
  • 那什么是无连接/无状态呢?
    • 请求的瞬间浏览器和服务器之间的通道是打开的,请求响应结束之后,通道关闭
    • 这样做的目的是降低服务器的压力

2、session对象在什么时候被销毁?

  • 当很长一段时间(这个时间可以配置)没有用户再访问session对象,此时session对象超时,web服务器会自动回收session对象
  • 可以配置这个超时时间,在web.xml文件中,其默认是30分钟
    <session-config> <session-timeout>120</session-timeout> </session-config>

3、那什么情况下才是一次会话结束呢?
1.浏览器关闭,缓存中的Cookie消失,会话不一定结束,因为服务器端session对象还没有被销毁。这时我们可以通过URL重写机制继承访问session对象。
2. 浏览器没关闭,但是由于长时间没有访问web服务器,服务器判定session超时,将session对象销毁。此时浏览器虽然没有关闭,但是这次会话已经结束。
3. session对象所关联的这个Cookie的name有点特殊,这个name必须是jsessionid全部小写,这时HTTP协议规定的。
4.浏览器禁用了Cookie,可以采用URL重写机制(这样编码的代价比较大,所以一般网站都是不允许禁用Cookie的)
5.怎么重写URL:http://ip:port/webapp/servlet/accessSys;jsessionid=xxxxxx

关于javax.servlet.http.HttpSession接口中常用方法:

  • 获取session对象,如果获取不到则新建
request.getSession(true); request.getSession();
  • 获取session对象,如果获取不到则返回null
request.getSession(false);
  • 向session中存储一个数据
void setAttribute(String name, Object value);
  • 从session范围中取出数据
Object getAttribute(String name);
  • 从session范围中删除数据
void removeAttribute(String name);
  • 销毁session
void invalidate();

可以通过以下Demo案例将这些方法运用起来

  • 第一步:创建欢迎页面login.html,其中里面的第一个超链接的路径指向向会话范围中存储一个数据的类,第二个超链接的路径指向从会话范围中取出数据的类,第三个超链接的路径指向销毁session对象的类。
<body>
    <a href="/hcz21/user/accessMySelfSessionServlet">访问属于我的会话对象</a>
    <br>
    <a href="/hcz21/user/getDataFromSession">从会话对象取出数据</a>
    <br>
    <a href="/hcz21/logout">安全退出</a>
</body>
  • 第二步:在web.xml文件中配置第一步超链接中指定的路径
<welcome-file-list>
    <welcome-file>login.html</welcome-file>
</welcome-file-list>

<servlet>
    <servlet-name>accessMySelfSessionServlet</servlet-name>
    <servlet-class>com.javaweb.servlet.AccessMySelfSessionServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>accessMySelfSessionServlet</servlet-name>
    <url-pattern>/user/accessMySelfSessionServlet</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>getDataFromSession</servlet-name>
    <servlet-class>com.javaweb.servlet.GetDataFromSessionServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>getDataFromSession</servlet-name>
    <url-pattern>/user/getDataFromSession</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>logout</servlet-name>
    <servlet-class>com.javaweb.servlet.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>logout</servlet-name>
    <url-pattern>/logout</url-pattern>
</servlet-mapping>
  • 第三步:创建AccessMySelfSessionServlet.java类,继承HttpServlet接口并重写doGet方法,通过request获取当前的session对象,然后向会话范围中存储一个数据
public class AccessMySelfSessionServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        String ip = request.getRemoteAddr();
        HttpSession session = request.getSession();
        System.out.println(ip+"'s session ="+session);

        //向session中存储一个数据
        session.setAttribute("username","张三");
    }
}
  • 第四步:创建GetDataFromSessionServlet.java类,继承HttpServlet接口并重写doGet方法,通过request获取当前的session对象,然后从session范围中取出数据
public class GetDataFromSessionServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        HttpSession session = request.getSession();
        //从session范围中取出数据
        Object username = session.getAttribute("username");
        System.out.println(username);
    }
}
  • 第五步:创建LogoutServlet.java类,继承HttpServlet接口并重写doGet方法,通过request获取当前的session对象,然后销毁session对象
public class LogoutServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //获取session对象,若没有获取到session对象则创建一个session对象、
        //HttpSession session = request.getSession();

        //获取session对象,若没有获取到session对象则创建一个session对象、
        //HttpSession session = request.getSession(true);

        //获取session对象,若没有获取到session对象则返回null
        HttpSession session = request.getSession(false);
        if (session!=null){
    
    
            //销毁session对象
            session.invalidate();
        }
    }
}
  • 第六步:当点击访问属于我的会话对象这个超链接,就把“username=张三”这个数据存储到服务器中;当再接着点击从会话对象取出数据这个超链接,就可以把“username=张三”这个数据取出来,运行结果如下图:
    运行结果图
  • 第七步:当点击安全退出这个超链接,这时服务器会把该用户的session销毁;当再接着点击从会话对象取出数据这个超链接时,取出来的数据为空,运行结果如下图:
    运行结果图

ServletContext、HttpSession、HttpServletRequest接口的对比:

  • 1、以上都是范围对象:
    • ServletContext application; 是应用范围
    • HttpSession session; 是会话范围
    • HttpServletRequest request; 是请求范围
  • 2、三个范围的排序:
    • application > session > request

相同点:都可以用来传递数据,都有相同的存取数据方法

  • 存:session.setAttribute(“name”,ObjectValue);
  • 取:Object value = session.getAttribute(“name”);
  • 删: session.removeAttribute(“name”);

不同点

  • ServletContext(application)是Servlet上下文对象,在服务器启动阶段解析web.xml文件创建ServletContext对象,在同一个webabb中所有的Servlet对象共享同一个ServletContext对象。该对象一旦创建不会被销毁,除非服务器停掉。i. 所以尽量不要往这个对象中存放大数据,因为这是一个所有用户共享的空间,往该对象中存储的数据在多线程环境下涉及到修改操作的话注意线程安全问题。一般存储在该对象中的数据首先是所有用户共享的,不会被修改的,少量数据。ServletContext对象传递数据可以跨Servlet、跨请求、跨用户(跨会话)传递数据
  • HttpSession(session)是会话对象,每一个用户都有一个这样的对象,存储在该对象中的数据一般都是该用户专属的数据,例如购物车对象可以存储在session中,HttpSession对象传递数据可以跨Servlet、跨请求(这些请求必须属于同一个会话)、但是不能跨用户传递数据
  • HttpServletRequest(request)是请求对象,一次请求一个对象,每一次请求都会新建一个请求对象,是一个请求级别的对象,存储该对象中的数据一般都是请求级别的数据,一次请求之后这个数据就不再使用的数据可以存储在该对象中,HttpServletRequest对象传递数据可以跨Servlet,但是不能跨请求,更不能跨用户传递数据
  • 3、使用原则:由小到大尝试,优先使用小范围(考虑原则:request< session < application)
    • 例如:登录成功之后,已经登录的状态需要保存起来,可以将登录成功的这个状态保存到session对象中。登录成功状态不能保存到request范围中,因为一次请求对应一个新的request对象。登录成功状态也不能保存到application范围中,因为登录成功状态是属于会话级别的,不能所有用户共享。

猜你喜欢

转载自blog.csdn.net/hcz666/article/details/108916119
今日推荐