web学习四——cookie&session

  1. cookie&session

6.1 会话

用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程成为会话

6.2 Cookie&Session

这里写图片描述
session和cookie的主要区别在于:
1.cookie是把用户的数据写给用户浏览器
2.session是把用户的数据写到用户独占的session中去(服务端)
session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
Session 与 cookie的对比:
Cookie : 由于 cookie是客户端浏览器, 所以 数据 不是很安全… 但是减轻了服务器的压力.
Session: 由于数据是存在 服务器端的, 所以 数据会 比较安全, 但是 加重了服务器的压力.

6.3 Cookie

Cookie

  • 1.一个cookie只能标识一种信息,至少含有一个标识该信息的名称和值
  • 2.一个web站点可以给一个浏览器发送多个cookie,一个浏览器可以存储多个web站点发送的cookie
  • 3.浏览器一般只允许存放300条cookie,每个站点至多存放20条cookie,每个cookie大小为4kb
  • 4.如果创建了一个cookie,发送至浏览器,默认它是会话级别的,当用户退出浏览器后被删除,若想永久的存储在磁盘上,需要设置maxAge,以秒为单位。
    注意:一个cookie 持久化保存到硬盘上之后, 实际上你也还是可以通知浏览器 删除 这个cookie 的, 就是将 setMaxAge设置为 0 , 设置 为0 , 就表示 不保存 cookie 信息了. 但是特别要注意, 删除 cookie的时候, 这个cookie名称和有效路径必须 一致 , 否则不会删除.

response接口中定义了一个addCookie()方法,用于在其响应头增加一个Set-Cookie头字段,同样request接口中定义了一个getCookies()方法,用于获取客户端提交的Cookie。

Cookie类的方法有:
Public Cookie(String name,String value)
setValue与getValue
setMaxAge与getMaxAge
setPath与getPath
getName

案例1:利用cookie,显示用户上次访问网站时间

//获得用户请求的时候,封装在request中的cookie信息		
		Cookie[] cookies=request.getCookies();
		response.setContentType("text/html;charset=UTF-8");
		//遍历这个cookie数组时,找到目标cookie对象,每个cookie都有一个唯一的名字标识一个cookie对象		
	    Cookie targetcookie=findTargetCookie(cookies,"lastvisit");
	    
	    if(targetcookie==null) {
	    	//没有目标cookie,说明是第一次访问
	    	response.getWriter().println("第一次访问网站!");
	    }else {
	    	//说明之前访问过
	    	String value=targetcookie.getValue();
	    	long time=Long.parseLong(value);
	    	response.getWriter().println("上次访问时间是:"+new Date(time).toLocaleString());
	    }
	    
	    //把当前时间写回Cookie
	    Cookie cookie=new Cookie("lastvisit",System.currentTimeMillis()+"");
	    
	    cookie.setPath("/");//这里“/”代表当前主机localhost	    
	    //http://www.baidu.com/123  这里/代表www.baidu.com
	    
	    cookie.setMaxAge(60*60*24*7);//从当前时间开始保存cookie一个周,以秒为单位
	    response.addCookie(cookie);//把cookie写回当前的浏览器
private Cookie findTargetCookie(Cookie[] cookies, String name) {
		// TODO Auto-generated method stub
		if(cookies==null) {
			//说明没有带任何的cookie过来,直接返回null
		return null;
		}
			//如果走到这里,说明带了cookie过来,遍历cookies数组,找到目标cookie对象
			for(Cookie cookie:cookies) {
				if(cookie.getName().equals(name)) {
					//说明当前的cookie就是目标cookie,返回cookie对象
					return cookie;
				}
			}
		return null;
	}

问题:
1.浏览器关闭之后再次打开去访问,发现 又变成了第一次访问了
注意: 默认的情况下, 一个cookie 的有效期是 浏览器进程, 那么在浏览器关闭之后,浏览器 进程没了, 那么相应的 cookie 信息也就没有。
如何 实现在浏览器关闭之后 ,再次打开,仍然可以 显示上次的访问时间呢?
可以自己手动的去设置 cookie 的有效期 就好了,设置 cookie 的有效期之后, 只要是在有效期内, 那么 cookie 就会一直 保留在浏览器的缓存中,以文件的形式存在.

cookie.setMaxAge(60*60*24*7);//从当前时间开始,保存cookie一个周,以秒为单位

2.如何给cookie设置有效路径?
如果给某个cookie 设置有效路径, 那么就表示 ,当 再次使用浏览器去访问某个 目标资源的时候,如果要访问的目标的路径与 cookie 所包含的有效路径不匹配, 那么 cookie 不会在访问的时候 带过去给 服务器, 如果匹配, 才会带过去.

//http://localhost:8080/day11/access
 cookie.setPath("/");//设置有效路径,这里“/”表示当前主机名localhost,那么就表示只有访问当前主机名localhost下的资源文件时,cookie才会带过去

一般开发过程中, 设置 成什么样 路径 最多 ?
setPath(“/”) , 写成 / 并不是最好的, 但是 却是 使用最多的. 的确是最简单的一种方式.

案例2:显示用户上次浏览过的商品

products.jsp

<%@page import="com.lln.cookie.util.CookieUtil"%>
<%@ 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>商品列表</h3>
智能时代<a href="/day11/showinfo?id=1">查看</a><br>
浪潮之巅<a href="/day11/showinfo?id=2">查看</a><br>
自制操作系统<a href="/day11/showinfo?id=3">查看</a><br>
Linux命令行与shell脚本编程大全<a href="/day11/showinfo?id=4">查看</a><br>
Linux私房菜-服务器架设篇<a href="/day11/showinfo?id=5">查看</a><br>
计算机算法基础<a href="/day11/showinfo?id=6">查看</a><br>
<hr>
<br>
<a href="/day11/clearrecords">清空浏览记录</a>
<br>
<br>
<%

Cookie[] cookies=request.getCookies();

Cookie targetcookie=CookieUtil.findTargetCookie(cookies, "history");
//
if(targetcookie==null){
	//没有任何浏览记录
	out.println("还没有浏览过商品。。。。。<a href='/day11/products.jsp'>去浏览</a>");
}else{
	//说明浏览过商品,取出商品,显示一下
	String value=targetcookie.getValue();
	String[] records=value.split("-");
	String[] booknames={"智能时代","浪潮之巅","自制操作系统","Linux命令行与shell脚本编程大全","Linux私房菜-服务器架设篇","计算机算法基础"};
	out.println("浏览过的商品有:"+"<br/>");
	for(String record:records){
		out.println("书名:"+booknames[Integer.parseInt(record)-1]+"<br>");
	}
}

%>
</body>
</html>

ShowInfo.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//获取查看的书的id
		String id = request.getParameter("id");
		//h获得带过来的cookie数组,查看有没有目标cookie
		Cookie[] cookies=request.getCookies();
		
		Cookie targetcookie=CookieUtil.findTargetCookie(cookies,"history");
		
		if(targetcookie==null) {
			//说明没有浏览记录,把当前书的id存入cookie
			Cookie cookie=new Cookie("history",id);
			cookie.setMaxAge(60*60*24);
			cookie.setPath("/");
			response.addCookie(cookie);
		}else {
			//说明之前有浏览记录
			//如果没有,就将此次的浏览id加进去,如果浏览过就什么也不做
			String value=targetcookie.getValue();
			String[] records=value.split("-");//1-2-5
			if(!checkExistId(records,id)) {
				//需要将当前的id拼接上去
				Cookie cookie=new Cookie("history",value+"-"+id);//1-2-5-4
				cookie.setMaxAge(60*60*24);
				cookie.setPath("/");
				response.addCookie(cookie);
			}
		}
		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().println("浏览商品成功。。。。<a href='/day11/products.jsp'>继续浏览</a>");
	
	}
	//判断是否包含当前点击的书的id
	private boolean checkExistId(String[] records, String id) {
		// TODO Auto-generated method stub
		for(String record:records) {
			if(record.equals(id)) {
				//如果进来则说明找到了当前点击的书
				return true;
			}
		}
		return false;
	}

