Cookie & HttpSession(会话控制)总结

文章目录

  • 会话控制(Cookie & HTTPSession)
    • 一、Cookie
      • 1、cookie简介
      • 2、cookie运行原理
        • 2.1 白话解说
        • 2.2 运行原理
      • 3、cookie的使用
        • 3.1 cookie的创建&获取&修改
          • (1)创建
          • (2)获取
          • (3)修改
            • a、直接修改
            • b、覆盖式修改
          • (4)cookie键值设置问题(建议都用英文)
      • 4、cookie有效性
      • 5、cookie有效路径
      • 6、cookie用途
      • 7、cookie缺陷
    • 二、HttpSession
      • 1、概述
      • 2、session的工作原理
        • 2.1 白话解说
        • 2.2 工作原理
      • 3、session的使用
        • 3.1 源码
        • 3.2 源码图示
      • 4、session的有效性
      • 5、URL重写
      • 6、session的活化和钝化
      • 7、session应用

会话控制(Cookie & HTTPSession)

概念:

​ 客户端(浏览器)与服务器的会话。

使用原因:

​ 使用原HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分中两次请求是否由一个客户端发出。这样的设计严重阻碍的Web程序的设计。

一、Cookie

1、cookie简介

  • Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求。
  • Cookie实际上就是服务器保存在浏览器上的一段信息。如:用于区分不同用户
  • Cookie与浏览器一一对应。Cookie不能跨越不同浏览器使用。也就是说,使用新的浏览器需要重新创建cookie对象。

2、cookie运行原理

2.1 白话解说

商场购物流程:

小王第一次去商场购物,商场正在搞优惠活动,每次购买200元以上并且积攒满10次就能领取一个小型洗衣机。小王参加了这个优惠活动。商场给小王一个盖了章的卡片,小王每次来商场购物满足条件,就给盖一个章,盖够10个章就可以领取礼品。其中这个盖了章的卡片就相当于cookie,它用于区分不同的用户。

2.2 运行原理

(1)浏览器请求

(2)服务器创建一个Cookie对象,该Cookie对象会携带用户信息。服务器将该Cookie发送给浏览器。

(3)以后浏览器再次请求时,会携带Cookie对象。

(4)服务器会通过该Cookie对象,区分不同用户。

图示:

Cookie & HttpSession(会话控制)总结_第1张图片

3、cookie的使用

3.1 cookie的创建&获取&修改

(1)创建
protected void doGet(HttpServletRequest request, HttpServletResponse response){
		Cookie cookie  = new Cookie("xxj","23"); //创建cookie对象
		response.addCookie(cookie);		//服务器将Cookie对象发送给浏览器	
	}
(2)获取
  • Cookie[] cookies = request.getCookies();
  • cookie.getName()
  • cookie.getValue()
  • cookie.getPath()
  • cookie.getMaxAge()
  • cookie.getSecure();
  • cookie.getVersion();
  • cookie.getDomain();
  • cookie.getComment();
  • cookie.isHttpOnly();
protected void doGet(HttpServletRequest request, HttpServletResponse response){
  		//返回的是一个cookie数组
		Cookie[] cookies = request.getCookies();
		for (Cookie cookie : cookies) {
			String name = cookie.getName();  //得到cookie的名字
			String value = cookie.getValue();//得到cookie的值
		
          //用于获取指定的cookie
			/*if("xxj".equals(name)) {
				System.out.println("name:"+name+"value:"+value);
			}*/   
		}
		
	}
(3)修改
  • cookie.setName()
  • cookie.setValue()
  • cookie.setPath()
  • cookie.setMaxAge()
  • cookie.setSecure();
  • cookie.setVersion();
  • cookie.setDomain();
  • cookie.setComment();
  • cookie.setHttpOnly();
a、直接修改
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
		//2.遍历查询name为level的Cookie
		if("level".equals(cookie.getName())) {
			// 3.将该Cookie的value改为sss
			cookie.setValue("sss");
			response.addCookie(cookie);
		}
}
b、覆盖式修改
Cookie cookie = new Cookie("level", "sssss");
response.addCookie(cookie); 
(4)cookie键值设置问题(建议都用英文)
//Cookie的name不能为中文,value可以为中文,但要指定底层编码字符集,比较麻烦。
所以建议都用英文。
//URLEncoder.encode("钻石会员", "UTF-8");


//创建Cookie对象
Cookie cookie = new Cookie("level", "s");
Cookie cookie2 = new Cookie("level2", URLEncoder.encode("钻石会员", "UTF-8"));
//将cookie响应给浏览器
response.addCookie(cookie);
response.addCookie(cookie2);

a、将cookie的name设置为中文,出现的错误

Cookie & HttpSession(会话控制)总结_第2张图片

b、将cookie的value设置为中文不进行指定字符集出现的问题

