• 会话技术之 Session


    会话技术之 Session


    文章中所有源代码都在我的这个GitHub的公开库--->servletStar来一个好吗?秋梨膏!


    不多废话,先来一个 HelloWorld。

    Session 有 get 肯定要先有 set 。

    @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //设置编码
            resp.setContentType("text/html;charset=UTF-8");
            // get 到session
            HttpSession session = req.getSession();
            //有中文,别忘了编码再传进去
            session.setAttribute("HelloWorld", URLEncoder.encode("Hello--World!向世界宣告我的到来!","UTF-8"));
        }
    

    这里分两个Servlet编写

    @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //设置编码
            resp.setContentType("text/html;charset=UTF-8");
            // get 到 session
            HttpSession session = req.getSession();
    //        获取到值,别忘了解码
            String  helloWorld =  URLDecoder.decode((String) session.getAttribute("HelloWorld"),"UTF-8");
            //输出一下
            resp.getWriter().write(helloWorld);
        }
    

    Session API

    • long getCreationTime();【获取Session被创建时间】
    • String getId();【获取Session的id】
    • long getLastAccessedTime();【返回Session上一次访问的时间】
    • ServletContext getServletContext();【获取ServletContext对象】
    • void setMaxInactiveInterval(int var1);【设置Session超时时间】
    • int getMaxInactiveInterval();【获取Session超时时间】
    • Object getAttribute(String var1);【获取Session属性】
    • Enumeration getAttributeNames();【获取Session所有的属性名】
    • void setAttribute(String var1, Object var2);【设置Session属性】
    • void removeAttribute(String var1);【移除Session属性,注意,不是销毁该Session
    • void invalidate();【销毁该Session】
    • boolean isNew();【该Session是否为新的】

    还有些过时的方法就不一一列举了

    Session 有效期

    在此之前先说一下 Session 的对象,是一个域对象, 只要Session 还没有被销毁(或者浏览器没有关闭),Servlet 就可以通过 Session 对象进行数据传递。

    Session 的生命周期可以通过方法去控制的,直接杀死销毁掉,当然关闭浏览器也是可以直接杀死掉的。

    //销毁该 session
            session.invalidate();
    

    还有可以通过时间的预先设置,在此时间段内目标Session 没有被访问,就会进行销毁。这是服务器出于防止内存溢出的考虑,将最久未访问的销毁。不知你是否嗅到了 least recently used (LRU)算法的味道。

    这种方式又有三种途径可以去实现,同时作用范围也不尽相同。

    在 Tomcat 的 web.xml 配置文件中配置(对部署在该服务器上的应用有效

    可以看到默认的配置:

    image-20200906215627123

    以分钟为单位,默认是 30 分钟。

    接下来照葫芦画瓢,修改为 20 分钟:

    <session-config>
            <session-timeout>20</session-timeout>
        </session-config>
    

    保存即可生效,再次强调作用域,是部署在该 Tomcat 服务器上的所有项目。如果只是为了练手,验证结果后,别忘了修改回来,或者记住你曾经修改过。

    在工程的 web.xml 文件中配置(对 web.xml 文件下的 web 应用有效

    配置内容是一样滴。

    <session-config>
        <session-timeout>20</session-timeout>
      </session-config>
    

    这里提一个醒,web.xml 在 Servlet 2.3 中,配置的元素必须按照顺序配置。而Servlet 2.4 中是不需要的。那么如何知道自己用的是哪个版本呢?

    很简单,你先不按顺序配,如下图所示报红了,那就说明你是 2.3 ,得乖乖按顺序配,提示也会贴心提醒你配置顺序。

    image-20200906220234436

    在单个Servlet 中通过 setMaxInactiveInterval(int var1) 方法设置 (对单个 Session 有效

    既然知道配置方法,那就来看看源码:

    image-20200906221831812

    从源码可知,是以秒为单位配置的。我们还是来个 20 分钟。

    //配置有效期
            session.setMaxInactiveInterval(60*20);
    

    既然三个作用范围,那就会有优先级的问题,这里由小见大,优先级为 3 > 2 > 1

    Session 原理

    http://127.0.0.1:8080/ling/session/putSession 首先由访问地址来看,可知使用的是 Http 协议。Http 协议是一种无状态协议。服务器端并不能通过 Http 协议感知到浏览器中的是哪一个用户。

    在浏览器中我们可以看到访问时,会为我们存下名为 JSESSIONID 的 Cookie ,它的值就是 Session的 ID。根本上,浏览器就是根据这一 Cookie 的值来判断是否是否为同一用户,该用哪一个 Session 进行通讯。注意他的生命周期,为 Session 。正合 Session 意。

    image-20200907152132373

    删除此 Cookie 后,访问一个从 Session中取值的 Servlet ,会报空指针错误,如上所述,因为服务器是根据浏览器发送来名为 JSESSIONID 的 Cookie 来判断使用哪一个 Session,没有 Cookie 提供的 ID ,也就无从去找对应的 Session 了,自然会是服务器端报空指针的错。

    image-20200907151233026


    那么问题来了,我禁用了 Cookie 的话,那 Session 不就不能用了吗?

    是的,正常渠道下是不能用了。

    URL 地址重写

    注意这两种方法都需要禁用Cookie

    关于对目标web 应用禁用 Cookie方法如下:

    Java Web规范⽀持通过配置禁⽤Cookie,禁⽤⾃⼰项⽬的Cookie,在META-INF⽂件夹下的context.xml⽂件中修改(没有则创建),并编写如下内容:

    <?xml version='1.0' encoding='utf-8'?>
    <Context path="/ouzicheng" cookies="false">
    </Context>
    

    这里有由HttpServletResponse 提供两种方法进行 URL 地址重写:

    • encodeURL(String url) ;

    看源码,我们再决定如何使用它:

    image-20200907160427467

    这里需要注意源码中也说了,如果浏览器支持 Cookie,或者Session 被关闭(通常是Session是否执行了 invalidate() 方法),这时候是不会进行地址重写的。注意,该方法不能在不支持Cookie的浏览器中生效。

    	// 目标url
        String url = "/ling/session/testSession";
        // 重写url,并重定向到目标url
        resp.sendRedirect(resp.encodeURL(url));
    
    • encodeRedirectURL(String url);

    源码里,坑爹的来了:

    image-20200907182340737

    大概就是,有不同,你们用的时候小心,但是什么不同我就不具体说了。。。这就一个接口,我哪找源码去.....

    		// 目标url
            String url = "/ling/session/testSession";
            // 重写url,并重定向到目标url
            resp.sendRedirect(resp.encodeRedirectURL(url));
    

    以上写法下,至少同一站点下,两者的效果并无差别:

    image-20200907153817655

    要问有什么不同,源码上也看不出来什么。关于不同点,只在网络找到以下说法:

    ---------来自CSDN。 原文链接:https://blog.csdn.net/SpbDev/article/details/37879549

    encodeURL在附加jsessionid之前还对url做了判断处理:如果url为空字符串(长度为0的字符串),则将url转换为完整的URL(http或https开头的);如果url是完整的URL,但不含任何路径(即只包含协议、主机名、端口,例如http://127.0.0.1),则在末尾加上根路径符号/。
    也就是encodeURL如果进行了编码,则返回的URL一定是完整URL而不是相对路径;而encodeRedirectURL则不对URL本身进行处理,只专注于添加jsessionid参数(如果需要)。

    --------来自 STACK OVERFLOW 。问答链接:https://stackoverflow.com/questions/4944778/whats-the-difference-between-encodeurl-and-encoderedirecturl

    The main difference between two is, the implementation of encodeRedirectURL method includes the logic to determine whether the session ID needs to be encoded in the URL in the case when you are redirecting the URL to different context where the session information is not required or invalid. The encodeURL method do not appent the seesion id if the cookies are enabled. In addition to this encodeRedirectURL do not append the session information if the URL is redirected to the different context (web application). Because the rules for making this determination can differ from those used to decide whether to encode a normal link, this method is separete from the encodeURL method.

    主要是这句 “如果 URL 重定向到不同的上下文(Web 应用程序),encodeRedirectURL 不追加会话信息。”,然而无从验证,笔者通过两种方法,得到的是同一个 Session 的 ID 值。

    Cookie和Session共同使用

    现在有一个这样的需求,在浏览器浏览数据时,不小心关闭了浏览器,现在需要设计重新打开浏览器还可以看到之前的记录(此记录不是单纯的字符型数据,指的是复杂类型数据)。

    结合 会话技术之Cookie ,可以知道,单一地使用 Cookie 或者 Session 都是无法达到在安全性和便捷性上合理的效果的。这时候需要两者结合使用才可以发挥两者的优势,规避两者的劣势。

    这时候可以结合上面所述,用 Cookie 保存 Session 的 ID 到 JSESSIONID ,在Session的有效期内,再次打开了浏览器,根据 JSESSIONID 的值去服务器找到目标 Session,将内容呈现带浏览器展示。

    // new 一个名为 JSESSIONID 的 Cookie
    Cookie cookie = new Cookie("JSESSIONID",session.getId());
    //设置该Cookie 有效期,注意并非Session的有效期,但是会影响Session 的取值
    cookie.setMaxAge(30*60);
    //设置访问路径
    cookie.setPath("/ling/");
    //加入
    response.addCookie(cookie);
    

    这样就可以满足上面提到的需求,同时利用了 Session 的存储方式以及对用户的不可见 和 Cookie 在浏览器(硬盘)持久化的特点。

    .

  • 相关阅读:
    简易的观察者模式
    SSM项目实战 之 权限管理系统
    SSM项目实战 之 Shiro
    SSM项目实战 之 Maven
    SSM项目实战 之 EasyUI
    Oracle复习思路
    Oracle存储过程 函数 计算使用资源
    Mybatis笔记(二)
    Mybatis笔记(一)
    Oracle表空间 与 分页
  • 原文地址:https://www.cnblogs.com/l1ng14/p/13628632.html
Copyright © 2020-2023  润新知