JavaWeb——会话追踪之Cookie和Session

文章目录

  • 会话技术
  • Cookie
    • Cookie的基本操作
    • 中文Cookie
    • Cookie的特点
  • HttpSession
    • Session的实现机制
    • Session常见方法
    • 开发中的应用
    • Cookie被禁用后实现会话跟踪

会话技术

客户端和服务器通信的过程中,自然而然的会产生一些数据交互。比如,A用户登录了邮箱,那么web服务器该怎么知道C一段时间后的登录状态呢?虽然HttpServletRequest对象和ServletContext对象都可以保存数据,但是不适用于这种情况。

  • 客户端的每次请求,服务器都会产生一个HttpServletRequest对象,该对象只保存请求所传递的数据。
  • 用一个WEB应用共享一个ServletContext对象,所以当多个用户登录时就有可能会造成数据混淆。

JavaWeb——会话追踪之Cookie和Session_第1张图片
如上图:当浏览器向ServletB发出请求时,它的登陆操作已经完成了,但是却没有留下任何依据能够证明它已经成功登陆。以至于ServletB对他的登陆状态无法判别,这种情况叫用户状态的丢失。造成这种结果的原因是http协议的无状态
为了解决这个问题,Servlet提供了会话跟踪技术来追踪用户状态,简单的说就是指将用户操作过的重要业务步骤记录下来,以便在后续的处理中使用
会话跟踪技术有2种:
1、Cookie
2、Session

Cookie

Cookie是一种会话技术,它用于将会话过程中的数据保存在用户的浏览器中,从而使得浏览器和服务器更好的交互。当服务器向客户端发送Cookie时,会在HTTP响应头字段增加Set-Cookie字段,该字段设置的Cookie遵循一定的规则,以键值对的形式保存,Cookie属性值可以有多个,但是这些属性之间必须以分号和空格分隔。比如:

Set-Cookie:"status='1'; time='2019-04-03 19:05:49'; version=2.5"

那么Cookie是怎么解决我们上面提到的问题的呢?
比如Bob现在登录邮箱,浏览器就会向服务器发送登录的请求,AServlet来处理这个登录请求,验证用户名和密码无误后,就会把Cookie代表登录的键值对发送给浏览器并保存起来。这样,在Cookie的有效期内(默认是会话结束时,即浏览器关闭),如果服务器想要判断Bob是否还在登录状态,只需要从浏览器这里拿到相应的Cookie就可以了。

Cookie的基本操作

现在我们来演示一下Cookie的基本操作:

  1. 设置Cookie
package com.xx.cookie;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class CookieTestServlet
 */
public class CookieTestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public CookieTestServlet() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 1.创建Cookie,默认有效期(存活时间)是浏览器会话结束时失效
		Cookie cookie = new Cookie("status", "online");
		// 2.我们也可以手动设置有效期,以秒为单位
		cookie.setMaxAge(100);
			// setMaxAge的特殊值:
				// -1 :会话Cookie,浏览器关闭时自动删除
				// 0 : 表示要删除一个cookie
		// 3.将cookie对象添加到response
		response.addCookie(cookie);
		// 给个cookie创建成功的提示
		response.getWriter().println("cookie create success");

	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

在浏览器中访问这个Servlet:
JavaWeb——会话追踪之Cookie和Session_第2张图片
Cookie设置成功后,我们就可以在浏览器中找到这个Cookie:
JavaWeb——会话追踪之Cookie和Session_第3张图片
现在我们来演示怎么得到Cookie:

package com.xx.cookie;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class GetCookieServlet
 */
public class GetCookieServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public GetCookieServlet() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 获取cookie
		Cookie[] cookies = request.getCookies();
		// 遍历cookie
		for (Cookie cookie : cookies) {
			response.getWriter().println(
			cookie.getName() + "=" + cookie.getValue());
		}
		//说明:每个cookie对象都有很多属性,我们都可以通过get方法拿到:
		//比如说getMaxAge(存活时间),getVersion(版本),getPath(路径)等
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

中文Cookie

有时候开发需要,我们需要设置name为中文或者value为中文的Cookie,怎么实现?
这里我们需要用到java.net.URLEncoder.encoder()java.net.URLDecoder.decode()方法:

  • 添加
// 设置中文Cookie,指定用utf-8编码
String cookieName = URLEncoder.encode("姓名", "utf-8");
String cookieValue = URLEncoder.encode("张三", "utf-8");
Cookie chineseCookie = new Cookie(cookieName, cookieValue);
response.addCookie(chineseCookie);
  • 获取
// 处理响应乱码
response.setContentType("text/html;charset=utf-8");
// 获取cookie
Cookie[] cookies = request.getCookies();
// 遍历cookie
for (Cookie cookie : cookies) {
	String name = URLDecoder.decode(cookie.getName());
	String value = URLDecoder.decode(cookie.getValue());
	response.getWriter().println(name + "=" + value);
}

Cookie的特点

  • 优点
  1. 采用字符串的形式存储数据,简单灵活
  2. 存储在用户的浏览器上,减少对服务器的压力
  • 缺点
  1. 对于重要数据而言,存储在浏览器上不够安全
  2. 无法存储格式复杂的数据格式,如对象,集合等

HttpSession

HttpSession是tomcat在服务器端为每个浏览器准备的私人储物箱,每个浏览器在tomcat里都有一个属于自己的HttpSession对象,用于存储私人数据