Cookie & HttpSession(会话控制)总结_第3张图片

如果指定字符集,浏览器中也不会进向中文显示

Cookie & HttpSession(会话控制)总结_第4张图片

4、cookie有效性

* Cookie默认有效性:当前会话有效(与浏览器有关,浏览器关闭或换一个浏览器,Cookie失效。)
	* 持久化Cookie
	* cookie.setMaxAge(ss秒)
		ss>0:在ss秒后失效
		ss=0:立即失效
		ss<0:默认情况 
* 注意:一旦设置持久化Cookie,Cookie默认(就是自带的cookie)有效性就不起作用了。

5、cookie有效路径

* cookie默认有效路径为:当前项目(/项目命)
* 设置cookie的有效路径
	* cookie.setPath()
	* 注意:一般设置有效路径在当前项目下的某个路径。					    			        (cookie.setPath(request.getContextPath()+"/demopath");

6、cookie用途

  • 网上商城的购物车

  • 保持用户登录状态

  • 7天免登陆

如:7天免登陆|记住密码



用户名:
密码:
7天记住密码:
/**
	 * 7天记住密码
	 * 		思路:1. 点击登录
	 * 			2. 在Servlet中获取用户名&密码
	 * 			3. 判断复选框是否选中
	 * 				选中:
	 * 					* 分别将用户名&密码存放到Cookie中
	 * 					* 持久化Cookie7天
	 * 					* 将两个Cookie响应到浏览器端
	 * 				没选中
	 * 					* 无
	 * 			4. 在浏览器端,获取两个Cookie,并显示用户名&密码到指定位置。
	 */
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//取username&pwd值
		String username = request.getParameter("username");
		String pwd = request.getParameter("pwd");
		String ck = request.getParameter("ck");
		if(ck != null) {
			//选中
			// 分别将用户名&密码存放到Cookie中
			Cookie cookieUserName = new Cookie("username", username);
			Cookie cookiePwd = new Cookie("pwd", pwd);
			//持久化Cookie7天
			cookieUserName.setMaxAge(60*60*24*7);
			cookiePwd.setMaxAge(60*60*24*7);
			//将两个Cookie响应到浏览器端
			response.addCookie(cookieUserName);
			response.addCookie(cookiePwd);
		}
		
	}

7、cookie缺陷

  1. Cookie的value只能是String类型,不灵活。
  2. Cookie存放到客户端浏览器中,不安全。因为Cookie是以明文传送。
  3. Cookie过多,Cookie是为请求或响应报文发送,无形中增加了网络流量。
  4. 各个浏览器对Cookie有限制,使用上有局限

二、HttpSession

1、概述

  • 使用Cookie有一个非常大的局限,就是如果Cookie很多,则无形的增加了客户端与服务端的数据传输量。而且由于浏览器对Cookie数量的限制,注定我们不能再Cookie中保存过多的信息,于是Session出现。

  • Session的作用就是在服务器端保存一些用户的数据,然后传递给用户一个名字为JSESSIONID的Cookie,这个JESSIONID对应这个服务器中的一个Session对象,通过它就可以获取到保存用户信息的Session。

2、session的工作原理

2.1 白话解说

如:我们常见的办卡。

健身房的销售人员,先询问你是否在他们的健身房办过健身卡。如果办过卡就不在办。如果没有办过,就去他们健身房填写表格创建个人信息(相当于创建session的对象),之后会产生一个卡号,随之把健身卡给你(相当于cookie对象)。以后客户去健身房健需要拿着健身卡进健身房。这个健身卡就是区分不同的客户。

2.2 工作原理

/* 使用Session对象之前,先通过特殊Cookie的value查询Session的id,从而查询Session对象。
	* 如果查询到Session对象,就可以使用
	* 如果未找到Session对象,则进行以下步骤:
		* 创建Session对象,同时创建特殊的Cookie,该Cookie的name为固定值:JSESSIONID,
		  该Cookie的value为:session的id。
		* 服务器会将该Cookie对象,发送到浏览器端。
		* 以后浏览器再次请求时,会携带该Cookie对象。
		* 服务器通过Cookie的value,找到相应的Session,通过Session区分不同用户。*/

图示:
Cookie & HttpSession(会话控制)总结_第5张图片

3、session的使用

* 类型:HttpSession
* session创建&获取&修改
	* session由服务器创建。
	* 获取 
		* html->Servlet:request.getSession() //从服务器获取session
		* jsp:直接获取(session是jsp的内置对象) 
			* _jspxFactory->pageContext->getSession() -> this.session = ((HttpServletRequest) 				request).getSession();//直接获取的流程

session获取:

