博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java EE之会话
阅读量:6036 次
发布时间:2019-06-20

本文共 6783 字,大约阅读时间需要 22 分钟。

1.需要会话的原因

所有HTTP服务器技术都普遍采用HTTP会话的概念,并且Java EE也在规范中添加了对会话的支持。

维持状态

会话用于维持请求和请求之间的状态。HTTP请求自身是完全无状态的。从服务器的角度来说,当用户的Web浏览器打开第一个连接到服务器的套接字时请求就开始了,直到服务器返回最后一个数据包并关闭连接时,该请求将结束。
在无状态方式下,应用程序通常无法正常工作。一个经典的例子就是在线购物网站。当你浏览商店时,找到了喜欢的商品,就会将它添加到购物车中。然后继续浏览商店并找到另一个喜欢的商品,同样也将它添加到购物车中。在查看购物车时,你应该看到其中有两个商品。在你发出的多个请求之间,网站通过某种方式了解到它们是来自于同一计算机中的同一浏览器,并将它们关联到你的购物车。其他人是无法看到你的购物车或购物车中包含的产品——购物车只绑定到你的计算机和浏览器。

记住用户

另一个需要考虑的场景是用户论坛网站。用户在登录之后,就可以添加论坛主题、回复主题、参与其他用户的私人讨论、向版主举报主题或回复、还可以收藏主题。注意在整个过程中用户只需要登录一次。系统需要通过某种方式记住该用户,会话就提供了这种功能。

2.使用会话cookie和URL重写

在Web会话的理论中,会话是由服务器或Web应用程序管理的某些文件、内存片段、对象或者容器,它包含了分配给它的各种不同数据。

通常会话被赋予一个随机生成的字符串,称为会话ID。第一次创建会话时(即收到请求时),创建的会话ID将会作为响应的一部分返回到用户浏览器中。接下来从该用户浏览器中发出的请求都将通过某种方式包含该会话ID。当应用程序收到含有会话ID的请求时,它可以通过该ID将现有会话与当前请求关联起来。

注意:使用随机字符串作为会话ID而不使用简单的序列ID,是因为序列ID是可预测的,这样可能会容易引起会话劫持。

2.1 会话cookie

HTTP 1.1的解决方案HTTP cookie,可用于将会话ID发送到浏览器,从而使浏览器可以在未来的请求中包含该会话ID。

cookie有各种不同的特性,例如域名、路径、过期日期或最大生命周期、安全标志或只含HTTP的标志。

  • Domian特性告诉浏览器应该将cookie发送到哪个域名中。
  • Path将cookie限制在相对于域名的某个特定URL中
  • Expires定义了cookie的绝对过期日期。
  • 如果存在Secure特性,浏览器将只会通过HTTPS发送cookie(这将保护cookie,避免以未加密的方式进行传输)。

在Java EE应用服务器中,会话cookie的名字默认为JSESSIONID

2.2 URL中的会话ID

另一种传输会话ID的流行方式是通过URL。

不同的技术对如何在URL中内嵌和定位会话ID使用不同的策略。
Java EE应用程序将会话ID添加到URL的最后一个路径段的矩阵参数中。通过这种方式分离开会话ID与查询字符串的参数,使它们不会相互冲突。
http://www.example.com/support?JSESSIONID=NRxclGg2vG7kI4MdlLn?foo=bar&high=five
这种方式使浏览器意识不到会话ID的存在。相反,服务器将重写Location头中的URL以及任何响应内容中URL,使浏览器用于访问服务器的所有URL都已经内嵌了会话ID。
HttpServletResponse接口定义了两个可以重写URL的方法:encodeURLencodeRedirectURL,它们将在必要的时候把会话ID内嵌在URL中。

3.在会话中存储数据

3.1 在部署描述符中配置会话

在许多情况下,都可以在Java EE中直接使用HTTP会话,不需要添加显式的配置。不过可以在部署描述符中配置它们,并且出于安全的目的也应该配置。

30
JSESSIONID
example.org
/shop
true
false
1800
COOKIE
URL
SSL

标签<session-timeout>以分钟为单位,如果它的值小于等于0,那么会话将永远也不过期。如果忽略该标签,那么它将使用容器的默认值。Tomcat容器的默认值是30分钟,可以通过Tomcat配置修改。

Servlet 3.0/Java EE6中新增的标签<tracking-mode>用于表示容器应该使用哪种技术追踪会话ID。它的合法值有:URL、COOKIE和SSL。
只有在追踪模式中使用了COOKIE时,才可以使用<cookie-config>标签。
<cookie-config>标签的标签:

  • 通过标签<name>可以自定义会话cookie的名字。默认值为JSESSIONID。
  • 标签<domain><path>对应着cookie的Domain和Path特性。Web容器已经设置了正确的默认值,因此通常不需要自定义它们。
  • 标签<comment>将在会话ID cookie中添加Comment特性,用于解释cookie的目的。
  • 标签<http-only><secure>对应着cookie的HttpOnly特性和Secure特性,它们的默认值都是假。
  • 标签<max-age>指定了cookie的Max-Age特性,用于控制cookie何时过期。默认情况下,cookie没有过期日期,这意味着它将在浏览器关闭时过期,将它设置为-1的效果相同。

3.2 存储和获取数据

3.2.1 在Servlet中使用会话