CookieUtil.java

public class CookieUtil {
	public static Cookie findTargetCookie(Cookie[] cookies, String name) {
		// TODO Auto-generated method stub
		if(cookies==null) {
		return null;}
		
		for(Cookie cookie:cookies) {
			if(cookie.getName().equals(name)) {
				//如果进来则说明找到了cookie对象,返回
				return cookie;
			}
		}
		return null;
	}
}

案例3:清空浏览记录

ClearRecords.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		Cookie cookie=new Cookie("history","");//1-2-5-4
		cookie.setMaxAge(0);
		cookie.setPath("/");
		response.addCookie(cookie);
//		response.sendRedirect("/day11/products.jsp");
		response.sendRedirect(request.getContextPath()+"/products.jsp");
	}

6.4 Session

6.4.1 session原理

Session的实现原理是基于cookie的,是在访问服务器的时候给浏览器回写一个JSESSIONID的cookie,这个cookie的值是session的id号,那么这个浏览器收到了,在后续访问服务器的时候会带着这个cookie过去,从而服务器就解析出来了,解析到session的id后,通过这个id号找到了服务器端对应的session对象,从而取出数据为用户服务。
默认情况下,一个session对象创建后,就一直驻留在内存中,如果一个session对象连续半个小时没有被访问,那么就会被销毁。

6.4.2 session 实现数据共享

session1.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//实现session保存数据,实现数据共享
		//注意:session对象的创建不是你自己new出来的
		//内部原理是,你来访问的时候,如果没有为你的浏览器创建过对象,那么就会新创建,如果已创建过,那么就拿已创建的session对象为你服务
	HttpSession session=request.getSession();
	session.setAttribute("name", "张三");
	//回写同名的cookie
	//通过session.getId()获得具体的id号
	Cookie cookie=new Cookie("JESSIONID",session.getId());//1-2-5-4
	cookie.setMaxAge(60*60*24);
	cookie.setPath("/");
	response.addCookie(cookie);
	
	}

session2.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//获得session对象的引用
		HttpSession session=request.getSession();
		//获得session中保存的数据
		String name = (String) session.getAttribute("name");
		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().println("name:"+name);
	}

问题1:关闭浏览器后,再次直接去打开session2,看不到数据。
因为session是基于cookie的,默认情况下cookie有效期是浏览器进程,浏览器一关闭,cookie就没了,从而下次再打开的时候,就找不到服务器端的session对象。
如何实现在关闭浏览器之后仍然可以 找到之前的数据呢?
按照 同样的方式, 在 浏览器访问 服务器端的servlet的时候, 回写一个同名的cookie , 并且设置一个 有效期 … 这样cookie 就会持久化保存到硬盘上, 从而实现下次打开浏览器 仍然可以找到 之前的 数据.

	//回写同名的cookie
	//通过session.getId()获得具体的id号
	Cookie cookie=new Cookie("JESSIONID",session.getId());//1-2-5-4
	cookie.setMaxAge(60*60*24);
	cookie.setPath("/");
	response.addCookie(cookie);

问题2:如果浏览器禁用了cookie 会怎么样呢?
这里写图片描述

  • 那么禁用了cookie 之后, 还能服务器端 使用 session 保存的 用户的商品信息吗 ?

    肯定是找不到了, 因为 session 是基于cookie 的, cookie 禁用了, 所以 对应 的session的信息 也就没了 .

  • 浏览器禁用了cookie后,的确就找不到 服务器的session 对象了, 那 服务器端的session 对象还在吗 ?
    在的, session 对象的存在与否 与浏览器是否禁用 cookie 没有 任何的 关系.

  • 服务端的session ,它的生命 周期 又是怎样的呢?
    默认的情况下, 一个session 创建后 就一直 驻留在内存中, 如果一个session 对象 连续 半个小时没有被访问过, 那么就会被销毁…