JavaWeb——会话追踪之Cookie和Session_第4张图片
在Servlet中可以通过request.getSession(true)方法来获得session对象,这个方法总是返回与发送请求的浏览器对应的session对象。
我们来测试一下:

package com.xx.session;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class TestSessionServlet
 */
public class TestSessionServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public TestSessionServlet() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 获取session对象,如果没有,就创建一个
		HttpSession session = request.getSession(true);
		// 获取session的id
		response.getWriter().println(session.getId());
		// 判断session是新的还是旧的
		response.getWriter().println(session.isNew());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

  • 第一次运行:
    JavaWeb——会话追踪之Cookie和Session_第5张图片
  • 第二次运行:
    JavaWeb——会话追踪之Cookie和Session_第6张图片

通过上面的例子我们可以发现,尽管所有的请求都会调用getSession方法,但是每个浏览器都有一个属于自己的session对象,并且只在第1次请求时,创建新对象。
总结Session的特点:
1、session 和 client浏览器一一对应(IE/Chrome/FF/…)
2、Session 的有效范围 比 request 大(1个Session对应同一client的多次请求)

Session的实现机制

Tomcat会为每个拥有session的浏览器设置一个特别的Cookie存储在浏览器中,称作会话Cookie。会话Cookie的名字固定叫做“JSESSIONID”, Cookie的值就是该浏览器对应的session ID号,其生命周期为-1(30分钟)。
当调用getSession(true)时,他首先检查用户的会话Cookie是否存在
如果不存在:为其创建新的session对象,将session对象的ID保存到新建的会话Cookie中,并将会话cookie送回浏览器 。
如果存在:则按照会话Cookie 的值找到对应的session对象返回。
这是我们运行上面的代码在浏览器Cookie中找到的会话Cookie:
JavaWeb——会话追踪之Cookie和Session_第7张图片

Session常见方法

package com.xx.session;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class GetSessionServelt
 */
public class GetSessionServelt extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public GetSessionServelt() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// HttpSession getSession()
		// 返回关于该请求的当前会话。或者若该请求没有会话则就创建一个。
		// HttpSession getSession(boolean create)
		// 返回有关本请求的当前HttpSession,或者若该请求没有会话,且“创建”属性为真,则就创建一个。
		// 1、拿到session对象
		HttpSession session = request.getSession(true);
		// 2.获取session的id
		String id = session.getId();
		response.getWriter().println("session_id:" + id);
		// 3.判断session的新旧
		boolean isNew = session.isNew();
		response.getWriter().println("isNew:" + isNew);
		// 4.获取会话创建的时间
		long time = session.getCreationTime();
		response.getWriter().println("createtime=" + time);
		// 5.设置最大有效时间,以秒为单位
		session.setMaxInactiveInterval(200);
		// 6.session失效
		// session.invalidate();
		// 7.浏览器最后一次请求的时间
		long lastAccessedTime = session.getLastAccessedTime();
		response.getWriter().println("lastAccessedTime=" + lastAccessedTime);
		// 8.session也是域对象
		session.setAttribute("name", "aSession");
		String name = (String) session.getAttribute("name");
		session.removeAttribute("name");
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

开发中的应用

1、显示当前登录用户信息
思路:登录成功后,将登陆信息 存储到用户的session对象中
步骤1:LoginAction中的成功分支中(跳转前),往session中存数据:

// 往session中,设置命名属性
HttpSession session = request.getSession(true);
session.setAttribute("LoginUser", user);

步骤2:在需要显示当前用户信息的界面中,从session中取数据

// 从session中,获取命名属性
HttpSession session = request.getSession(true);
Object obj = session.getAttribute("LoginUser");
User u = (User)obj;
out.println("当前用户:"+u.getUsername()+" 退出
"
);

注意:显示当前登录用户信息的代码,可以提取成公共页面,然后使用include包含。

2、强制用户登录
思路:获取并判断session对象中是否存储了用户的登陆信息,如果保存了则说明该用户已经登陆过;否则:说明该用户没有登陆,就强制回到登录页面。
在需要强制登录控制的代码的最上方添加:

// 获取session中的命名属性
HttpSession session = reqeust.getSession(true);
Object obj = session.getAttribute("LoginUser");
// 判断是否登录
if (obj == null){
	response.sendRedirect("/xxx/login.html");
	return;
}

3、安全退出
思路:删除session中存储的用户登陆信息,并且让session失效。

// 从session中,移除命名属性
HttpSession session = request.getSession(true);
session.removeAttribute("LoginUser");
// 让session失效
session.invalidate();
// 跳转到login
response.sendRedirect("/xxx/login.html");

Cookie被禁用后实现会话跟踪

在Chrome中禁止使用Cookie:
JavaWeb——会话追踪之Cookie和Session_第8张图片
如果client的Cookie被禁用,则每次请求server,都会重新创建新的session对象
怎么解决:

// 获取session
HttpSession session =  request.getSession();
response.getWriter().println(session.getId()+"\t"+session.isNew());
// NoCookieSetSessionServlet是你服务端响应请求的servlet的类名
String url = "NoCookieSetSessionServlet";
// 对url进行重写
String encodeURL = response.encodeURL(url);
// encodeURL方法作用:对原URL进行编码,检查client的cookie是否被禁用,如果被禁则自动在原URL后,添加“;jsessionid=xxxxxx”,实现会话。
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("RequestSessionServlet");

你可能感兴趣的:(JavaWeb)