javaweb:会话管理和保存会话数据的两种技术(Cookie、Session)

版权声明: https://blog.csdn.net/weixin_42442713/article/details/84189439

会话:

什么是会话?

会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话

会话过程中要解决的一些问题?

每个用户与服务器进行交互的过程中,各自会有一些数据,程序要想办法保存每个用户的数据。

例如:用户点击超链接通过一个servlet购买了一个商品,程序应该保存用户购买的商品,以便于用户点结帐servlet时,结帐servlet可以得到用户商品为用户结帐。

保存会话数据的两种技术:

Cookie

Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。

Session

Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。

Cookie技术:

Cookie快速入门:

Cookie 是一个小的文本数据,由服务器端生成,发送给客户端浏览器,客户端浏览器如果设置为启用  Cookie,则会将这个小文本数据保存到某个目录下的文本文件内。

下次登录同一页面,浏览器则会自动将Cookie传回服务器端。

Cookie 值的形式:key-value

显示用户上次访问时间

判断用户是否是第一次访问

如果是第一次访问,需要输出欢迎,并且记录当前的时间,保存到cookie中,再回写到浏览器端。

如果不是第一次访问,获取cookie中的时间,输出时间,并且记录当前的时间,保存到cookie中,再回写到浏览器端。

                                                                                Cookie相当于一个证书

Cookie API:

ljavax.servlet.http.Cookie类用于创建一个Cookieresponse接口也中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。 同样,request接口中也定义了一个getCookies方法,它用于获取客户端提交的CookieCookie类的方法:

üpublic Cookie(String name,String value)

üsetValuegetValue方法

üsetMaxAgegetMaxAge方法

üsetPathgetPath方法

üsetDomaingetDomain方法

ügetName方法

Cookie细节:

l一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。

l一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie

l浏览器一般只允许存放300Cookie每个站点最多存放20Cookie每个Cookie的大小限制为4KB

l如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。

删除持久cookie,可以将cookie最大时效设为0注意,删除cookie时,path必须一致,否则不会删除

Cookie应用:

1.用户验证简略化。ID、密码作为cookie信息发送给用户,在以后的访问中可以获得到cookie,简化输入。

2.网上购物等应用。每将一个商品放入购物车,就会发送cookie给用户。

3.把握用户访问的时间。访问时,将时间作为cookie发送给用户,退出时将该cookie返回给web服务器,这样可以掌握访问该站点的时间长度。

4.推荐系统与搜索引擎。

•5编写商品信息列表,给每个商品起唯一的id值,通过id传值。

•6判断是否是第一次访问

•7如果是第一次访问,创建cookie,记录商品id,回写到浏览器