实际上你是可以 自己去修改这个值的.
在tomcat服务器的conf目录下的web.xml(是被所有的web应用都共享的 ) 文件中 有配置
这里写图片描述
你可以 进入到自己的web工程下 web.xml 文件中更改
这里写图片描述
设置session的有效期有多种方式:
方式一: 在web.xml文件中配置
方式二: 使用代码 去 设置
这里写图片描述
要的是 秒
方式三: 手动的立马销毁session 对象
这里写图片描述

问题3:浏览器禁用cookie后,如何实现session的追踪(了解)?
可以使用url 重写 的方式去实现 … ,实际开发过程中,这个技术 没有人会去用.
这里写图片描述

案例一:使用Session完成简单的购物车功能

处理用户请求的购买的Servlet程序

  • 1.获得购买的商品的信息
  • 2.获得session中的购物车,判断购物车中是否有当前点击的商品
  • 有:将原有的数量取出来+1,再放进去
  • 没有:就将现有商品存进去,数量设置为1
  • 3.需要将购物车存到session中去
  • 4.给用户提示,添加商品到购物车成功
    清空购物车,将购物车中的商品给移除
  • 两种方式:
  • 1.由于购物车是存在session中的,可以手动的将session销毁
  • session.invalidate()
  • 2.将购物车从session中移除
  • session.removeAttribute(“cart”);
    product.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>出售商品如下:</h3>
智能时代<a href="/day11/buy?id=1">购买</a><br>
浪潮之巅<a href="/day11/buy?id=2">购买</a><br>
自制操作系统<a href="/day11/buy?id=3">购买</a><br>
Linux命令行与shell脚本编程大全<a href="/day11/buy?id=4">购买</a><br>
Linux私房菜-服务器架设篇<a href="/day11/buy?id=5">购买</a><br>
计算机算法基础<a href="/day11/buy?id=6">购买</a><br>
<hr>
<a href="/day11/cart.jsp">查看购物车</a>
<hr>
<br>
<a href="/day11/clearcart">清空购物车</a>
</body>
</html>

cart.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>
<a href="/day11/clearcart">清空购物车</a><br>
<%
    Map <String,Integer> cart=(Map<String, Integer>) request.getSession().getAttribute("cart");

	if(cart==null){
		//还没有购买过商品
		out.println("还没有购买过商品。。。。<a href='/day11/product.jsp'>去购买</a>");
	}else{
		//遍历购物车,取出商品
		Set<String> keys=cart.keySet();
		
		out.println("购买的商品有:");
		for(String key:keys){
			Integer count=cart.get(key);
			out.println("商品名称:"+key+"   数量:"+count);
		}
		
		
		
		
	}
%>
</body>
</html>

BuyServlet.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		String id=request.getParameter("id");
		String[] booknames={"智能时代","浪潮之巅","自制操作系统","Linux命令行与shell脚本编程大全","Linux私房菜-服务器架设篇","计算机算法基础"};
		//获得书名
		String bookname=booknames[Integer.parseInt(id)-1];
		//获得购物车
		Map <String,Integer> cart=(Map<String, Integer>) request.getSession().getAttribute("cart");
		
		if(cart==null) {
			//如果进来,说明之前没有购买过商品,则新建一个购物车出来
			cart=new HashMap<String,Integer>();
		}
		if(cart.containsKey(bookname)) {
			//则说明之前购买过这本书,获得原有数量+1,再进去
			Integer count=cart.get(bookname);
			cart.put(bookname, count+1);
		}else {
			//没有购买过,直接put进去
			cart.put(bookname, 1);
		}
		//需要将购物车存到session中去
		request.getSession().setAttribute("cart", cart);
		//给用户提示,添加商品到购物车成功
		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().println("添加商品到购物车成功。。。。<a href='/day11/product.jsp'>继续购买</a>");
		
	}