HttpSession session = request.getSession();
		//1. 持久化Cookie(name=JSESSIONID)
		Cookie[] cookies = request.getCookies();
		for (Cookie cookie : cookies) {
			//查询特殊的Cookie对象
          //遍历Cookie,通过JSESSIONID找到特殊的Cookie
			if("JSESSIONID".equals(cookie.getName())) {  
				//持久化
				cookie.setMaxAge(30);
//				cookie.setMaxAge(60*30+30);
				response.addCookie(cookie);
				break;
			}
		}

3.1 源码

_jspxFactory->pageContext->getSession() -> this.session = ((HttpServletRequest) request).getSession();

_jspxFactory:

类型:

javax.servlet.jsp.JspFactory

public abstract class JspFactory {

    private static volatile JspFactory deflt = null;
 	 。。。。。。
  	public abstract PageContext getPageContext(Servlet servlet,
            ServletRequest request, ServletResponse response,
            String errorPageURL, boolean needsSession, int buffer,
            boolean autoflush);
  	。。。。。。
}

pageContext

public abstract class PageContext 
    extends JspContext
{
	。。。。。。
	 public abstract HttpSession getSession();
	。。。。。。
}

getSession()

public class PageContextImpl extends PageContext {
	。。。。。。
	
	private transient HttpSession session;
	
	。。。。。。
	@Override
    public HttpSession getSession() {
        return session;
    }
}

this.session = ((HttpServletRequest) request).getSession()

private void _initialize(Servlet servlet, ServletRequest request,
            ServletResponse response, String errorPageURL,
            boolean needsSession, int bufferSize, boolean autoFlush) {
        this.servlet = servlet;
        this.config = servlet.getServletConfig();
        this.context = config.getServletContext();
        this.errorPageURL = errorPageURL;
        this.request = request;
        this.response = response;
       
        this.applicationContext = JspApplicationContextImpl.getInstance(context);
  
        if (request instanceof HttpServletRequest && needsSession)
          
          /*
          	这是我们拿到的session,最终的地方
          */
            this.session = ((HttpServletRequest) request).getSession();
  
  
  		
        if (needsSession && session == null)
            throw new IllegalStateException(
                    "Page needs a session and none is available");
        depth = -1;
        if (bufferSize == JspWriter.DEFAULT_BUFFER) {
            bufferSize = Constants.DEFAULT_BUFFER_SIZE;
        }
        if (this.baseOut == null) {
            this.baseOut = new JspWriterImpl(response, bufferSize, autoFlush);
        } else {
            this.baseOut.init(response, bufferSize, autoFlush);
        }
        this.out = baseOut;      
        setAttribute(OUT, this.out);
        setAttribute(REQUEST, request);
        setAttribute(RESPONSE, response);
        if (session != null)
            setAttribute(SESSION, session);
        setAttribute(PAGE, servlet);
        setAttribute(CONFIG, config);
        setAttribute(PAGECONTEXT, this);
        setAttribute(APPLICATION, context);
        isIncluded = request.getAttribute(
                RequestDispatcher.INCLUDE_SERVLET_PATH) != null;
    }

3.2 源码图示

Cookie & HttpSession(会话控制)总结_第6张图片

4、session的有效性

* Session默认有效性为:当前会话有效(与浏览器有关,浏览器关闭或换一个浏览器,Cookie失效。)
	* Session是会话级别,本质原因:因为Cookie是会话级别。
* 持久化Session
	1. 持久化特殊的Cookie(name:JSESSIONID) 
	2. 持久化Session
		* Session默认存活30分钟。
		* 设置session的timeout
			* <session-config>
				<session-timeout>5分钟</session-timeout>
			</session-config> 
         * 设置session的非活动时间
             * session.setMaxInactiveInterval(ss秒);
                   * tomcat7.0
                        * ss>0:设置session的非活动时间为ss。
                        * ss<=:设置session永不失效 
                   * tomcat6.0
                        * ss>0:设置session的非活动时间为ss。
                        * ss=0:设置session立即失效 
                        * ss<0:设置session永不失效 
	3. 设置session失效
		* session.invalidate(); //session域中的所有内容都失效。如果只是想让一个实效,必须进行单独								移除(session.removeAttribute(String str))

持久化session的两种方法:

  1. web.xml设置

    单位:分钟----->局限性高(如:不能表示30.5分钟)

Cookie & HttpSession(会话控制)总结_第7张图片

  1. session.setInactiveInterval()

    单位:秒

示例:

/**
	 * 持久化Session
	 * 		1. 持久化Cookie(name=JSESSIONID)
	 * 		2. 判断持久化时间
	 * 			时间<=30分钟:无需设置session的非活动时间(因为session默认存活30分钟)
	 * 			时间>30分钟
	 * 				1. web.xml设置
	 * 				2. session.setInactiveInterval()
	 *		30.5分钟
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		//1. 持久化Cookie(name=JSESSIONID)
		Cookie[] cookies = request.getCookies();
		for (Cookie cookie : cookies) {
			//查询特殊的Cookie对象
			if("JSESSIONID".equals(cookie.getName())) {
				//持久化
				cookie.setMaxAge(30);
//				cookie.setMaxAge(60*30+30);
				response.addCookie(cookie);
				break;
			}
		}
		//2. 持久化Session
		session.setMaxInactiveInterval(30);
//		session.setMaxInactiveInterval(60*30+30);
		
	}

5、URL重写

  • 在整个会话控制技术体系中,保持JSESSIONID的值主要通过Cookie实现。但Cookie在浏览器端可能会被禁用,所以我们还需要一些备用的技术手段,例如:URL重写。

  • URL重写其实就是将JSESSIONID的值以固定格式附着在URL地址后面,以实现保持JSESSIONID,进而保持会话状态。这个固定格式是:URL;jsessionid=xxxxxxxxx

  • 例如:

    targetServlet;jsessionid=F9C893D3E77E3E8329FF6BD9B7A09957
    
  • 实现方式:

    • response.encodeURL(String)
    • response.encodeRedirectURL(String)

    示例:

    //1.获取Session对象
    HttpSession session = request.getSession();
    
    //2.创建目标URL地址字符串
    String url = "targetServlet";
    
    //3.在目标URL地址字符串后面附加JSESSIONID的值
    url = response.encodeURL(url);
    
    //4.重定向到目标资源
    response.sendRedirect(url);
    

6、session的活化和钝化

* 钝化:session对象与session内的数据一同从内存序列化到硬盘的过程,称之为钝化。
	* 触发时机:关闭服务器时,触发钝化。 
* 活化:session对象与session内的数据一同从硬盘反序列化到内存的过程,称之为活化。
	* 触发时机:重启服务器时,触发活化。 

钝化和活化的数据存放的位置:

Cookie & HttpSession(会话控制)总结_第8张图片

注意:

如果session域中的 “对象” 没有进行序列化,在服务器重启之后是读不到数据的。就是不能够反序列化。

示例:

package com.atguigu.bean;
import java.io.Serializable;
public class Student implements Serializable {
	private static final long serialVersionUID = 1L;
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Student(String name) {
		super();
		this.name = name;
	}
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Student [name=" + name + "]";
	}
}


protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		//设置session的非活动时间
//		session.setMaxInactiveInterval(interval);
		//设置session立即失效
//		session.invalidate();
		//设置session中的studetn对的
		session.setAttribute("stu", new Student("zs"));  //就是student类需要进行序列化
		System.out.println("sessionId:"+session.getId());
	}


<body>
<h2>session</h2>
sessionId:<%=session.getId() %><br> 
<a href="GetSessionServlet">获取Session</a><br>
<a href="ChiSessionServlet">持久化Session</a><br>
student:${sessionScope.stu }
</body>

7、session应用

  • 表单的重复提交

  • 购物车的实现

  • 登录与登出

* 表单重复提交的条件
	1. 转发跳转页面,f5
	2. 网速慢,提交表单后,f5
	3. 提交表单后,单击回退按钮,再提交。
* 解决表单重复提交问题(让表单只提交一次)
	* 使用UUID作为token,解决表单重复提交问题。
	* UUID:是一个十六进制的32位的随机数,全球唯一。
	* String uuid = UUID.randomUUID().toString().replace("-", ""); 
* 步骤
	1. 生成一个UUID
	2. 将UUID分别存放到session域和隐藏域中。 
	3. 提交表单,分别从两个域中获取UUID
		* 判断是否相等
		* 相等:提交表单,将Session域中的UUID移除。
		* 不等:不提交表单

示例:




<% 
	//1. 生成一个UUID
	String uuid = UUID.randomUUID().toString().replace("-", "");
	//将UUID分别存放到session域和隐藏域中。
	session.setAttribute("uuid", uuid);
%>

解决表单重复提交

用户名:
密码:
7天记住密码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		/*
		 3. 提交表单,分别从两个域中获取UUID
			 * 判断是否相等
				* 相等:提交表单,将Session域中的UUID移除。
				* 不等:不提交表单
		 */
		HttpSession session = request.getSession();
		//获取session域中的uuid
		Object uuid = session.getAttribute("uuid");
		//获取隐藏域中uuid
		String uuid2 = request.getParameter("uuid2");
		//* 判断是否相等
  		//如果session域中的UUID被移除,则表单已经被提交。就不可能再满足条件。
		if(uuid != null && uuid.toString().equals(uuid2)) { 
			//相等:提交表单,将Session域中的UUID移除。
			System.out.println("提交表单");
			session.removeAttribute("uuid");
		}
		
		System.out.println("end");
	}

你可能感兴趣的:(Javaweb)