`

回话记得有session,以及集中模式介绍

阅读更多
对request.getSession(false)的理解(附程序员常疏忽的一个漏洞)
【前面的话】

在网上经常看到有人对request.getSession(false)提出疑问,我第一次也很迷惑,看了一下J2EE1.3 API,看一下官网是怎么解释的。

【官方解释】

  getSession 

public HttpSessiongetSession(boolean create)

Returns the current HttpSession associated with this request or, if if there is no current session and create is true, returns a new session.

If create is false and the request has no valid HttpSession, this method returns null.

To make sure the session is properly maintained, you must call this method before the response is committed. If the container is using cookies to maintain session integrity and is asked to create a new session when the response is committed, an IllegalStateException is thrown.

Parameters:true - to create a new session for this request if necessary; false to return null if there's no current session

Returns: the HttpSession associated with this request or null if create is false and the request has no valid session

译:

getSession(boolean create)意思是返回当前reqeust中的HttpSession ,如果当前reqeust中的HttpSession 为null,当create为true,就创建一个新的Session,否则返回null;

简而言之:

HttpServletRequest.getSession(ture) 等同于 HttpServletRequest.getSession()

HttpServletRequest.getSession(false) 等同于 如果当前Session没有就为null;

【问题和bug】:

我周围很多同事是这样写的;

HttpSession session = request.getSession();   // a new session created if no session exists, 哈哈!完蛋啦!如果session不存在的话你又创建了一个!  String user_name = session.getAttribute("user_name"); 
HttpSession session = request.getSession(); // a new session created if no session exists, 哈哈!完蛋啦!如果session不存在的话你又创建了一个! String user_name = session.getAttribute("user_name");
需要注意的地方是request.getSession() 等同于 request.getSession(true),除非我们确认session一定存在或者sesson不存在时明确有创建session的需要,否则尽量使用request.getSession(false)。在使用request.getSession()函数,通常在action中检查是否有某个变量/标记存放在session中。这个场景中可能出现没有session存在的情况,正常的判断应该是这样:

HttpSession session = request.getSession(false);  if (session != null) {      String user_name = session.getAttribute("user_name");  } 
HttpSession session = request.getSession(false); if (session != null) { String user_name = session.getAttribute("user_name"); }

【投机取巧】:

如果项目中用到了Spring(其实只要是Java的稍大的项目,Spring是一个很好的选择),对session的操作就方便多了。如果需要在 Session中取值,可以用WebUtils工具(org.springframework.web.util.WebUtils)的 getSessionAttribute(HttpServletRequest request, String name)方法,看看高手写的源码吧:哈哈。。

/**  * Check the given request for a session attribute of the given name.  * Returns null if there is no session or if the session has no such attribute.  * Does not create a new session if none has existed before!  * @param request current HTTP request  * @param name the name of the session attribute  * @return the value of the session attribute, or <code>null</code> if not found  */  public static Object getSessionAttribute(HttpServletRequest request, String name) {      Assert.notNull(request, "Request must not be null");      HttpSession session = request.getSession(false);      return (session != null ? session.getAttribute(name) : null);  } 
/** * Check the given request for a session attribute of the given name. * Returns null if there is no session or if the session has no such attribute. * Does not create a new session if none has existed before! * @param request current HTTP request * @param name the name of the session attribute * @return the value of the session attribute, or <code>null</code> if not found */ public static Object getSessionAttribute(HttpServletRequest request, String name) { Assert.notNull(request, "Request must not be null"); HttpSession session = request.getSession(false); return (session != null ? session.getAttribute(name) : null); }
注:Assert是Spring工具包中的一个工具,用来判断一些验证操作,本例中用来判断reqeust是否为空,若为空就抛异常。

上面的代码又可以简洁一下啦,看吧:

HttpSession session = request.getSession(false);  String user_name = WebUtils.getSessionAttribute(reqeust, "user_name"); 



2.9.8 session对象

session对象也是一个非常常用的对象,这个对象代表一次用户会话。一次用户会话的含义是:从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开为止,这个过程就是一次会话。

session通常用于跟踪用户的会话信息,如判断用户是否登录系统,或者在购物车应用中,用于跟踪用户购买的商品等。

session范围内的属性可以在多个页面的跳转之间共享。一旦关闭浏览器,即session结束,session范围内的属性将全部丢失。

session对象是HttpSession的实例,HttpSession有如下两个常用的方法:

setAttribute(String attName , Object attValue):设置session范围内attName属性的值为attValue。

getAttribute(String attName):返回session范围内attName属性的值。

下面的示例演示了一个购物车应用,以下是陈列商品的JSP页面代码。

程序清单:codes\02\2.9\jspObject\shop.jsp

<%@ page contentType="text/html; charset=gb2312" language="java" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>选择物品购买</TITLE>
</HEAD>
<BODY>
<FORM METHOD=POST ACTION="processBuy.jsp">
书籍:<INPUT TYPE="checkbox" NAME="item" value="book"><br>
电脑:<INPUT TYPE="checkbox" NAME="item" value="computer"><br>
汽车:<INPUT TYPE="checkbox" NAME="item" value="car"><br>
<INPUT TYPE="submit" value="购买">
</FORM>
</BODY>
</HTML>

这个页面几乎没有动态的JSP部分,全部是静态的HTML内容。该页面包含一个表单,表单里包含3个复选按钮,用于选择想购买的物品,表单由processBuy.jsp页面处理,其页面的代码如下:

程序清单:codes\02\2.9\jspObject\processBuy.jsp

<%@ page contentType="text/html; charset=gb2312" language="java" import="java.
util.*"%>
<%
//取出session范围的itemMap属性
Map<String,Integer> itemMap = (Map<String,Integer>)session
.getAttribute("itemMap");
//如果Map对象为空,则初始化Map对象
if (itemMap == null)
{
itemMap = new HashMap<String,Integer>();
itemMap.put("书籍" , 0);
itemMap.put("电脑" , 0);
itemMap.put("汽车" , 0);
}
//获取上个页面的请求参数
String[] buys = request.getParameterValues("item");
//遍历数组的各元素
for (String item : buys)
{
//如果item为book,表示选择购买书籍
if(item.equals("book"))
{
int num1 = itemMap.get("书籍").intValue();
//将书籍key对应的数量加1
itemMap.put("书籍" , num1 + 1);
}
//如果item为computer,表示选择购买电脑
else if (item.equals("computer"))
{
int num2 = itemMap.get("电脑").intValue();
//将电脑key对应的数量加1
itemMap.put("电脑" , num2 + 1);
}
//如果item为car,表示选择购买汽车
else if (item.equals("car"))
{
int num3 = itemMap.get("汽车").intValue();
//将汽车key对应的数量加1
itemMap.put("汽车" , num3 + 1);
}
}
//将itemMap对象放到设置成session范围的itemMap属性
session.setAttribute("itemMap" , itemMap);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>购买的物品列表</TITLE>
</HEAD>
<BODY>
您所购买的物品:<br>
书籍:<%=itemMap.get("书籍")%>本<br>
电脑:<%=itemMap.get("电脑")%>台<br>
汽车:<%=itemMap.get("汽车")%>辆<p>
<a href="shop.jsp">再次购买</a>
</BODY>
</HTML>

上面页面中粗体字代码使用session来保证itemMap对象在一次会话中有效,这使得该购物车系统可以反复购买,只要浏览器不关闭,购买的物品信息就不会丢失,图2.31显示的是多次购买后的效果。

 
图2.31  利用session记录购物车信息

考虑session本身的目的,通常只应该把与用户会话状态相关的信息放入session范围内。不要仅仅为了2个页面之间交换信息,就将该信息放入session范围内。如果仅仅为了2个页面交换信息,可以将该信息放入request范围内,然后forward请求即可。

关于session还有一点需要指出,session机制通常用于保存客户端的状态信息,这些状态信息需要保存到Web服务器的硬盘上,所以要求session里的属性值必须是可序列化的,否则将会引发不可序列化的异常。

session的属性值可以是任何可序列化的Java对象。



9.3.1 单例模式

有些时候,允许自由创建某个类的实例没有意义,还可能造成系统性能下降(因为创建对象所带来的系统开销问题)。例如整个系统只有一个窗口管理器,只有一个假脱机打印设备;在Java EE应用中可能只需要一个数据库引擎访问点,Hibernate访问时只需要一个SessionFactory实例,如果在系统中为它们创建多个实例就没有太大的意义。

如果一个类始终只能创建一个实例,则这个类被称为单例类,这种模式就被称为单例模式。

对Spring框架而言,可以在配置Bean实例时指定scope="singleton"来配置单例模式。不仅如此,如果配置<bean .../>元素时没有指定scope属性,则该Bean实例默认是单例的行为方式。

Spring推荐将所有业务逻辑组件、DAO组件、数据源组件等配置成单例的行为方式,因为这些组件无须保存任何用户状态,故所有客户端都可共享这些业务逻辑组件、DAO组件,因此推荐将这些组件配置成单例模式的行为方式。

如果不借助Spring框架,我们也可手动实现单例模式。为了保证该类只能产生一个实例,程序不能允许自由创建该类的对象,而是只允许为该类创建一个对象。为了避免程序自由创建该类的实例,我们使用private修饰该类的构造器,从而将该类的构造器隐藏起来。

将该类的构造器隐藏起来,则需要提供一个public方法作为该类的访问点,用于创建该类的对象,且该方法必须使用static修饰(因为调用该方法之前还不存在对象,因此调用该方法的不可能是对象,只能是类)。

除此之外,该类还必须缓存已经创建的对象,否则该类无法知道是否曾经创建过实例,也就无法保证只创建一个实例。为此该类需要使用一个静态属性来保存曾经创建的实例,且该属性需要被静态方法访问,所以该属性也应使用static修饰。

基于上面的介绍,下面程序创建了一个单例类。

程序清单:codes\09\9.3\Singleton\TestSingleton.java

class Singleton
{
//使用一个变量来缓存曾经创建的实例
private static Singleton instance;
//将构造器使用private修饰,隐藏该构造器
private Singleton(){}
//提供一个静态方法,用于返回Singleton实例
//该方法可以加入自定义的控制,保证只产生一个Singleton对象
public static Singleton getInstance()
{
//如果instance为null,表明还不曾创建Singleton对象
//如果instance不为null,则表明已经创建了Singleton对象,将不会执行该方法
if (instance == null)
{
//创建一个Singleton对象,并将其缓存起来
instance = new Singleton();
}
return instance;
}
}
public class TestSingleton
{
public static void main(String[] args)
{
//创建Singleton对象不能通过构造器,只能通过getInstance方法
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
//将输出true
System.out.println(s1 == s2);
}
}

上面程序中第一行粗体字代码使用了一个静态属性来保存已创建的Singleton实例,程序第二段粗体字代码用于判断系统是否已经创建过Singleton实例——如果已经创建过Singleton实例,则直接返回该Singleton实例即可。

正是通过上面第二段粗体字代码提供的控制逻辑,从而保证了Singleton类只能产生一个实例。所以在TestSingleton类的main方法中看到两次产生的Singleton对象实际上是同一个对象。

在Java EE应用中,单例模式是一种应用非常广泛的设计模式,应用中许多组件都只需要单个实例,下面介绍的工厂模式里的工厂也只需要单个实例……

使用单例模式主要有如下两个优势:

减少创建Java实例所带来的系统开销。

便于系统跟踪单个Java实例的生命周期、实例状态等。



1. Object getAttribute( String name ) ;
获取与指定名字相关联的session属性值。
2. Enumeration getAttributeNames() ;
取得session内所有属性的集合。

3. long getCreationTime() ;
返回session的创建时间,最小单位千分之一秒。

4. String getId() ;
取得session标识。

5. long getLastAccessedTime() ;
返回与当前session相关的客户端最后一次访问的时间,由1970-01-01算起,单位毫秒。

6. int getMaxInactiveInterval( int interval ) ;
返回总时间,以秒为单位,表示session的有效时间(session不活动时间)。-1为永不过期。

7. ServletContext getServletContext() ;
返回一个该JSP页面对应的ServletContext对象实例。

8. HttpSessionContext getSessionContext() ;


9. Object getValue( String name ) ;
取得指定名称的session变量值,不推荐使用。

10. String[] getValueNames() ;
取得所有session变量的名称的集合,不推荐使用。

11. void invalidate() ;
销毁这个session对象。

12. boolean isNew() ;
判断一个session是否由服务器产生,但是客户端并没有使用。

13. void pubValue( String name, Object value ) ;
添加一个session变量,不推荐使用。

14. void removeValue( String name ) ;
移除一个session变量的值,不推荐使用。

15. void setAttribute( String name, String value ) ;
设置指定名称的session属性值。

16. void setMaxInactiveInterval( int interval ) ;
设置session的有效期。

17. void removeAttribute( String name ) ;
移除指定名称的session属性。



在回答问题之前,跟你简单介绍Session的工作原理:

不需要写手动写SessionID:
代码如下:
HttpSession sesion = Request.getSesion();
if(session!=null){
//如果sessionID不等于空,则说明是第二次访问
//写第二次访问时的代码
}else{
//写第一次访问的代码
}

java web怎么通过sessionid得到session这个我们不需要了解,就是第二次客户端发出请求时,将sessionid也发给了服务器,服务器根据这个唯一的ID找到相应的session(session都是保存在服务器的数据库中,每个session用唯一一个ID所标识),就像是数据库中根据关键字查找数据一样,找到之后就可以直接用这个session里面的数据了。
分享到:
评论

相关推荐

    关于web回话跟踪session

    ### 关于Web回话跟踪与Session机制 #### Session机制概览 在Web开发中,Session是一种常用的技术,用于跨多个请求来跟踪用户的状态。当一个用户访问网站时,服务器会创建一个Session对象来存储该用户的特定信息。...

    session回话共享

    在IT行业中,尤其是在Web开发领域,"Session回话共享"是一个关键的概念,它涉及到用户状态的维护和跨服务器的数据共享。这里的"session"是指在Web应用程序中,服务器用于跟踪和存储用户状态的一种机制。通常,当用户...

    Tomcate集群session.zip

    Tomcate集成redis集群session

    servlet利用cookie回话跟踪的工程

    虽然Cookie可以实现回话跟踪,但它有一些限制,如大小限制(通常4KB)、安全性(数据暴露在客户端)以及隐私问题(用户可以选择禁用Cookie)。相比之下,Session在服务器端存储用户数据,安全性和容量都更高,但会...

    redis-session-manager-redis-session-manager-2.0.5.zip

    本文将深入探讨Redis Session Manager的相关知识点,包括Redis的基本概念、Session管理的原理以及在Windows环境下的部署和使用。 1. Redis基本概念 Redis(Remote Dictionary Server)是一个开源的、基于键值对的...

    利用RSA实现回话加密

    该算法基于两个大素数的乘积以及欧拉函数的性质,使得加密和解密过程可以互逆。RSA的关键在于一对公钥和私钥:公钥用于加密,私钥用于解密。这一特性使得只有持有私钥的一方才能解密由公钥加密的信息,从而确保了...

    python模拟登陆,用session维持回话的实例

    本文将详细解析如何使用Python进行模拟登录,并探讨如何利用`session`对象来维持回话状态,确保后续请求能够识别已登录的身份。 #### 一、模拟登录的基本原理 在进行模拟登录之前,我们需要了解一些基本概念: - *...

    自动清除打印机连接回话

    企业使用打印机,经常会出现用户连接打印机而无法打印的现象,这是因为打印机链接用户的回话数饱和导致,使用这个软件则可无须担心回话数饱和,它会自动清除连接回话,摆脱困扰。

    Ajax设计模式 中文

    该模式介绍了如何在客户端存储和管理会话状态,以确保跨请求的上下文一致性。 ### 8. 预加载模式 预加载模式是在用户实际需要之前加载数据,以减少延迟,提升用户体验。可以预测用户可能的操作,提前加载相关资源。...

    Session与Cookie

    上JSP老师的代码,关于回话session与cookie的比较代码

    如何杀掉Teradata数据库回话

    以下将详细介绍如何使用pmonv2来杀掉Teradata的会话,以及关于Teradata会话和transientjournal表的相关知识。 1. **启动pmonv2**: - 首先,在桌面找到PM Green文件夹,打开其中的“pmonv2”应用程序。这通常是一...

    深入解析Session工作原理及运行流程

    * 单纯的使用session来存储用户回话信息,那么当用户量较多时,session文件数量会很多,会存在session查询慢的问题 * 本质上,session技术就是一种基于后端有别于数据库的临时存储技术 为什么要使用Session 我们...

    php数据库储存回话

    php的mysql存储session功能实现

    Python Web框架之Django框架cookie和session用法分析

    在Django里面,cookie和session都记录了客户端的某种状态,用来跟踪用户访问网站的整个回话。 两者最大的区别是cookie的信息是存放在浏览器客户端的,而session是存放在服务器端的。 两者使用的方式都是request....

    WCF会话行为

    本篇将深入探讨WCF的三种会话方式,以及它们在不同实例模式下的应用,并分析实例、会话和通信协议的组合效果。 ### 1. 会话类型 WCF中的会话主要分为以下三种: 1. **无会话(NoSession)**:这是默认模式,服务...

    ChatGPT技术的多轮对话优化与回话状态管理策略.docx

    在对话生成和响应调整中,根据回话状态信息可以生成更为具体和有针对性的回答,从而提高回答的实用性和用户的满意度。在这一过程中,模型可以被训练以控制回答的风格和口吻,以满足不同用户的个性化需求,实现更加...

    MobaXterm解除存储会话上限

    MobaXterm解除存储会话上限,默认为10-12个左右,将此文件放在安装目录下即可 只对V21版本有效

    Socket回话---sokect编程

    Socket回话,或者说Socket编程,是计算机网络编程中的核心概念,它允许两个远程应用程序通过互联网进行双向通信。在Java中,Socket提供了TCP/IP协议的低级别接口,让我们能够实现服务器端(Server)与客户端(Client...

    asciinema回话记录和回放使用运维总结-精华版

    该文档为asciinema回话记录和回放使用运维总结,个人珍藏版,可作为线上操作实录,希望能帮助到有用到的朋友~

Global site tag (gtag.js) - Google Analytics