ClearCart.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
//		request.getSession().invalidate();
		request.getSession().removeAttribute("cart");
		//重定向回购物车页面
		response.sendRedirect(request.getContextPath()+"/cart.jsp");	
	}

案例二:利用Session实现一次性验证码用户登陆

login.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>
<script type="text/javascript">
function checkimage(){
	document.getElementById("myimage").src="/day11/checkimage?"+new Date().getTime();
}
</script>
</head>
<body>
<h3>登录页面</h3>
<font color="red" size="5">${message} </font>
<form action="/day11/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
验证码:<input type=" text" name="checkcode">
<img src="/day11/checkimage" style="cursor:pointer" onclick="checkimage();" id="myimage" ><br>
<input type="submit" value="登录">
</form>
</body>
</html>

CheckImage.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//首先需要在内存中构建一张图片出来
		BufferedImage bf=new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
		
		Graphics2D graphics=(Graphics2D) bf.getGraphics();
		
		Color color=new Color(203,232,225);
		
		//设置背景杨色
		graphics.setColor(color);
		graphics.fillRect(0, 0, WIDTH, HEIGHT);
		
		String base="ABCDEFGHIJKLMN";
		Random random=new Random();
		//状态机:如果之前设置过相应属性,下次没有调用相应API时,其状态不会发生改变
		graphics.setColor(Color.RED);
		graphics.setFont(new Font("楷体",Font.BOLD,18));
		
		int m=13;
		
		StringBuilder sb=new StringBuilder();
		for(int i=0;i<4;i++) {
			int index=random.nextInt(base.length());
			char charAt=base.charAt(index);
			
			//-30-------30
			int jiaodu=random.nextInt(60)-30;
			double theta=jiaodu*Math.PI/180;
			
			graphics.drawString(charAt+"", m, 15);
			graphics.rotate(theta, m, 15);
			sb.append(charAt);
			m+=20;
		}
		//将sb存到session域对象中去
		request.getSession().setAttribute("checkcode_session", sb.toString());
		System.out.println("checkcode_session:"+request.getSession().getAttribute("checkcode_session"));
		
		for(int i=0;i<4;i++) {
			int x1=random.nextInt(WIDTH);
			int y1=random.nextInt(HEIGHT);
			int x2=random.nextInt(WIDTH);
			int y2=random.nextInt(HEIGHT);
			graphics.drawLine(x1, y1, x2, y2);
		}		
		ImageIO.write(bf,"png",response.getOutputStream());	
	}

Login.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//解决乱码问题
		request.setCharacterEncoding("UTF-8");
		
		//获取用户名、密码、验证码
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		String checkcode = request.getParameter("checkcode");
		
		System.out.println("checkcode:"+checkcode);
		
		//校验验证码
		String checkcode_session=(String) request.getSession().getAttribute("checkcode_session");
		System.out.println("login:"+checkcode_session);
		
		if(checkcode==null||!checkcode.equalsIgnoreCase(checkcode_session)) {
			//如果进来,说明验证码不正确
			request.setAttribute("message", "对不起,您输入的验证码不正确。。。。");
			//请求转发到登录页面
			request.getRequestDispatcher("/login.jsp").forward(request, response);
			return ;
		}
		//如果走到这里说明验证码正确,
		//做用户名和密码的校验
		if("admin".equals(username)&&"admin".equals(password)) {
			//将登录的用户存到域对象中去
			request.getSession().setAttribute("loginUser", "admin");
			//说明用户名和密码正确,重定向到网站的首页
			response.sendRedirect(request.getContextPath()+"/index.jsp");
		}else {
			//说明用户名和密码不正确,请求转发到登录页面
			request.setAttribute("message", "对不起,您的用户名或密码不正确。。。。");
			request.getRequestDispatcher("/login.jsp").forward(request, response);
		}		
	}

猜你喜欢

转载自blog.csdn.net/lln_lln/article/details/80874155