??xml version="1.0" encoding="utf-8" standalone="yes"?>
摘要Q虽然session机制在web应用E序中被采用已经很长?wbr>间了Q但是仍然有很多Z清楚session机制的本?wbr>Q以至不能正的应用q一技术。本文将详细讨论session的工
sessionQ中文经常翻译ؓ会话Q其本来的含义是指有始有l的一pd动作/消息Q比如打电话时从?wbr>L话拨号到挂断电话q中间的一pdq程可以UCZ个sessi
然而当session一词与|络协议相关联时Q它又往往隐含?wbr>"面向q接"??保持状?q样两个含义Q?面向q接
而到了web服务器蓬勃发展的时代Qsession在web开发语
鉴于q种混ؕ已不可改变,本文中session一词的q用也会Ҏ
二、HTTP协议与状态保?/strong>
然而聪明(或者贪心?Q的Z很快发现如果能够提供一些按需生成?wbr>动态信息会使web变得更加有用Q就像给有线电视加上Ҏ功能一?wbr>。这U需求一斚wqHTML逐步d了表单、脚?wbr>、DOM{客L行ؓQ另一斚w在服务器端则出现了CGI规范以响
让我们用几个例子来描qC下cookie和session机制之间
׃HTTP协议是无状态的Q而出于种U考虑也不希望使之成ؓ有状
三、理解cookie机制
正统的cookie分发是通过扩展HTTP协议来实现的
而cookie的用是由浏览器按照一定的原则在后台自动发送给?wbr>务器的。浏览器查所有存储的cookieQ如果某个cookie
cookie的内容主要包括:名字Q|q期旉Q\径和域?br />其中域可以指定某一个域比如.google.comQ相当于d招牌Q比如宝z公司,也可以指定一个域下的具体某台机器比如www.google
存储在硬盘上的cookie可以在不同的览器进E间׃n
下面是一个goolge讄cookie的响应头的例?br />HTTP/1.1 302 Found
四、理解session机制
当程序需要ؓ某个客户端的h创徏一个session的时?wbr>Q服务器首先查这个客L的请求里是否已包含了一个sessio
保存q个session id的方式可以采用cookieQ这样在交互q程中浏览器可以自动
׃cookie可以被h为的止Q必L其他机制以便在cook
另一U技术叫做表单隐藏字Dc就是服务器会自动修改表?wbr>Q添加一个隐藏字D,以便在表单提交时能够把session id传递回服务器。比如下面的表单
在谈论session机制的时候,常常听到q样一U误?wbr>"只要关闭览器,session消׃"。其实可以想象一下会
恰恰是由于关闭浏览器不会Dsession被删?wbr>Q迫使服务器为seesion讄了一个失效时?wbr>Q当距离客户端上一ơ用session的时间超q这个失效时间时
五、理解javax.servlet.http.HttpSessio
首先QWeblogic Server提供了一pd的参数来控制它的HttpSession
一般情况下Qsession都是存储在内存里Q当服务器进E被停止
复制严格说来不算持久化保存,因ؓsession实际上还是保存在
cookie生存旉的设|则会媄响浏览器生成的cookie是否
cookie的\径对于web应用E序来说是一个非帔R要的选项
关于session的设|参考[5] http://e-docs.bea.com/wls
六、HttpSession常见问题
׃session会消耗内存资源,因此Q如果不打算使用sess
2、session何时被删?br />l合前面的讨论,session在下列情况下被删除a.E序调用HttpSessi
3、如何做到在览器关闭时删除session
4、有个HttpSessionListener是怎么回事
5、存攑֜session中的对象必须是可序列化的?br />不是必需的。要求对象可序列化只是ؓ了session能够在集中
6、如何才能正的应付客户端禁止cookie的可能?br />Ҏ有的URL使用URL重写Q包括超链接Qform的actio
7、开两个览器窗口访问应用程序会使用同一个sessionq是
8、如何防止用h开两个览器窗口操作导致的session混ؕ
9、ؓ什么在Weblogic Server中改变session的值后要重新调用一ơsessi
10、ؓ什么session不见?br />排除session正常失效的因素之外,服务器本w的可能性应该是
七、跨应用E序的session׃n
然而按照Servlet规范Qsession的作用范围应该仅仅限
首先来看一下Tomcat是如何实现web应用E序之间sessi
Ҏq个Ҏ,我们可以推测Tomcat中session的内存结
W者以前用q的iPlanet也采用的是同L方式
iPlanet中有一U很单的Ҏ来实现共享一个session idQ那是把各个应用程序的cookie路径都设?
需要注意的是,操作׃n的session应该遵@一些编E约?wbr>Q比如在session attribute名字的前面加上应用程序的前缀
我们再看一下Weblogic Server是如何处理session的?br />
从截屏画面上可以看到Weblogic ServerҎ有的应用E序讄的cookie的\径都?
对于q样一U结构,在session机制本n上来解决sessio
应用E序A
应用E序B
值得注意的是q种用法不可ULQ因为根据ServletConte
那么Weblogic ServerZ么要把所有的应用E序的cookie路径都设?wbr>/呢?原来是ؓ了SSOQ凡是共享这个session的应用程序都
八、ȝ
二、HTTP协议与状态保?/font>
三、理解cookie机制
四、理解session机制
五、理解javax.servlet.http.HttpSess
六、HttpSession常见问题
七、跨应用E序的session׃n
八、ȝ
在我的经验里Qsessionq个词被滥用的程度大概仅ơ于tra
HTTP协议本n是无状态的Q这与HTTP协议本来的目的是相符?wbr>Q客L只需要简单的向服务器h下蝲某些文gQ无论是客户端还?wbr>服务器都没有必要U录彼此q去的行为,每一ơ请求之间都是独立的
1、该店的店员很厉宻I能记住每位顾客的消费数量
3、发l顾客一张会员卡Q除了卡号之外什么信息也不纪?wbr>Q每ơ消ҎQ如果顾客出C卡片Q则店员在店里的U录本上扑ֈq?wbr>个卡号对应的U录d一些消费信息。这U做法就是在服务器端保持?wbr>态?/wbr>
cookie机制的基本原理就如上面的例子一L?wbr>Q但是还有几个问题需要解冻I"会员?如何分发Q?会员?wbr>"的内容;以及客户如何使用"会员??/wbr>
如果不设|过期时_则表C个cookie的生命期为浏览器会话
Location: http://www.google.com/intl/zh
Set-Cookie: PREF=ID=0565f77e132de138:NW=1
Content-Type: text/html
q是使用HTTPLookq个HTTP Sniffer软g来俘LHTTP通讯U录的一部分
览器在再次讉Kgoolge的资源时自动向外发送cookie
使用Firefox可以很容易的观察现有的cookie的?br />使用HTTPLook配合Firefox可以很容易的理解cook
IE也可以设|在接受cookie前询?/font>
q是一个询问接受cookie的对话框?/font>
session机制是一U服务器端的机制Q服务器使用一U类g?wbr>列表的结构(也可能就是用散列表Q来保存信息?/wbr>
另一U是作ؓ查询字符串附加在URL后面Q表现Ş式ؓhttp:
q两U方式对于用h说是没有区别的,只是服务器在解析的时候处?wbr>的方式不同,采用W一U方式也有利于把session id的信息和正常E序参数区分开来?br />Z在整个交互过E中始终保持状态,必d每个客户端可能请求的
<form name="testform" action="/xxx">
<input type="text">
</form>
在被传递给客户端之前将被改写成
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV
<input type="text">
</form>
q种技术现在已较少应用Q笔者接触过的很古老的iPlanet6
HttpSession是Javaq_对session机制的实?wbr>规范Q因为它仅仅是个接口Q具体到每个web应用服务器的提供?wbr>Q除了对规范支持之外Q仍然会有一些规范里没有规定的细微差?wbr>。这里我们以BEA的Weblogic Server8.1作ؓ例子来演C?/wbr>
Q在本小节中session的含义ؓ⑤和⑥的混合Q?/font>
1、session在何时被创徏
一个常见的误解是以为session在有客户端访问时p创徏Q然而事实是直到某server端程序调用HttpServletR
严格的讲Q做不到q一炏V可以做一点努力的办法是在所有的客户端页面里使用javascri
你可以创Llistenerȝ控session的创建和销
http://e-docs.bea.com/wls
参见W三节对cookie的讨论,对session来说是只认i
q个问题与防止表单多ơ提交是cM的,可以通过讄客户端的令牌?wbr>解决。就是在服务器每ơ生成一个不同的idq回l客L
做这个动作主要是Z在集环境中提示Weblogic Server session中的值发生了改变Q需要向其他服务器进E复制新的s
常常有这L情况Q一个大目被分割成若干项目开?wbr>Qؓ了能够互不干扎ͼ要求每个项目作Z个单独的web应用E序
<path>/NASApp</path>
</session-info>
在Tomcat中则没有q么方便的选择。在Tomcat版本3?wbr>Q我们还可以有一些手D|׃nsession。对于版?以上的T
context.setAttribute("appA", session);
contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttrib
session机制本nq不复杂Q然而其实现和配|上的灵zL却?wbr>得具体情况复杂多变。这也要求我们不能把仅仅某一ơ的l验或者某一
--
房子{在上
]]>
CASE:
Invitor:邀误对象模?br />Integer Invitor.joinstatus:邀误所处参加状?br />当前存在状态声明:是否被邀P是否注册用户Q是否拒l,是否审批
设计思\Q?br />bit0: 1-invited , 0-not invited
bit1: 1-registed , 0-not registed
bit2: 1-refused , 0-not refused
bit3: 1-approved , 0-not approved
Example:0111(7)=the invitor is invited ,and is registed ,and has been refused without approved.
//判断joinstatus状?br />public static String theStatusOfApplicant(Invitor iv) throws TrainingAppException {
String status = "default";
if (((iv.getJoinStatus() & 0x8) == 0) && ((iv.getJoinStatus() & 0x4) == 0)) {
status = "default";// 待批?0x0)
}
if (((iv.getJoinStatus() & 0x8) == 0x8) && ((iv.getJoinStatus() & 0x4) == 0)) {
status = "approved";// 已审?0x4)
}
if (((iv.getJoinStatus() & 0x4) > 0) && ((iv.getJoinStatus() & 0x8) == 0)) {
status = "refused";// 已拒l?0x8)
}
return status;
}
//更新joinstatus状?审批和拒lؓ互斥)
private void updateJoinstatus(MainTrainingInfo mtrInfo, List<Invitor> invitors, Integer opertorType) {
for (Iterator it = invitors.iterator(); it.hasNext();) {
Invitor iv = (Invitor) it.next();
if (APPLY_OPERTORTYPE_APPROVE == opertorType.intValue()) { // approve
iv.setJoinStatus((iv.getJoinStatus() | 0x8) & 0x8);
} else {
iv.setJoinStatus((iv.getJoinStatus() | 0x4) & 0x4); // refuse
}
iv.setMainId(mtrInfo);
mtrInfo.getInvitor().add(iv);
}
persistence.update(mtrInfo);
if (APPLY_OPERTORTYPE_APPROVE == opertorType.intValue()) { // approve
log.info(" ### 甌已获批准,发送邀请邮?");
// Send Mails.
try {
instanceMailSendService.approveInvitorSendMail(mtrInfo, invitors, getHostEmail(mtrInfo),
MainTrainingInfoUtil.getLocale(mtrInfo), true, true);
} catch (Exception e) {
log.error(e.toString());
}
}
}
对原生SQL查询执行的控制是通过SQLQuery接口q行的,通过执行Session.createSQLQuery()获取q个接口。最单的情况下,
可以采用以下形式Q?/font>
List cats = sess.createSQLQuery("select * from cats")
.addEntity(Cat.class)
.list();
q个查询指定?
SQL查询字符?/font>
查询q回的实?/font>
q里Q结果集字段名被假设Z映射文g中指明的字段名相同。对于连接了多个表的查询Q这可能造成问题Q因为可能在?br />个表中出现同样名字的字段。下面的Ҏ可以避免字D名重复的问?
List cats = sess.createSQLQuery("select {cat.*} from cats cat")
.addEntity("cat", Cat.class)
.list();
q个查询指定?
SQL查询语句Q它带一个占位符Q可以让Hibernate使用字段的别?
查询q回的实体,和它的SQL表的别名.
addEntity()ҎSQL表的别名和实体类联系hQƈ且确定查询结果集的Ş态?
addJoin()Ҏ可以被用于蝲入其他的实体和集合的兌.
List cats = sess.createSQLQuery(
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
)
.addEntity("cat", Cat.class)
.addJoin("kitten", "cat.kittens")
.list();
原生的SQL查询可能q回一个简单的标量值或者一个标量和实体的结合体?
Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
.addScalar("maxWeight", Hibernate.DOUBLE);
.uniqueResult();
除此之外Q你q可以在你的hbm文g中描q结果集映射信息Q在查询中用?/font>
List cats = sess.createSQLQuery(
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
)
.setResultSetMapping("catAndKitten")
.list();
2.命名SQL查询
可以在映文档中定义查询的名?可以象调用一个命名的HQL查询一L接调用命名SQL查询.在这U情况下,不需要调用addEntity()
Ҏ.
<sql-query name="persons">
<return alias="person" class="eg.Person"/>
SELECT person.NAME AS {person.name},
person.AGE AS {person.age},
person.SEX AS {person.sex}
FROM PERSON person
WHERE person.NAME LIKE :namePattern
</sql-query>
List people = sess.getNamedQuery("persons")
.setString("namePattern", namePattern)
.setMaxResults(50)
.list();
在sping里面用回调查?br /> public List getPaysByBizId(final String bizId) {
return (List)getHibernateTemplate().execute(new HibernateCallback(){
public Object doInHibernate(Session session)throws HibernateException{
Query query = session.getNamedQuery("find.pays.by.bizid");
query.setParameter("bizId",bizId);
return query.list();
}
},true);
}