会话技术:
什么是会话?
会话就是用户打开浏览器,读取多个页面,再关闭浏览器的过程. 在IE8以下的IE浏览器中,如果打开了一个浏览器,在没有关闭的情况下,又打开另一个浏览器,那么 视为两个不同的会话,而IE8以上的IE浏览器则视为同一次会话.
会话的作用:
会话技术主要用于解决一次会话过程中的数据保存问题.
Cookie:
是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
各自的数据了
Cookie特性:
1.name 必须的
2.Value 必须的,单一的值
3.Path 可选的,路径
4.Domain 可选的
5.Age 可选的,生命周期
注意:浏览器针对每一个网站最多支持20个cookie,浏览器最多支持300个cookie,每个cookie的大小不能超过4KB.
Cookie案例 1: 查看上次访问的时间 //设置cookie resp.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer=resp.getWriter(); writer.write("你上次访问的时间是 : "); Cookie [] cooks=req.getCookies();//得到所有的cooks的参数 for (int i = 0; cooks!=null&&i < cooks.length; i++) { if("lastAcceptTime".equals(cooks[i].getName()))//找到了对应的参数名 { String value =cooks[i].getValue();//得到值 long time=Long.parseLong(value);//把value变成字符串 writer.write(new Date(time).toLocaleString()); } } writer.write("<a href='"+req.getContextPath()+"/servlet/Test2'>clear</a>"); Cookie cook=new Cookie("lastAcceptTime",System.currentTimeMillis()+""); cook.setMaxAge(Integer.MAX_VALUE);//设置生命周期 resp.addCookie(cook); //把cookie的生命周期设置为0 Cookie [] cook=req.getCookies(); for (int i = 0;cook!=null&& i < cook.length; i++) { if("lastAcceptTime".equals(cook[i].getName())){ cook[i].setMaxAge(0); cook[i].setPath(req.getContextPath()); resp.addCookie(cook[i]); } } |
Cookie案例2 : 记住用户名 //设置页面 resp.setCharacterEncoding("UTF-8"); req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); PrintWriter out=resp.getWriter(); String username=""; String checked=""; Cookie[]cooks=req.getCookies(); for (int i = 0;cooks!=null&& i < cooks.length; i++) { if("username".equals(cooks[i].getName())){//查找到了username这个属性 username=cooks[i].getValue();//把cooks[i]的值赋给username checked="checked='checked'"; } } //提供登录页面 out.print("<html><head><title>登录</title></head><body>"); out.print("<form action='"+req.getContextPath()+"/servlet/ProcessServlet' method='post'>"); out.print("用户名:<input type='text' name='username' value='"+username+"'/><br/>"); out.print("密码:<input type='password' name='password' /><br/>"); out.print("<input type='checkbox' name='remember' "+checked+"/>记住用户名<br/>"); out.print("<input type='submit' value='登录' /><br/>"); out.print("</form></body></html>"); //判断是否记住用户名 req.setCharacterEncoding("UTF-8"); resp.setContentType("tet/html;charset=UTF-8"); String username=req.getParameter("username");//得到username的值 String remember=req.getParameter("checked");//得到checked的值 PrintWriter out=resp.getWriter(); if(remember!=null){//判断复选框是否勾选,如果没勾选,就=null Cookie cook=new Cookie("username",username);//创建一个cookie,把用户名添加到cookie中 cook.setPath(req.getContextPath()); cook.setMaxAge(Integer.MAX_VALUE); resp.addCookie(cook); }else{ Cookie []cooks=req.getCookies();//复选框没有勾选,就查找cookie for (int i = 0; cooks!=null&&i < cooks.length;i++) {//遍历cookie数组,得到用户名 if("username".equals(cooks[i].getName())){ cooks[i].setPath(req.getContextPath()); cooks[i].setMaxAge(0);//把用户名的cookie的生命周期设置为0 resp.addCookie(cooks[i]); } } out.print("恭喜!登录成功!"); } |
Session
Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的HttpSession对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
Web中的Session指的就是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。因此从上述的定义中我们可以看到,Session实际上是一个特定的时间概念。需要注意的是,一个Session的概念需要包括特定的客户端,特定的服务器端以及不中断的操作时间。A用户和C服务器建立连接时所处的Session同B用户和C服务器建立连接时所处的Session是两个不同的Session。
Session原理:
HttpSession其实是一个域对象,内部维护一个Map集合.
在HttpServletRequest中,可以使用getSession()方法或者getSession(boolean creat)方法得到session对象,那么这两个方法有什么区别呢?
getSession(): 如果客户端没有对应的session对象,那么就创建一个,如果有对应的session对象,就得到它.
getSession(boolean creat); 参数如果为true,那么和上面的方法一样,如果为false, 则只能获取.
实际上HttpSession实现原理就是使用了Cookie技术,把session对象的ID以cookie的形式写到了浏览器中.
Cookid的名称是:JSESSIONID
Cookid的取值是:Session的ID
Cookie的path是: 当前应用的路径
Cookie的age是: 浏览器的经进程
浏览器关闭,默认情况下结束会话,但是HttpSession对象不会立刻消失,而是保存30分钟,,要想立刻销毁HttpSession对象,可以执行invalidate方法
HttpSession的常用方法:
getId(); 获取到每个Session的ID值,这个ID值是随机生成的唯一值
getAttribute("name"); 得到指定的参数的值
setAttribute("key","value");设置参数的值
Session的内部实现原理其实就是Cookie,如果客户端禁用了Cookie,如果保存会话数据呢?
解决方法:在访问其他URL的时候,在后面加上JSESSIONID.因为Cookie的名称是JSESSIONID, 在URL中以参数的形式加上JSESSIONID,就可以把Cookie带给服务器.
这个过程称为URL重写.
Session的生命周期
浏览器关闭后,HttpSession不会立刻销毁,而是保存30分钟,如果想立刻销毁Httpsession,可以执行Httpsession的invalidate()方法.
可以再xml文件中设置session-timeout属性,属性值是的单位是分钟
<session-config>
<session-timeout>10</session-timeout>
</session-config>
强烈注意: 放入HttpSession中的对象的类型需要实现Serializable接口进行序列化
Session的状态:
Session在getSession的时候调用然后进入运行状态,当超时(30分钟未访问资源),或调用了invalidate()方法的时候,Session就被销毁了. 在Session运行状态的时候,如果session太多,或者应用重写启动了,那么session会被钝化,也就是进入持久化状态;当应用重新开启,或者常久没活动的session又活动了,那么session会从持久化状态被激活.
Session案例练习
1.验证表单是否重复提交. //设置表单,并且给表达隐藏域和session都提供一个相同的令牌,使用UUID对象的randomUUID方法生成随机令牌 resp.setContentType("Text/html;charset=UTF-8"); PrintWriter out=resp.getWriter(); UUID token=UUID.randomUUID();//生成一个随机数 req.getSession().setAttribute("token", token.toString());//把随机数写入session out.print("<form action='/day07/servlet/TestSubmit' method='post'>"); out.print("用户名:<input type='text' name='username'/><br/>"); out.print("<input type='hidden' name='token' value='"+token+"'/>"); out.print("<input type='submit' value='go'/></form>"); //得到表单隐藏域中的令牌和session中的令牌,对比令牌是否一致,如果一致,就登录成功,然后删除session中的令牌 resp.setContentType("Text/html;charset=UTF-8"); PrintWriter out=resp.getWriter(); String code=req.getParameter("token");//得到表单中的令牌 String scode=(String)req.getSession().getAttribute("token");//得到session中的令牌 if(code.equals(scode)){ out.write("登录成功!!"); req.getSession().removeAttribute("token"); }else{ out.write("请不要重复登录"); } |
UUID: 使用算法,计算出世界上唯一的一个令牌
使用UUID对象的randomUUID()可以生成令牌
二: 验证码验证 //在生成验证码数字的时候,通过MD5来进行加密,然后通过BASE64来找到加密后的密文对应的字符,再把这个密文加进session中 //MD5加密 MessageDigest md=MessageDigest.getInstance("md5");//通过MD5加密 byte [] b=md.digest(code.getBytes()); BASE64Encoder base=new BASE64Encoder();//密文找到对应的 return base.encode(b); //生成验证码,然后把验证码加密写入session中 private static int WIDTH = 120; private static int HEIGHT = 25; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //图片默认是会缓存的,去掉缓存 response.setHeader("Expires", "-1"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); //BufferedImage代表一副内存图片 BufferedImage image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB); //Graphics得到画笔,在图片上画 Graphics g = image.getGraphics(); g.setColor(Color.YELLOW); g.fillRect(0, 0, WIDTH, HEIGHT); g.setColor(Color.BLUE); g.drawRect(1, 1, WIDTH-2, HEIGHT-2); g.setColor(Color.GREEN); Random r = new Random(); for(int i=0;i<9;i++) g.drawLine(r.nextInt(WIDTH), r.nextInt(HEIGHT), r.nextInt(WIDTH), r.nextInt(HEIGHT)); g.setColor(Color.GRAY); g.setFont(new Font("宋体", Font.BOLD|Font.ITALIC, 22)); StringBuffer sb = new StringBuffer(); int x = 20; for(int i=0;i<4;i++){ int num = r.nextInt(10); g.drawString(num+"", x, 20); x+=20; sb.append(num); } try { request.getSession().setAttribute("code", MD5.codeing(sb.toString()));//验证码加密后写入session中 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } ImageIO.write(image, "jpeg", response.getOutputStream()); } //在输入验证码的时候,把输入的验证码也使用MD5加密,然后与session中的密文进行对比,如果相同,那么验证通过 String code=req.getParameter("code"); try { String scode=MD5.codeing((String) req.getSession().getAttribute("code")); if(code.equals(scode)){ System.out.println("登录成功!"); req.getSession().removeAttribute("code"); }else{ System.out.println("验证码失败!"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } |