会话技术Cookie和Session

会话技术
    1.浏览器开始访问网站到访问网站结束期间产生的多次请求响应组合在一起叫做一次会话
    会话的过程中会产生会话相关的数据,我们需要将这些数据保存起来。
    
    Cookie:客户端技术
    Session:服务器端技术

    
    2.Cookie   
        Cookie是基于set-Cookie响应头和Cookie请求头工作的,服务器可以发送set-Cookie请求头命令浏览器保存一个cookie信息,浏览器会在访问服务器时以Cookie请求头的方式带回之前保存的信息
        
        request.getCookies();
        
        response.addCookie(Cookie c);
        
        new  Cookie(String name,String value)//Cookie在构造的时候就需要设定好cookie的名字和值
        getName();
        getValue();
        setValue();
        !!setMaxAge与getMaxAge方法  
            -- 一个Cookie如果没有设置过MaxAge则这个Cookie是一个会话级别的Cookie,这个Cookie信息打给浏览器后浏览器会将它保存在浏览器的内存中,这意味着只要浏览器已关闭随着浏览器内存的销毁Cookie信息也就消失了.一个Cookie也可以设置MaxAge,浏览一一旦发现收到的Cookie被设置了MaxAge,则会将这个Cookie信息以文件的形式保存在浏览器的临时文件夹中,保存到指定的时间到来位置.这样一来即使多次开关浏览器,由于这些浏览器都能在临时文件夹中看到cookie文件,所以在cookie失效之前cookie信息都存在.
            -- 想要命令浏览器删除一个Cookie,发送一个同名同path的cookie,maxage设置为0,浏览器以名字+path识别cookie,发现同名同path,cookie覆盖后立即超时被删除,从而就 删除了cookie.
            
        c.setMaxAge(0);
c.setPath(request.getContextPath());

response.addCookie(c);






        !!setPath与getPath方法
            -- 用来通知浏览器在访问服务器中的哪个路径及其子路径时带着当前cookie信息过来
                如果不明确设置,则默认的路径是发送Cookie的Servlet所在的路径
                http://localhost/Day05/servlet/...
  
        
        

案例:上次访问网站的时间:

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		
		Cookie []  cs = request.getCookies();
		Cookie findC = null;
		if(cs!=null){
			for(Cookie c : cs){
				if("lastTime".equals(c.getName())){
					findC = c;
				} 
			}
		}
		if(findC == null){
			response.getWriter().write("您是第一次访问本网站!");
		}else{
			Long lastTime = Long.parseLong(findC.getValue());
			response.getWriter().write("您上次访问时间是:"+new Date(lastTime).toLocaleString());
		}
		
		Date date = new Date();
		Cookie c = new Cookie("lastTime",date.getTime()+"");
		c.setMaxAge(3600*24*30);
		c.setPath(request.getContextPath());
		//c.setDomain(".baidu.com");
		response.addCookie(c);
	}













    
    3.Session

        Session 是一个域
            !!作用范围:当前会话范围
            !!生命周期:【三种销毁方法】

                当程序第一次调用到request.getSession()方法时说明客户端明确的需要用到session此时创建出对应客户端的Session对象.

                当session超过30分钟(这个时间是可以在web.xml文件中进行修改的)没有人使用则认为session超时销毁这个session.
                程序中明确的调用session.invalidate()方法可以立即杀死session.
                当服务器被非正常关闭时,随着虚拟机的死亡而死亡.

                *如果服务器是正常关闭,还未超时的session会被以文件的形式保存在服务器的work目录下,这个过程叫做session的钝化.下次再正常启动服务器时,钝化着的session会被恢复到内存中,这个过程叫做session的活化.

得到Session,没有就创建://检查一下当前浏览器有没有session,有就直接来来用,没有就创建一个session
HttpSession session = request.getSession();

            ! !作用:在会话范围内共享数据

!!session 的原理:
request.getSession()方法会检查请求中有没有JSESSIONID cookie,如果有拿出他的值找到对应的session为他服务.
如果没有则检查请求的URL后有没有以参数的形式带着JSESSIONID过来,如果有则找到对应的Session为浏览器服务器
如果还找不到则认为这个浏览器没有对应的Session,创建一个Session然后再在响应中添加JSESSIONID cookie,值就是这个Session 的id


默认情况下,JSESSIONID 的path为当前web应用的名称,并且没有设置过MaxAge,是一个会话级别的cookie.

这意味着一旦关闭浏览器再新开浏览器时,由于JSESSIONID丢失,会找不到之前的Session

我们可以手动的发送JSESSIONID cookie,名字和path设置的和自动发送时一样,但是设置一下MaxAge,使浏览器除了在内存中保存JSESSIONID信息以外还在临时文件夹中以文件的形式保存,这样即使重开浏览器仍然可以使用之前的session

利用原理:实现在用户关闭浏览器后,借助于Cookie技术,重写原来一模一样的Session来实现登陆浏览器后仍然能够看到以前的信息:

//下面这行代码利用session原理,实现在关闭浏览器后再次登录仍然有用户信息。
		//实际上是在session之前将sessionID写回到客户端,在临时文件夹中保存
		HttpSession session = request.getSession();
		Cookie jc = new Cookie("JSESSIONID",session.getId());   //之前设置了setMaxAge,这次是从浏览器的临时文件中取sessionID
		jc.setPath(request.getContextPath());
		jc.setMaxAge(1800);
		response.addCookie(jc);
		session.setAttribute("prod", prod);




URL重写:
如果浏览器禁用了Cookie,浏览器就没有办法JSESSIONID cookie,这样就用不了Session了.
我们可以使用URL重写的机制,在所有的超链接后都以参数的形式拼接JSESSIONID信息,从而在点击超链接时可以使用URL参数的方式待会JSESSIONID,从而使用Session
将URL进行重写拼接上JSESSIONID的过程就叫做URL重写


request.getSession() --在URL重写之前一定要先创建出Session,才有Session id,才能进行重写
response.encodeURL()--- 一般的地址都用这个方法重写
response.encodeRedirectURL() --- 如果地址是用来进行重定向的则使用这个方法

*url重写的方法一旦发现浏览器带回了任意cookie信息,则认为客户端没有禁用cookie,就不会再进行重写操作

经典实例:对于URL重写技术主要解决了用户禁用了Cookie,我们让用户在关闭浏览器之后重新打开浏览器时仍然能够显示用户信息的功能,但是实际生活中用的不多,像淘宝网站,超链接是亿级以上的,不可能用URL重写来解决问题的。

 <%
  	request.getSession();
  
  	String url1 = request.getContextPath()+"/servlet/BuyServlet?prod=电视机";
  	url1 = response.encodeURL(url1);
  	String url2 = request.getContextPath()+"/servlet/BuyServlet?prod=冰箱";
  	url2 = response.encodeURL(url2);
  	String url3 = request.getContextPath()+"/servlet/PayServlet";
  	url3 = response.encodeURL(url3);
   %>
  	<a href="<%= url1 %>">电视机</a>
  	<a href="<%= url2 %>">冰箱</a>
  	<a href="<%= url3 %>">结账</a>


cookie是客户端技术
数据保存在客户端,这个信息可以保存很长时间
数据随时有可能被清空,所以cookie保存的数据是不太靠谱的
数据被保存在了客户端,随时有可能被人看走,如果将一些敏感信息比如用户名密码等信息存在cookie中,可能有安全问题


session是服务器端技术
数据保存在服务区端,相对来说比较稳定和安全
占用服务器内存,所以一般存活的时间不会太长,超过超时时间就会被销毁.我们要根据服务器的压力和session 的使用情况合理设置session的超时时间,既能保证session的存活时间够用,同时不用的session可以及时销毁减少对服务器内存的占用.


Session案例:

!!用户登录注销

登陆界面:login.jsp

