会话
会话可以简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
每个用户与服务器进行交互的过程中,各自会有一些数据,程序要想办法保存每个用户的数据。可以通过两种方式:Cookie/Session。
Cookie
Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器,当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去,这样,web资源处理的就是用户各自的数据了。
javax.servlet.http.Cookie类用于创建以一个Cookie,response接口中也定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段,同样,request接口中也定义了一个getCookie方法,它用于获取客户端提交的Cookie。
显示上次访问时间并可清除
1 | PrintWrite out = response.getWrite(); |
tip:如果创建了一个cookie,并将它发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器内存 中),用户退出浏览器之后即被删除,若希望浏览器将该cookie存储在硬盘上,需使用setMaxAge,并给出一个以秒为单位的时间,将最大失效设为0则是命令浏览器删除该cookie,注意删除cookie时,path必须一致,否则不会删除。
Session
Session是服务器端技术,利这个技术,服务器在运行时可以为每一个用户的浏览器创建一个独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其他资源时,其他web资源再从用户各自的session中取出数据为用户服务。
1 | //buySession |
session对象在调用getSession方法时创建,在30分钟内没有再次使用,浏览器会自动销毁,手动摧毁使用invalidate()方法即可。
session工作原理
session工作是基于cookie的。服务器创建session出来后,会把session的id号,以cookie的形式回写给客户机,这样,只要客户机的浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现客户机浏览器带session id过来了,就会使用内存中与之对应的session为之服务。
现在有个问题,Sun公司在设计getSession方法时,默认使用cookie没有使用期限,也就是随着浏览器关闭,cookie也就销毁,也就意味着标识每一个session的唯一ID被销毁,这样就无法使session存留30分钟。
解决办法:
在获得session之后获取到ID号,重写对应的cookie,覆盖掉本来的即可。
1 | HttpSession session = request.getSession(); |
防止表单重复提交
1 | //form.jsp |
1 | //DoFormServlet |
但是会有如下三种情况的表单重复提交:
- 在网络延迟的情况下让用户有时间点击多次submit按钮导致表单重复提交;
- 表单提交后用户点击【刷新】按钮导致表单重复提交;
- 用户提交表单后,点击浏览器的【后退】按钮回退到表单页面后进行再次提交;
解决方案:
- 利用JavaScript防止表单重复提交
1 | <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> |
或者,表单提交之后,将提交按钮设置为不可用,让用户没有机会点击第二次提交按钮:
1 | function dosubmit(){ |
使用JavaScript防止表单重复提交的做法只对上述提交到导致表单重复提交的三种场景中的【场景一】有效,而对于【场景二】和【场景三】是没有用,依然无法解决表单重复提交问题。
- 利用Session防止表单重复提交
具体的做法:在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
在下列情况下,服务器程序将拒绝处理用户提交的表单请求:
- 存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
- 当前用户的Session中不存在Token(令牌)。
- 用户提交的表单数据中没有Token(令牌)。
首先,创建FormServlet,用于生成Token(令牌)和跳转到form.jsp页面
1 | package xdp.gacl.session; |
在form.jsp中使用隐藏域来存储Token(令牌)
1 | <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> |
DoFormServlet处理表单提交
1 | package xdp.gacl.session; |
生成Token的工具类TokenProccessor
1 | package xdp.gacl.session; |
通过这种方式处理表单重复提交,可以解决上述的场景二和场景三中出现的表单重复提交问题。
注:转载文章请注明出处,谢谢~