如果你想要转载话,可不可以不要删掉下面的
作者信息
呀!;
作者:淮左白衣
写于
来源笔者自己之前学javaWeb的时候,写的笔记 ;
目录
Session对象
在 web
开发中,服务器可以为用户浏览器创建一个会话对象(session对象
)
注意
:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session
中,当用户使用浏览器访问其他程序时,其他程序可以从用户的 session
中取出该用户的数据,为用户服务 ;
Session和cookie的主要区别在于:
Cookie
是把用户数据写给用户的浏览器
-
session
技术把用户的数据写到用户独占的session
中。Session
对象有服务器创建,开发人员
可以调用request
对象的getSession
方法得到session对象 。
一个session对象只为一个会话服务 ;也就是说在 同一台电脑
上,打开 同一个浏览
器两次,会创建2个session对象。这里就引申出 session的生命周期
问题 ;
Session对象的生命周期
创建: 并不是浏览器访问服务器就会创建session对象;而是当浏览器访问的资源中有 getSession()
这个方法时,才会创建session对象 ;
当session对象创建以后 ,再次访问 getSession()
这个方法时,不会创建新的session对象;只是去获取服务器已经创建好的 session
对象 ;
销毁: 当一个 session
对象 30分钟
内没有人使用,那么服务器就会销毁这个session对象 ;无论浏览器是否关闭,即使浏览器没有被关闭,但是只要这个session
对象30分钟
内没有被使用,就会被销毁 ; 这个 30分钟
,我们是可以通过修改服务器的配置来改变这个有效时长的 ;
通过服务器配置,修改 session
有效时长:单位是分钟
;
<session-config>
<session-timeout>10</session-timeout>
</session-config>
通过代码,销毁session
// 销毁session对象
session.invalidate();
getSession()方法重载
这样,就会只获取session
,而不创建session
;如果,没有创建对象,则返回null ;
request.getSession(false) ;
session的实现原理
其实 session
是基于 cookie
的;
设想一下,为什么服务器那么聪明,可以知道什么时候创建session对象,什么时候不创建而是去获取session ? ;
原因 : ,就在于 session
是基于 cookie
技术的; 服务器第一次为浏览器创建一个 session
对象的时候,(这里要知道每一个session
对象,都是带有id
的),会将session的id
以cookie
的形式回写给浏览器。
因此,当服务器遇到 getSession()
方法的时候,它会看浏览器是否带有标识 session
对象id
的cookie
来,如果这样的cookie
,则为这次会话,创建一个session对象;如果有带着标识session
对象的id
的cookie
来,则服务器根据id
,返回对应的session
对象;
这个 cookie
是没有设置有效时长的,因此就是一个会话的 cookie
; 这也解释了为什么同一个浏览器打开两次,访问服务器会创建不同的session;
为服务器自动回写的cookie设置保存时长
服务器没有为代表Id的cookie没有设置有效时长,显然是不合理的,假如我们在逛淘宝,由于我们误操作,导致浏览器关闭了,那么我们之前的买的商品就丢失了,还需要再去买一次;
因此,我们需要去设置一个有效时长 ;
具体方法
:就是获得session对象的id,然后创建一个cookie
,将cookie
的名字和patn
设置,与服务器自动回写的cookie
一致;然后设置有效时长 ;
其中服务器回自动写的cookie
的名字为“JSESSIONID”
,path
为WEB项目的路径
;
getSession( )内部原理
getSession()
方法,获取到特定的session
对象 ;
内部实现
;它先根据代表id的cookie
来获取 ;如果没有这个cookie,就会去看是否重写了URL地址,如果重写了URL,则根据url后面的id来获取session对象;
如果,上述两种方法都没有,则获取不到session,它会创建一个session对象 ;
URL地址重写
当浏览器 禁止接受cookie
的时候,我们需要对URL地址,进行重写,以达到根据cookie分辨出,谁是谁的session
的效果;
我们需要对我们的网址的超链接,进行URL重写
,就是在超链接的后面添加浏览器各自的session
对象的 id
;这样,根据这个id,response.getSession()
就可以获得服务器中已创建的 session
对象了 ;
URL重写
这一步 Sun
公司帮我们做好了:方法:response.encodeURL(url)
,自动在url后面加上session的id,返回一个带有id标识的超链接 ;这样,即使禁止了保存cookie,服务器还是可以知道谁是谁的session ;
但是,假如浏览器禁止保存cookie,即使我们进行了URL地址重写,当关闭浏览器,再打开,就会创建新的session对象了 ;,因为,毕竟浏览器端,是不保存任何cookie的数据的 ;进行URL重写,只能保证,一次会话期间,服务器可以分辨出,谁是谁的session ;
只要涉及到会话管理的url,都要重写URL地址,因为,我们不确定浏览器是否禁止保存cookie了;
当我们进行了URL重写的时候 ,重定向,sendRedirect
后面的地址,需要使用encodeRedirectURL() ;
细节
:当我们没有禁止保存cookie的时候,同时又存在重写URL编码,这时候,会发生什么呢?
在第一次访问服务器的时候,服务器是不知道浏览器是否禁止了cookie,它会回写一个cookie,并且同时还对URL地址进行重写;这时候刷新一下页面的时候,浏览器就会带着cookie去访问服务器,服务器发现浏览器没有禁止cookie,就不再对URL地址进行重写 ;
备注
:同一个浏览器,打开多个选项卡,或者打开新的窗口,都会共享session对象,因为浏览器的进程没有销毁,cookie还存活着;以上的话都是基于IE7,到IE8就变了,即使关闭浏览器再打开,还是共享session对象 ;
Session案例
模拟购物功能
;但是一般都是用cookie来完成,考虑到服务器压力,为每个用户创建一个session保存购物信息,需要巨大的内存空间,而且session有效时间为半小时,时间越久服务器压力越大 ;
模拟登录功能
;使用session的原因,是因为其他servlet需要知道用户的登录状态;我们把用户的登录状态保存到session对象中,便于其他servlet查看;(cookie也可以完成)
保存登录状态
:就是保存用户的对象,一个唯一的标记即可 ;注销登录状态,就是将浏览器对应的session对象中的标记去除 ;
还是一样的,代码太多 ,贴上来,也不一定有人看,别说代码,就这篇博客,可能都没人看,,,
假如,你真的需要代码,可以加下我的QQ:1255621959 ;(好孩子看不到系列,(全选试试))
表单细节:
在写表单的时候,需要为提交的内容写一个name
属性,没有这个name
属性,对应的数据是不会得到提交的 ;
表单默认以get
方式提交;表单上添加action
属性,表示将数据提交到哪里;
防止表单重复提交;
有两种方法可以防止重复提交 ;
-
在客户端使用JS
但是,这样做不是万无一失的;对于懂行的人来说,可以查看网页源代码,会看到表单的源代码,它会得到我们将表单提交的servlet地址;也会发现,我们是使用JS来防止重复提交的,它只要将js的代码删除,保存页面再继续访问,数据就会被重复提交;(简而言之JS代码会被删掉)
-
在服务器端防止数据重复提交
我们在
服务器端
使用程序生成一个随机数
,将这个随机数放到表单里面,进行返回,服务器在浏览器提交数据的时候,会检查浏览器提交的数据带有的随机数,在服务器中是否存在;如果存在了,则说明表单已经提交过了; -
随机数问题
如果随机数,在服务器中存在;则允许提交数据;在提交完数据以后,将服务器保存的随机数删掉;下次浏览器再次提交数据,也不会处理了;
在生成随机数的时候,使用单例模式,创建一个随机数发生器,目的是为了防止减少随机数重复的概率;我们一般使用当前时间的毫秒值+一个随机数来拼接成一个随机数 ;
数据指纹算法
拼接随机数的时候,后面的随机数的长度是不确定的,导致拼接的随机数长度也是不确定的;我们最好保证每次生成的随机数的长度是一致的;但是显然是不可能的保证到的;但是我们可以使用数据指纹,无论数据的长度是多少,它们的数据指纹长度是固定的 ;我们选用MD5
算法,生成数据指纹,长度是128位(16K);
// 获取当前时间的毫秒值
long time = System.currentTimeMillis();
String random = time + new Random().nextInt() + "";
// 由于拼接出来的random长度是不一样的
try {
// 转化为长度固定为128位的MD5数据指纹
byte[] md5 = MessageDigest.getInstance("md5").digest(random.getBytes());
// MD5需要进行base64编码
return Base64.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
类MessageDigest.digest()
方法,生成数据指纹;返回的是一个字节数组 ;MD5还是可以用于验证信息的完整性 ;
base64编码
不能使用得到的 数据指纹
字节数组直接new字符串,因为生成的字节数组里面的放到的东西是啥,我也不清楚,反正GB2312码表里面没有;转码会出现乱码;这是就需要特定的转码方法base64编码 ;
Base64编码
是将每3个字节变为4个字节;三个字节24位,每次取6位,空余的2个高位用0补全 ;这样3个字节就变为4个字节;组成的四个字节,每个字节的最小值为0(00000000),最大值为63(00111111);然后base64编码有自己的码表,它把0~63都变为明文,即键盘上可见的字符;这样无论原始数据,是什么,都可以变为明文,而不出现乱码 ;
Base64编码的使用场景很多
,比如上传下载文件,浏览器都会自动的把数据进行base64编码的;这样就可以选择不在base64码表中的字符来当做结束开始标记 ;
验证码的验证:
在服务器发送验证码给浏览器的时候,先将验证码存储到浏览器对应的session对象中;然后验证浏览器带过来的验证码和保存到session中的验证码是否一样; (注意编码问题)
再讲转发与重定向的区别
-
转发
:浏览器的url的地址是不会发生改变的,这样每次刷新页面,都会执行转发之前的逻辑和转发 ;
这样,在有些场景就会出现问题,比如买东西,每次刷新,都会再次执行买的逻辑,买无数次。。。 -
重定向
:浏览器的url的地址发生改变,,这样每次刷新页面,都会执行新的地址的
还是买定西的场景:会将购买商品的页面的地址重定向到购物车的地址,这样刷新,就是刷新购物车,和购买商品没关系。就不会出现购买多次的情况了 ;
Servlet的提供的容器(域)
request
域
数据仅仅使用一次,使用结束以后,就没有用了的情况,选用request域 ;session
域
数据使用完以后,过一会还需要继续使用,选用session域servletContext
域
数据使用完以后,过一会还需要继续使用,不仅还需要继续使用,等会还需要给别人使用,选用servletContext域 ;