<pre name="code" class="java">	<h1>我的网站-登录</h1><hr>
  	<form action="${pageContext.request.contextPath }/servlet/LoginServlet" method="POST">
  		用户名:<input type="text" name="username"/>
  		密码:<input type="password" name="password"/>
  		<input type="submit" value="登录"/>
  	</form>


 
 

在LoginServlet中,检查用户名是否正确,如果正确就导向主页,如果不正确给予提示用户名或密码不正确:

		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		//1.获取用户名密码
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		//2.查询数据库检查用户名密码
		if(UserDao.valiNamePsw(username, password)){
			//3.如果正确登录后重定向到主页
			request.getSession().setAttribute("user", username);
			response.sendRedirect(request.getContextPath()+"/loginout/index.jsp");
			return;
		}else{
			//4.如果错误提示
			response.getWriter().write("用户名密码不正确!");
		}
	


在主页index.jsp界面:显示用户的登陆状态,然后若已经登陆提示欢迎回来用户可以注销

  	<h1>我的网站</h1><hr>
  	<%
  		//获取session中的登录状态
		String user = (String)session.getAttribute("user");
  	 %>
  	 <%
  	 	if(user == null || "".equals(user)){//用户没有登录
  	 		%>
  	 			欢迎光临!游客!
  	 			<a href="${pageContext.request.contextPath }/loginout/login.jsp">登录</a>
  	 			<a href="#">注册</a>
  	 		<%
  	 	}else{//用户登录过
  	 		%>
  	 			欢迎回来!<%=user %>!
  	 			<a href="${pageContext.request.contextPath }/servlet/LogoutServlet">注销</a>
  	 		<%
  	 	}
  	  %>


在注销的Loginout的Servlet中,杀死Session即可。

		//1.杀死session
		if(request.getSession(false)!=null 
				&& request.getSession().getAttribute("user")!=null){
			request.getSession().invalidate();
		}
		//2.重定向到主页
		response.sendRedirect(request.getContextPath()+"/loginout/index.jsp");
	

UserDAO

public class UserDao {
	private UserDao() {
	}
	private static Map <String,String>map = new HashMap<String, String>();
	static{
		map.put("张三丰", "111");
		map.put("张翠山", "999");
		map.put("张无忌", "888");
		map.put("赵敏", "777");
	}
	public static boolean valiNamePsw(String username,String password){
		return map.containsKey(username) && map.get(username).equals(password);
	}
}



防止表单重复提交:两种方法,第一种是前台js校验第二种前台传入一个随机数random并放到Session,第一次登陆后,后台将Session中的random移出,当再次登陆后,Session中的random已经为空了,不执行再次登陆注册的业务逻辑。

login.jsp

  	<script type="text/javascript">
  		var isNotSub = true;
  		function canSub(){
  			if(isNotSub){
  				isNotSub = false;
  				return true;
  			}else{
  				alert("请不要重复提交!!!");
  				return false;
  			}
  		}
  	</script>
  </head>
  <body>
  <%
  	Random r = new Random();
  	int valinum = r.nextInt();
  	session.setAttribute("valinum",valinum+"");
   %>
  	<form action="${pageContext.request.contextPath }/servlet/ResubServlet" method="POST" onsubmit="return canSub()">
  		用户名:<input type="text" name="username"/>
  		<input type="hidden" name="valinum" value="<%=valinum %>"/>
  		<input type="submit" value="注册"/>
  	</form>
  </body>



后台Servlet代码:

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		try {
			Thread.sleep(4*1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		

		String username = request.getParameter("username");
		String valinum = request.getParameter("valinum");
		String valinum2 = (String) request.getSession().getAttribute("valinum");
		if(valinum2!=null && !"".equals(valinum2) && valinum.equals(valinum2)){
			request.getSession().removeAttribute("valinum");
			System.out.println("向数据库中注册一次:"+username);
		}else{
			response.getWriter().write("from web:不要重复提交!!");
		}
	}



 

你可能感兴趣的:(防止表单重复提交,用户登陆注销)