Session
Cookie技术可以将用户的信息保存在各自的浏览器中,
优点:很明显实现了同一个用户不同请求中数据共享。
缺点:黑客可以利用脚本等手段 窃取cookie中的重要数据,从而泄漏个人的隐私,存在巨大的安全隐患。
session技术 是将会话的数据保存在服务器端的技术。
3.1.什么是session?
为了更好的理解session,以网站购物为例,通过一张图来描述session保存用户 信息的原理。
用户甲和用户乙都调用buyServlet将商品添加到购物车,调用payServlet进行商品结算。
由于甲和乙购买商品类似,这里以甲为主。
当用户甲访问购物网站时,服务器为甲创建了一个session对象(相当于购物车)。
当甲将小米手机添加到购物车时,小米手机的信息便存到了session对象中,同时,服务器将session对象的唯一标识id属性以Cookie的形式返回给甲的浏览器。
当甲完成购物进行结账时,需要向服务器结账请求,这时,浏览器就会自动在请求头将 唯一标识 回送给服务器。
服务器根据唯一标识,找到为用户甲创建的session容器,并将session对象中存放的手机信息进行结算。
需要注意的是:由于客户端需要接受、记录、和回送session的唯一标识,
因此通常情况下,session是借助cookie技术来传递ID属性的。
3.1.Session的API
3.1.1.获取Session对象
Session是基于用户的请求,而把用户的重要信息在服务器端针对这个用户(浏览器)创建了一个容器。
而这个Session容器是由web服务器(tomcat)帮助我们创建的,在程序中我们只能去获取到这个容器,然后给容器添加数据或者取出数据,或者删除数据,而我们是不能创建这个容器对象。
在HttpServletRequest对象中提供了获取session对象的方法:
使用request对象就可以获取到当前针对用户的请求服务器内部创建的那个Session容器对象。
HttpSession依然是一个接口,而这个接口的实现类有web服务器来提供。只要能够运行我们JavaEE项目的web访问前,它们都会实现Java提供的所有web技术中的接口。
演示Session:
需要2个Servlet程序:
在第一个Servlet中获取到Session对象,然后把用户当前的ip保存在Session中,在第二Servlet中取出,然后通过response对象把ip给客户端响应回去。第一个Servlet访问完之后,不使用转发技术。
给Session对象中保存数据:
需要使用HttpSession接口中的:
获取数据:
删除Session中的数据
需求1: 共享数据:第一个Servlet程序:获取到用户的ip保存在Session中;在第二个servlet中取出session中的ip(debug演示)
3、新建Session2Servlet,从session中获取ip
4、通过浏览器直接访问Session2Servlet,能够看到ip吗?
看不到,原因:还没有向session容器中存放ip。
5、通过浏览器先访问Session1Servlet,再访问Session2Servlet,能看到ip地址吗? 能
3.2.2.服务器端操作Session时细节
其实服务器端可以识别每个用户的对应的Session容器,主要是因为服务器针对每个用户都发送了JSESSIONID(session容器的唯一标识)的Cookie信息。这样用户在操作的时候,都会携带这个Cookie到服务器端,因此服务器端才能识别针对当前这个用户的那个session容器对象。
服务器在给客户端响应数据的时候,把Session容器的唯一标识以Cookie的形式发送给浏览器,而这个Cookie是一个会话级别(临时)Cookie,它只能存活在浏览器运行的阶段,如果浏览器关闭了,这个Cookie信息就没有了,因此在此打开浏览器访问的时候,就不会在服务器获取到针对当前用户的JSESSIONID信息,因此无法找到针对当前用户的那个Session容器。
进一步说明,服务器端的Session容器对象,是针对每个浏览器的。
3.2.3.使用getSession方法的细节
在api中提供2个获取Session对象的方法:
getSession():
空参数的方法,在使用的时候,如果服务器端针对当前用户的浏览器没有Session容器,这时在服务器的内部会先创建一个Session对象,然后把这个Session对象返回给我们的程序。
如果Session容易已经存在,这时它是不会再创建新的Session容器对象,只是把找到的这个Session容器对象返回给程序。在找的过程中需要依赖于JSESSIONID。
getSession(Boolean create):
如果这个在调用的时候,传递的值为false,它仅仅只会在容器根据JSESSIONID找有没有对应的Session容器对象,如果有就返回这个Session容器对象,如果没有,就返回null。
如果传递的值true,在根据JSESSIONID找Session容器对象的时候,如果不存在就会创建一个新的Session容器对象,并返回这个容器对象,如果存在就,直接返回存在的Session容器对象。
3.3.思考:关闭浏览器后再次访问能获取到Session的数据吗?
一般情况下,关闭浏览器之后,再次访问,是无法获取到Session中的数据的。
因此在服务器针对当前用户的第一次请求创建的唯一的Session容器对象,而在给这次请求的之后,服务器需要给用户响应数据,在响应的时候,服务器把当前Session容器对象的JSESSIONID以Cookie的形式发送给了浏览器。而这个Cookie并没有设置有效时间,那么这个Cookie就属于临时Cookie,在关闭浏览器之后,再次打开浏览器的时候,上次的Cookie已经消失了,用户虽然拿同一个浏览器访问服务器,可是这时没有JSESSIONID,服务器端的Session容器依然存在,但是没有JSESSIONID,服务器内部无法获取到这个session对象
把包含了JSESSIONID的Cookie在客户端持久化。
3.4.禁用Cookie后Session追踪
服务器端获取Session对象依赖于客户端携带的Cookie中的JSESSIONID数据。如果用户把浏览器的隐私级别调到最高,这时浏览器是不会接受Cookie、这样导致永远在服务器端都拿不到的JSESSIONID信息。这样就导致服务器端的Session使用不了。
Java针对Cookie禁用,给出了解决方案,依然可以保证JSESSIONID的传输。
Java中给出了再所有的路径的后面拼接JSESSIONID信息。
使用response对象中的方法完成:
需求3:浏览器禁用cookie,当前servlet的session中设置ip,超链接跳转另一个servlet时可以获取ip地址。
1在Session1Servlet中,使用response.encodeURL(url)对超链接路径拼接 session的唯一标识
2使用浏览器访问
在response对象中的提供的encodeURL方法它只能对页面上的超链接或者是form表单中的action中的路径进行重写(拼接JSESSIONID)。
如果我们使用的重定向技术,这时必须使用下面方法完成:
1在Session1Servlet的基础上增加如下代码:
其实就是在路径后面拼接了Session的唯一标识 JSESSIONID。
3.5.Session的生命周期(面试)
Session对象的创建时间:
当前服务器启动之后,用户第一次访问某个Servlet程序的时候,在这个Servlet中调用getSession()方法或者调用的getSession(true),这时服务器内部才会针对当前这个用户的浏览器创建一个Session容器对象。
Session的销毁时间:
1、不正常关闭服务器。如果是正常关闭服务器,这时服务器内部会使用IO流中的序列化技术把这个Session对象保存在tomcat/work目录下面。
2、Session在服务器的存活时间。Session对象在服务器内部有默认的存活的时间。一般默认是30分钟。如果在30分钟内,用户没有再对当前这个服务器中的资源进行任何的访问操作,这时只要时间到达30分钟,服务器会自动的销毁这个session。
Session的存活时间我们可以在当前这个项目的web.xml中配置:
3、调用HttpSession中的销毁Session的方法:
3.1.Session案例一次性验证码登录
验证码的实现原理:
在一个Servlet中生成验证,并把验证码上的数据保存在Session,用户提交验证码之后,会提交给另外一个Servlet程序。在获取用户提交数据的Servlet中的从Session中把验证码取出,在取出的同时从Session中把验证码删除。
注册页面:register.jsp
生成验证码参考:cn.itcast.session.CheckImgServlet
publicclassCheckImgServletextendsHttpServlet {
publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {
intwidth = 120;
intheight = 40;
// 先生成一张纸
BufferedImage bufi =newBufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 画笔
Graphics g = bufi.getGraphics();
// 设置背景颜色
// 修改画笔颜色
g.setColor(Color.white);
// 填充
g.fillRect(0, 0, width, height);
// 绘制边框
// 设置边框颜色
g.setColor(Color.red);
// 画边框
g.drawRect(0, 0, width - 1, height - 1);
// 准备一些数据
String data ="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz";
// 生成随机对象
Random r =newRandom();
String checkcode ="";
// 生成4个随机的数字
for(inti = 0; i < 4; i++) {
// 生成随机颜色
g.setColor(newColor(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
// 设置字体
g.setFont(newFont("宋体", Font.ITALIC, 25));
String c = data.charAt(r.nextInt(data.length())) +"";
g.drawString(c, 10 + (20 * i), 30);
checkcode += c;
}
// 将生成的验证码放到 session中
request.getSession().setAttribute("session_checkcode", checkcode);
// 画干扰线
for(inti = 0; i < 8; i++) {
// 设置随机颜色
g.setColor(newColor(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
// 画线 两点确定一线
g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
}
// 将图片输出到浏览器
ImageIO.write(bufi,"jpg", response.getOutputStream());
}
publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {
}
}
注册servlet:
3.1.Servlet三种数据范围
下面的三个对象,可以当做容器来使用,可以保存数据,因此他们也被称为域对象。
ServletContext:它保存的数据所有的Servlet共享。它的范围最大。开发几乎不用。除非需要保存整个项目中共享的信息才会使用。
HttpSession:它是针对当前某个用户(浏览器)的一系列操作,然后在服务器端创建的一个容器,整个容器仅仅只能是当前这个客户端(浏览器)使用。多个客户端(浏览器),它们会有不同的Session容器对象
HttpServletRequest:它的针对用户的这次请求,只要请求和响应结束,这个容器就消失了。一般开发中这个容器是最常用。只要给request中保存了数据之后,那么就会使用转发技术,转发到JSP页面上,在页面上使用EL表达式把request中的数据取出,并显示。