•8如果不是第一次访问,获取cookie中的商品信息,但是需要判断cookie中是否已经包含该商品,如果包含就不用处理,如果不包含,可以取出商品的id,累加操作。(可以编写一个判断是否包含的方法

•9重定向到商品列表页面,把商品循环到列表页面

•10清除浏览记录

显示上次浏览商品的实现过程:

Cookie 操作主要用到以下几个方法:

response.addCookie(Cookie c):将 Cookie 写入客户端

Cookie.setMaxAge(int second):设置 Cookie 有效时间

写入Cookie的过程:

步骤1:创建cookie对象。Cookie构造函数(名称、值),皆为字符串类型。

步骤2:设置有效时间。sexMaxAge(),单位为s(秒)。

步骤3:写入Http响应报文。通过response.addCookie完成。

Cookie 读取操作:

读取客户端 Cookie方法

Cookie[]  request.getCookies():读取客户端所有 Cookie,以数组形式返回。然后再遍历数组,根据名称找到所需的Cookie.

从客户端读取cookie:

步骤1:调用request.getCookies( )

步骤2:对数组进行循环,调用每个cookiegetName方法,直到找到感兴趣的cookie位置。

Cookie的安全性:

盗取的方法:

利用跨站脚本技术,将信息发给目标服务器;为了隐藏 URL,甚至可以结合 Ajax(异步 Javascript 和 XML 技术)在后台窃取 Cookie

通过某些软件,窃取硬盘下的  Cookie。一般说来,当用户访问完某站点后,Cookie文件会存在机器的某个文件夹下,因此可以通过某些盗取和分析软件来盗取  Cookie。

利用客户端脚本盗取 Cookie。在 Javascript 中有很多 API 可以读取客户端 Cookie,可以将这些代码隐藏在一个程序(如画图)中,很隐秘地得到 Cookie 的值

例子>显示用户访问时间:

创建MyCookieUtil类,在里面写一个判断cookieshu的方法:

package cn.itcast.utils;

import javax.servlet.http.Cookie;

/**
 * 操作cookie
 * @author Administrator
 *
 */
public class MyCookieUtil {
	
	/**
	 * 通过cookie的名称来获取指定的cookie,如果找到返回cookie,如果找不到,返回null
	 * @param cookies
	 * @param cookieName
	 * @return
	 */
	public static Cookie getCookieByName(Cookie [] cookies,String cookieName){
		// 如果cookies数组为空,返回null
		if(cookies == null){
			return null;
		}else{
			// 如果不为空,循环遍历,拿到每一个cookie,和cookieName去判断,如果匹配成功了,返回。
			for (Cookie cookie : cookies) {
				// 拿到每一个cookie,和cookieName去判断,如果匹配成功了,返回。
				// 获取cookie的名称
				if(cookie.getName().equals(cookieName)){
					// 匹配成功了
					return cookie;
				}
			}
			return null;
		}
	}

}











LasTimeServlet.java,在此类中调用MyCookieUtil类的getCookieByName方法:

package cn.itcast.cookie;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.itcast.utils.MyCookieUtil;

/**
 * 显示用户上次的访问时间
 * @author Administrator
 *
 */
public class LatTimeServlet extends HttpServlet {
	private static final long serialVersionUID = -6068764497514719951L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/**
		 * 1.先判断是否是第一次访问?因为:第一次访问和第n次处理的业务是不同的。
		 * 2.如果是第一次访问:先输出一句欢迎,记录当前的时间,保存到cookie中,回写到浏览器端。
		 * 3.如果不是第一次访问,获取cookie中的值(就是你上次的访问的时间),把时间输出到页面上。记录当前的时间,保存到cookie中。回写到浏览器端。
		 */
		
		// 设置字符中文乱码的问题
		response.setContentType("text/html;charset=UTF-8");
		
		// 先判断是否是第一次访问?先获取所有的cookie数组,查找咱们定义的cookie。
		// 如果找到咱们定义的cookie,说明不是第一次访问。如果没找到,那就是说明是第一次访问。
		// 获取cookie的数组
		Cookie [] cookies = request.getCookies();
		// 查找自己定义的cookie,查找指定名称的cookie。	(Cookie c = new Cookie("last","cookie的值"));
		Cookie cookie = MyCookieUtil.getCookieByName(cookies, "last");
		// 记录当前的时间
		Date date = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		// 当前的时间的字符串
		String sDate = sdf.format(date);
		// 如果cookie为null,说明是第一次访问
		if(cookie == null){
			// 我是第一次访问
			// 输出一句话
			response.getWriter().print("<h3>亲,带钱再来哦!!</h3>");
			// 记录当前的时间
			// 把当前的时间回保存cookie中
			Cookie c = new Cookie("last", sDate);
			
			// 设置有效时间
			c.setMaxAge(60*60);	// 1小时
			c.setPath("/day11"); // 有效路径就变成了/day11
			// 回写
			response.addCookie(c);
		}else{
			// 获取上次的访问时间(从cookie中获取)
			String lasttime = cookie.getValue();
			// 把上次的时间输出到页面上去
			response.getWriter().print("<h3>亲,您上次的访问时间是"+lasttime+",下次快点来哦!!</h3>");
			// 记录当前的时间
			cookie.setValue(sDate);
			
			// 设置有效时间
			cookie.setMaxAge(60*60);	// 1小时
			cookie.setPath("/day11"); // 有效路径就变成了/day11
			
			// 回写
			response.addCookie(cookie);
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}

例子:商品的浏览记录:

前台程序:

productList.jsp

<%@page import="cn.itcast.utils.MyCookieUtil"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>商品的列表页面</title>

<style type="text/css">
	.img1{
		width: 160px;
		height: 140px;
	}
	.img2{
		width: 80px;
		height: 70px;
	}

</style>

</head>
<body>

	<img class="img1" src="/day11/img/1.jpg"><a href="/day11/product?id=1">手电筒</a>
	<img class="img1" src="/day11/img/2.jpg"><a href="/day11/product?id=2">电话</a>
	<img class="img1" src="/day11/img/3.jpg"><a href="/day11/product?id=3">电视</a>
	<br/>
	<img class="img1" src="/day11/img/4.jpg"><a href="/day11/product?id=4">冰箱</a>
	<img class="img1" src="/day11/img/5.jpg"><a href="/day11/product?id=5">手表</a>
	<img class="img1" src="/day11/img/6.jpg"><a href="/day11/product?id=6">电脑</a>
	
	<h3>商品的浏览器记录</h3>
	<h4><a href="/day11/removeProduct">清除浏览记录</a></h4>
	
<%
	// 获取到cookie的内容 可以把cookie的内容动态的显示到页面上
	Cookie [] cookies = request.getCookies();
	// 通过指定名称来获取cookie
	Cookie cookie = MyCookieUtil.getCookieByName(cookies, "product");
	// 判断cookie不为空
	if(cookie != null){
		// 获取cookie的值
		String longid = cookie.getValue();		// product=1,2,3
		// 切割
		String [] ids = longid.split(",");
		// 循环遍历
		for(String id : ids){
%>
		<img class="img2" src="/day11/img/<%= id %>.jpg">++++"/day11/img/<%= id %>.jpg"
<%			
			
		}
	}
%>	
	
</body>
</html>






后台程序:

ProdcutServlet.java 

package cn.itcast.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;

import cn.itcast.utils.MyCookieUtil;

/**
 * 商品浏览记录的后台
 * @author Administrator
 *
 */
public class ProductServlet extends HttpServlet {
	private static final long serialVersionUID = -5747737695587699577L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/**
		 * 0.获取传过来id值
		 * 1.判断是否是第一次访问?(获取指定名称的cookie如果为null,说明是第一次访问)
		 * 		* 如果是第一次访问,把商品的id保存到cookie中,回写cookie。
		 * 		* 如果不是第一次访问
		 * 			* 先获取cookie中的内容,进行判断(判断cookie中是否包含当前点击的商品)
		 * 				* 如果cookie中已经包含了该商品,那么就不用处理了
		 * 				* 如果不包含,在cookie中追加该商品	product=1	product=1,2
		 * 2.重定向商品的列表页面
		 * 3.需要在商品的列表页面中获取cookie的中内容,把内容显示到页面上。
		 */
		// 先获取商品的id
		String id = request.getParameter("id");
		// 获取cookie的数组
		Cookie [] cookies = request.getCookies();
		// 查找指定名称的cookie
		Cookie cookie = MyCookieUtil.getCookieByName(cookies, "product");
		// 如果cookie为null,说明是第一次访问,把商品的id保存到cookie中,回写
		if(cookie == null){
			// 是第一次
			Cookie c = new Cookie("product",id);
			
			// 设置有效时间
			c.setMaxAge(60*60*24);
			
			// 设置有效的路径
			c.setPath("/day11");
			
			// 回写
			response.addCookie(c);
		}else{
			// 说明cookie不为空
			// 先获取cookie的内容(拿出来做判断),cookie有可能包含当前的商品
			String longid = cookie.getValue();		// product=1,2,3		假如说当前点击的是4	product=4,1,2,3
			// 判断字符串ids是否包含当前的id
			// 把ids字符串切割成数组
			String [] ids = longid.split(",");
			if(!checkId(ids,id)){
				// 说明不包含该商品
				cookie.setValue(id+","+longid);
				
				cookie.setMaxAge(60*60*24);
				
				// 设置有效的路径
				cookie.setPath("/day11");
				
				// 回写cookie
				response.addCookie(cookie);
			}
		}
		// 重定向或者转发(使用request域存储内容,必须是转发)request.getContextPath()获取虚拟路径,默认和项目名称相同
		response.sendRedirect(request.getContextPath()+"/cookie/productList.jsp");
	}
	
	/**
	 * 判断ids的数组中是否包含id的值
	 * @param ids
	 * @param id
	 * @return
	 */
	private boolean checkId(String[] ids, String id) {
		for (String s : ids) {
			// 获取s和id匹配
			if(s.equals(id)){
				// 包含
				return true;
			}
		}
		// 不包含
		return false;
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}





session:

lWEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。

lSessionCookie的主要区别在于:

Cookie是把用户的数据写给用户的浏览器。

Session技术把用户的数据写到用户独占的session中(服务器端)。

lSession对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。

session为每个浏览器保存数据:

session实现原理:

session案例:

l使用Session完成简单的购物车功能

接收传过来的商品id

使用Map集合代码购物车(key商品名称,value商品数量)

session中获取购物车

如果获取不到,是第一次,创建Map,存入商品和数量

如果获取到,不是第一次,拿到Map,判断Map中是否包含商品,如果包含取出数量+1,如果不存在,直接存入。

把购物车存入到session

前台:

cartlist.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h3>手电筒<a href="/day11/cart?id=1">加入购物车</a></h3>
	<h3>电视<a href="/day11/cart?id=2">加入购物车</a></h3>
	<h3>冰箱<a href="/day11/cart?id=3">加入购物车</a></h3>
	<h3>洗衣机<a href="/day11/cart?id=4">加入购物车</a></h3>
	<h3>电话<a href="/day11/cart?id=5">加入购物车</a></h3>
	<h3>电脑<a href="/day11/cart?id=6">加入购物车</a></h3>

</body>
</html>

后台程序:

Carservlet.java:

package cn.itcast.session;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 购物车的后台
 * @author Administrator
 *
 */
public class CartServlet extends HttpServlet {
	private static final long serialVersionUID = -4944571720622706932L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/**
		 * 0.Map<String,Integer> cart 车里面放商品的名称和数量。
		 * 1.接收参数,接收的id值。把id值转换成相应的商品。
		 * 2.判断是否是第一次购买(从session中获取车,如果车是null,肯定是第一次购买)
		 * 		* 如果是一次购买,创建一个购物车,把该商品和数量存入到车中,再把车存入到session中。
		 * 		* 如果不是第一次购买
		 * 			* 先判断车中是否包含该商品,因为如果包含该商品了,数量+1
		 * 			* 如果不包含该商品,直接把该商品存入车中。
		 * 3.转发或者重定向到继续购物或者结算页面
		 * 4.去结算的页面(把商品的名称和数量显示到页面上)
		 */
		// 先获取请求的参数
		String id = request.getParameter("id");
		// 想id转换成响应的商品名称
		String [] names = new String []{"手电筒","电视","冰箱","洗衣机","电话","电脑"};
		// 转换成int类想
		int index = Integer.parseInt(id);
		// 当前的商品名称
		String productName = names[index - 1];
		// 先获取session
		HttpSession session = request.getSession();
		// 从session来获取车
		Map<String, Integer> cart = (Map<String, Integer>)session.getAttribute("cart");
		// 如果cart是null
		if(cart == null){
			// 第一次
			// 把购买的商品存入到车中
			cart = new HashMap<String, Integer>();
			// 把商品放入车中
			cart.put(productName, 1);
			// 把车放入session中
			session.setAttribute("cart", cart);
		}else{
			// 先获取车中的内容,和当前购买的商品进行判断
			if(cart.containsKey(productName)){
				// 先获取商品的数量
				Integer count = cart.get(productName);
				// 数量+1  
				count++;
				// 在把商品存入车中
				cart.put(productName, count);
				// 存入到session中
				session.setAttribute("cart", cart);
			}else{
				// 直接存入到车中
				cart.put(productName, 1);
				// 存入到session中
				session.setAttribute("cart", cart);
			}
		}
		
			
	
		// 重定向到继续购物或者去结算的页面
		response.sendRedirect(request.getContextPath()+"/session/gopay.jsp");
		
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}

继续购物:

gopay.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h3><a href="/day11/session/cartlist.jsp">继续购物</a>|<a href="/day11/session/pay.jsp">去结算</a></h3>

</body>
</html>

 付款:

pay.jsp:

<%@page import="java.util.Set"%>
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h4>商品的信息</h4>

<%
	// 获取车
	Map<String,Integer> cart = (Map<String,Integer>)request.getSession().getAttribute("cart");
	// 购物车不为空
	if(cart != null){
		// 获取车的商品名称和数量
		Set<String> names = cart.keySet();
		// 循环set集合,商品的名称
		for(String name : names){
			
%>
		<h3>亲,您购买了<%= name %>,数量是<%= cart.get(name) %></h3>
<%			
			
		}
	}else{
		
%>
		<h3>亲,您还没有<a href="/day11/session/cartlist.jsp">败家</a>,请您快去败家</h3>
<%		
		
	}
	
%>

</body>
</html>

浏览器禁用Cookie后的session处理:

实验演示禁用Cookieservlet共享数据导致的问题。

l解决方案:URL重写

response. encodeRedirectURL(java.lang.String url)

用于对sendRedirect方法后的url地址进行重写。

response. encodeURL(java.lang.String url)

用于对表单action和超链接的url地址进行重写

session创建和销毁:

session的创建

服务器启动,第一次访问调用getSession()方法时,创建session

Session的销毁

服务器非正常关闭(正常关闭不会销毁,会序列化到work目录)

Session过期

调用sessioninvalidate()方法销毁

session案例:

l利用Session实现一次性验证码用户登陆

在生成的验证码的servlet中使用session存入生成的验证码(使用StringBuffer拼接字符)

在校验的servlet中获取表单输入的验证码和session中保存的验证码

获取到两个不同来源的验证码后做对比

session案例一次性校验码:

l一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码。

l服务器程序接收到表单数据后,首先判断用户是否填写了正确的验证码,只有该验证码与服务器端保存的验证码匹配时,服务器程序才开始正常的表单处理流程。

l密码猜测工具要逐一尝试每个密码的前题条件是先输入正确的验证码,而验证码是一次性有效的,这样基本上就阻断了密码猜测工具的自动地处理过程

Servlet的数据访问范围:

lapplication Scope  servletContext (数据库连接池,配置, 线程池, 站点访问次数)

每一个Web应用对应一个ServletContext

存放所有用户都可以访问的数据

lsession Scope HttpSession (存放与用户相关数据)

存放每个用户自己会话过程中的数据

lrequest Scope  HttpServletRequest

l(Servlet处理结果,JSP显示

数据存放在request对象中

生成新的请求时,原request存放数据丢失

Cookie 和 Session 的比较:

Cookie是存放在客户端的。Session对象是存放在服务器端,但通常需要借助Cookie来存放个JSESSIONID号。

Cookie只能存放文本信息,而且大小受限。Session对象中可以存放任何类型信息

Cookie可以长时间保存在客户端。Session对象在浏览器关闭后就失效了Session数据存放在服务器内存。

 

猜你喜欢

转载自blog.csdn.net/weixin_42442713/article/details/84189439