Java EE之会话
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的方法:encodeURL
和encodeRedirectURL
,它们将在必要的时候把会话ID内嵌在URL中。
3.在会话中存储数据
3.1 在部署描述符中配置会话
在许多情况下,都可以在Java EE中直接使用HTTP会话,不需要添加显式的配置。不过可以在部署描述符中配置它们,并且出于安全的目的也应该配置。
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<name>JSESSIONID</name>
<domain>example.org</domain>
<path>/shop</path>
<comment><![CDATA[Keeps you logged in. See our privacy policy for more information.]]></comment>
<http-only>true</http-only>
<secure>false</secure>
<max-age>1800</max-age>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
<tracking-mode>URL</tracking-mode>
<tracking-mode>SSL</tracking-mode>
</session-config>
标签<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<Integer, Integer>());
@SuppressWarnings("unchecked")
Map<Integer, Integer> cart =
(Map<Integer, Integer>)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" %>
<!DOCTYPE html>
<html>
<head>
<title>View Cart</title>
</head>
<body>
<h2>View Cart</h2>
<a href="<c:url value="/shop" />">Product List</a><br /><br />
<a href="<c:url value="/shop?action=emptyCart" />">Empty Cart</a><br /><br />
<%
@SuppressWarnings("unchecked")
Map<Integer, String> products =
(Map<Integer, String>)request.getAttribute("products");
@SuppressWarnings("unchecked")
Map<Integer, Integer> cart =
(Map<Integer, Integer>)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) +
")<br />");
}
}
%>
</body>
</html>
该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
方法的使用。
3.4 在会话中存储更复杂的数据
理论上讲,会话可以存储希望存储的数据。
当然,也必须考虑希望存储数据的大小。如果在会话中添加了过多数据,那么有可能会导致虚拟机的内存耗尽。
示例源码(在会话中存储更复杂的数据)链接:https://pan.baidu.com/s/1cLQS-qLiYd9LSOiksMCDFA 密码:ed9f
4.使用会话
Java EE中会话最有用的特性之一就是会话事件。
使用监听器检测会话的变化。Servlet API中定义了几种监听器,大多数尽管不是全部,都将监听某种形式的会话活动。通过实现对应事件的监听器接口订阅某个事件,然后在部署描述符中添加<listener>
配置,或者在该类中添加注解@javax.servlet.annotation.WebListener
。
当某个事件发生时,将触发事件的发布,然后容器将调用对应事件监听器中的方法。
@WebListener
public 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());
}
}
或者在部署描述符中配置
<listener>
<listener-class>com.wrox.SessionListener</listener-class>
</listener>
示例源码(使用会话)链接:https://pan.baidu.com/s/1r4Ojmj22MuXRA3EzIITdTA 密码:5ejb
Java EE之会话的更多相关文章
- Java EE.Servlet.会话管理
一次会话是从客户打开浏览器开始到关闭浏览器结束.记录会话信息的技术称为会话跟踪.常见的会话跟踪技术有Cookie.URL重写和隐藏表单域. 1.Cookie Cookie是一小块可以嵌入到HTTP请求 ...
- Java EE : 三、图解Session(会话)
目录 Java EE : 一.图解Http协议 Java EE : 二.图解 Cookie(小甜饼) Java EE : 三.图解Session(会话) 概述 一.Session由来 二.Sessio ...
- 【Java EE 学习 69 中】【数据采集系统第一天】【SSH框架搭建】
经过23天的艰苦斗争,终于搞定了数据采集系统~徐培成老师很厉害啊,明明只是用了10天就搞定的项目我却做了23天,还是模仿的...呵呵,算了,总之最后总算是完成了,现在该好好整理该项目了. 第一天的内容 ...
- Java EE : 二、图解 Cookie(小甜饼)
目录 Java EE : 一.图解Http协议 Java EE : 二.图解 Cookie(小甜饼) Java EE : 三.图解Session(会话) 概述 一.概述 二.详细介绍Cookie 传输 ...
- Java EE : 一、图解Http协议
目录 Java EE : 一.图解Http协议 Java EE : 二.图解 Cookie(小甜饼) Java EE : 三.图解Session(会话) 概述 一.技术基石及概述 二.深入理解技术基石 ...
- Java EE 和 Java Web
什么是 Java Web 应用程序? Java Web 应用程序会生成包含各种类型的标记语言(HTML 和 XML 等)和动态内容的交互式 Web 页.它通常由 Web 组件组成(如 JavaServ ...
- JAVA EE(简述)
一.平台概述 JavaEE的全称是Java Enterprise Edition,它是一个开发分布式企业级应用的规范和标准 Java 平台三个版本: Java ME(Java Micro Edit ...
- JavaWeb学习----JSP简介及入门(含Eclipse for Java EE及Tomcat的配置)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...
- Java EE (8) -- Java EE Patterns
Java EE 模式目录由以下三个层组成: – 整合层(4) – 业务层(9) – 表示层(8) 涉及 Java EE 平台代码与其它类型应用程序或遗留系统的集成: 服务激活器 ...
随机推荐
- IEEE1588 ( PTP ) 协议简介
IEEE1588 协议,又称 PTP( precise time protocol,精确时间协议),可以达到亚微秒级别时间同步精度,于 2002 年发布 version 1,2008 年发布 vers ...
- php从入门到放弃系列-01.php环境的搭建
php从入门到放弃系列-01.php环境的搭建 一.为什么要学习php 1.php语言适用于中小型网站的快速开发: 2.并且有非常成熟的开源框架,例如yii,thinkphp等: 3.几乎全部的CMS ...
- layui数据表格使用(一:基础篇,数据展示、分页组件、表格内嵌表单和图片)
表格展示神器之一:layui表格 前言:在写后台管理系统中使用最多的就是表格数据展示了,使用表格组件能提高大量的开发效率,目前主流的数据表格组件有bootstrap table.layui table ...
- 服务端模版注入漏洞检测payload整理
服务端模版注入漏洞产生的根源是将用户输入的数据被模版引擎解析渲染可能导致代码执行漏洞 下表涵盖了java,php,python,javascript语言中可能使用到的模版引擎,如果网站存在服务端模版注 ...
- React Native iOS 离线包
平时使用React Native 时候, js代码和图片资源运行在一个Debug Server上(需要cd 到RN目录,然后终端执行 npm start 命令开启本地服务 ).每次更新代码之后只需要使 ...
- 最新的CocoaPods 安装及使用
当在开发iOS应用时,会经常使用到很多的第三方开源类库,一般的方法是直接从GitHub下载,然后拖到项目中使用,如果该开源类库不依赖其他的类库,就可以直接使用:如果该开源类库还依赖一些其他的类库,则需 ...
- Beta发布—视频展示
视频链接:http://v.youku.com/v_show/id_XMzE3ODQ0NjIzMg==.html视频简要内容介绍:1.一个小小的logo展示.2.在alpha的基础上,beta发布中增 ...
- C++自学及C的补缺
我这个寒假可以坐在电脑前的时间算是比较少的,因为我放假不久后就去打工了,而打工的时间是很流动的,所以我无法固定时间来学习,因此我只能根据我的打工时间来安排我的学习. 由于我的书是除夕前夕淘宝的,近期是 ...
- python learning Exception & Debug.py
''' 在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因.在操作系统提供的调用中,返回错误码非常常见.比如打开文件的函数open(),成功时返 ...
- Internet History, Technology and Security (Week2)
Week2. History: The First Internet - NSFNet coursera address Supercomputers Justify a National Netwo ...