private void addToCart(HttpServletRequest request,                           HttpServletResponse response)            throws ServletException, IOException    {        int productId;        try        {            productId = Integer.parseInt(request.getParameter("productId"));        }        catch(Exception e)        {            response.sendRedirect("shop");            return;        }        HttpSession session = request.getSession();        if(session.getAttribute("cart") == null)            session.setAttribute("cart", new Hashtable
()); @SuppressWarnings("unchecked") Map
cart = (Map
)session.getAttribute("cart"); if(!cart.containsKey(productId)) cart.put(productId, 0); cart.put(productId, cart.get(productId) + 1); response.sendRedirect("shop?action=viewCart"); }

HttpServletRequest的getSession方法有两种方式:getSession()getSession(boolean)

getSession()的调用实际将会调用getSession(true),如果会话存在,就返回已有会话,不存在,就创建一个新的会话。
如果调用getSession(false),那么如果会话存在就返回已有会话,否则返回null
HttpSession的getAttribute方法将返回会话中存储的对象,setAttribute方法将把对象绑定到会话中。

3.2.2 在JSP中使用会话

viewCart.jsp

<%@ page import="java.util.Map" %>            View Cart                

View Cart

">Product List
">Empty Cart
<% @SuppressWarnings("unchecked") Map
products = (Map
)request.getAttribute("products"); @SuppressWarnings("unchecked") Map
cart = (Map
)session.getAttribute("cart"); if(cart == null || cart.size() == 0) out.println("Your cart is empty."); else { for(int id : cart.keySet()) { out.println(products.get(id) + " (qty: " + cart.get(id) + ")
"); } } %>

该JSP使用隐式的session变量访问会话中存储的商店购物车Map,然后列出了购物车中所有的产品和它们的数量。

示例源码(在会话中存储和获取数据)链接:https://pan.baidu.com/s/1KYDagePVcW0SXzk9WK3Z1Q 密码:fz21

3.3 删除数据

private void emptyCart(HttpServletRequest request,                           HttpServletResponse response)            throws ServletException, IOException    {        request.getSession().removeAttribute("cart");        response.sendRedirect("shop?action=viewCart");    }

也可以通过调用getAttribute方法获取Map,然后调用Map的clear方法清空数据。这里只是为了演示removeAttribute方法的使用。

1393432-20180606102919034-1542205263.png

3.4 在会话中存储更复杂的数据

理论上讲,会话可以存储希望存储的数据。

当然,也必须考虑希望存储数据的大小。如果在会话中添加了过多数据,那么有可能会导致虚拟机的内存耗尽。

示例源码(在会话中存储更复杂的数据)链接:https://pan.baidu.com/s/1cLQS-qLiYd9LSOiksMCDFA 密码:ed9f

4.使用会话

Java EE中会话最有用的特性之一就是会话事件。

使用监听器检测会话的变化。Servlet API中定义了几种监听器,大多数尽管不是全部,都将监听某种形式的会话活动。通过实现对应事件的监听器接口订阅某个事件,然后在部署描述符中添加<listener>配置,或者在该类中添加注解@javax.servlet.annotation.WebListener
当某个事件发生时,将触发事件的发布,然后容器将调用对应事件监听器中的方法。

@WebListenerpublic class SessionListener implements HttpSessionListener, HttpSessionIdListener{    private SimpleDateFormat formatter =            new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss");    @Override    public void sessionCreated(HttpSessionEvent e)    {        System.out.println(this.date() + ": Session " + e.getSession().getId() +                " created.");        SessionRegistry.addSession(e.getSession());    }    @Override    public void sessionDestroyed(HttpSessionEvent e)    {        System.out.println(this.date() + ": Session " + e.getSession().getId() +                " destroyed.");        SessionRegistry.removeSession(e.getSession());    }    @Override    public void sessionIdChanged(HttpSessionEvent e, String oldSessionId)    {        System.out.println(this.date() + ": Session ID " + oldSessionId +                " changed to " + e.getSession().getId());        SessionRegistry.updateSessionId(e.getSession(), oldSessionId);    }    private String date()    {        return this.formatter.format(new Date());    }}

或者在部署描述符中配置

com.wrox.SessionListener

示例源码(使用会话)链接:https://pan.baidu.com/s/1r4Ojmj22MuXRA3EzIITdTA 密码:5ejb

转载于:https://www.cnblogs.com/gzhjj/p/9140444.html

你可能感兴趣的文章
解决https://localhost:1158/em 页面无法打开的问题
查看>>
[Cocoa]深入浅出Cocoa之Core Data(4)- 使用绑定
查看>>
原理:什么是Quadtrees?(转)
查看>>
记:返回方法参数的值(或多个值),
查看>>
Effective C++ 的52个条款列表
查看>>
c#读取ini文件
查看>>
一阶微分方程的求解
查看>>
其它 Helper
查看>>
监控利器Prometheus初探
查看>>
foreach遍历打印表格
查看>>
Oracle笔记(中) 多表查询
查看>>
Delphi 中的 XMLDocument 类详解(5) - 获取元素内容
查看>>
差异分析定位Ring 3保护模块
查看>>
2013年7月12日“修复 Migration 测试发现的 Bug”
查看>>
vim文本编辑器详解
查看>>
学习vue中遇到的报错,特此记录下来
查看>>
CentOS7 编译安装 Mariadb
查看>>
32位系统和64位系统的选择
查看>>
01配置管理过程指南
查看>>
jstl格式化时间
查看>>