会话技术

HTTP协议的特点:

  1. 应答式,必须先有请求才有响应.
  2. 明文传输.不安全.
  3. 无状态.服务器不会记录客户端的访问信息.

Web技术基于第三点,也提出解决方案

Cookie

​ 服务器在第一次客户端访问时,给客户端一个凭证,每次客户端访问时,将这个凭证带过来.这样服务器就可以识别.如果该凭证有效,则继续使用,否则服务器会给一个新的凭证.这个凭证由浏览器保存.保存在客户端.这时容易出现数据安全问题.由于这个信息存储在客户端上,更换浏览器就会丢失.更换了终端也会丢失.在实际开发中,Cookie的使用越来越少了.

​ Cookie可以用于:访问历史记录,购物车,记住密码。

Cookie的使用

cookie是服务器给客户端

​ 1.服务器创建Cookie

​ 2.在响应中,设置Cookie

​ 3.返回给客户端

package com.sxt.controller;

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;

public class CookieServlet extends HttpServlet {
	
	private static final long serialVersionUID = -5312491120640167631L;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 创建Cookie
		Cookie cookie  = new Cookie("cookieName", "cookieValue");
		// 设置cookie的存活时间    默认一次浏览器的退出,可以通过设置存活时间进行持久化  单位是 秒
		cookie.setMaxAge(60*3);
		// 获取cookie的存活时间
		cookie.getMaxAge();
		// 获取cookie的名称
		cookie.getName();
		// 获取cookie的值
		cookie.getValue(); 
		// 设置生效的资源路径  cookie默认是对当前整个项目有效
		//cookie.setPath(uri);
		// 设置只能HTTP协议进行读取.设置true 只能HTTP协议操作Cookie 客户端无法进行操作
		//cookie.setHttpOnly(true);
		// 设置cookie的访问域名
		//cookie.setDomain(pattern);
		Cookie cookie1  = new Cookie("cookieName1", "cookieValue1");
		Cookie cookie2  = new Cookie("cookieName2", "cookieValue2");
		Cookie cookie3  = new Cookie("cookieName3", "cookieValue3");
		// 设置cookie
		resp.addCookie(cookie);
		resp.addCookie(cookie1);
		resp.addCookie(cookie2);
		resp.addCookie(cookie3);
		req.getSession();
	}
}

Cookie案例:记住密码

package com.sxt.controller;

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;

public class LoginController extends HttpServlet {

	private static final long serialVersionUID = 8806988355645425860L;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String userName = req.getParameter("userName");
		String password = req.getParameter("password");
		String rember = req.getParameter("rember");
		// 记住密码
		if("1".equals(rember)) {
			Cookie userNameCookie = new Cookie("userName", userName);
			userNameCookie.setMaxAge(60*60*24*3);
			Cookie passwordCookie = new Cookie("password", password);
			passwordCookie.setMaxAge(60*60*24*3);
			resp.addCookie(userNameCookie);
			resp.addCookie(passwordCookie);
		}else {
			// 不记住密码 删除Cookie
			Cookie[] cookies = req.getCookies();
			if(cookies != null) {
				for (Cookie cookie : cookies) {
					String name = cookie.getName();
					if(name.equals("userName")) {
						// Cookie 设置为0  删除Cookie
						cookie.setMaxAge(0);
						resp.addCookie(cookie);
					}
					if(name.equals("password")) {
						cookie.setMaxAge(0);
						resp.addCookie(cookie);
					}
				}
			}
		}
	}

}
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<form action="login.do" >
	<p>
		用户名:<input type="text" name="userName" value="${cookie.userName.value}" />
	</p>
	<p>
		密码:<input type="text" name="password" value="${cookie.password.value}" />
	</p>
	<p>
		记住密码:<input type="checkbox" name="rember" value="1" />
	</p>
	<input type="submit" value="提交" />
</form>

</body>
</html>

Session:表示一次会话

Session存储在服务器.Session存储任意数据.并且Session是依赖Cookie的.服务器会给浏览器一个Cookie信息,JSESSIONID是Session的ID,浏览器每次请求会将这个信息带到服务器,从而换取Session.

Session和Coolie的关系

​ session的本质,是存储在服务器内存中的一个对象。根据Cookie中JSESSIONID的值查找。

注意: 在JSP页面中,默认会创建Session。但是在Servlet中,需要手动的创建。

​ 根据不同的JSESSIONID,会从服务器获取不同的Session对象。所以,不同客户端其使用的Session是不一样的。若JSESSIONID不一样,那么其获取的Session也不一样。

示例

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	// req.getSession() : 获取与当前请求相关的session对象  若没有则创建一个
	// 获取了一个session
	HttpSession session = req.getSession();
	session.setAttribute("keyName", "value");
	/*
	由于服务器获取session 是根据cookie中 JSESSIONID的值  获取。但是Cookie默认是存在客户端的内存中,一旦客户端关闭
	Cookie 会消失。则找不到之前的SESSION了
	创建一个Cookie  且这个Cookie设置生命周期,让客户端将这个Cookie进行持久化。然后将SESSION的ID值存在这个COOKIE中
	关闭浏览器。再次打开浏览器  进行访问。此时会自动将COOKIE带给服务器。而COOKIE中有JESSIONID,若找到了。*/
	System.out.println("session地址:"+session);
	//获取SESSION的ID
	String id = session.getId();
	Cookie cookie = new Cookie("JSESSIONID",id);
	cookie.setMaxAge(60*60);
	resp.addCookie(cookie);
	resp.getWriter().print("Hello ");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	// req.getSession() : 获取与当前请求相关的session对象  若没有则创建一个
	//获取了一个session
	HttpSession session = req.getSession();
	System.out.println(session.getAttribute("keyName").toString());
	System.out.println("session地址:"+session);
	resp.getWriter().print("Hello ");
}

Session的应用场景

​ 当前用户,即用户登录后将用户信息放入session中,然后以后取的时候,直接从session中取.

​ 验证码,将验证码放入session,用户输入的验证,与session验证码进行对比.一致,则通过.

Session的局限性

​ 由于Session是存储在服务器内存中,若服务器是多个节点的,则session无法共享.session失效了.在生产场景中,若是多台服务器,一般使用中间件存储session.

如何使用Session

  1. 创建Session

    req.getSession();		//若当前不存在session  则创建新的session  否则返回当前session
    req.getSession(true);	//若当前不存在session  则创建新的session  否则返回当前session
    req.getSession(false);	//若当前存在session 	  则返回当前session  否则返回null
    
  2. 设置session的有效期

    session.setMaxInactiveInterval(interval); //设置session的有效期(单位是秒),若不大于0 则表示永久有效
    
  3. 设置session失效

    invalidate();	// 不让任何对象绑定这个session. 则request 找不到这个session.
    
  4. session属性相关操作

    session.setAttribute(name, value) // 设置session中的属性值
    session.getAttribute(name)		//根据name 获取对应的属性值
    session.getAttributeNames()		//获取session 所有属性的name值
    session.removeAttribute(name)	//删除属性值
    

Session的使用

package com.sxt.controller;

import java.io.IOException;

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

@WebServlet(urlPatterns = {"/session.do"})
public class SessionServlet extends HttpServlet {
	private static final long serialVersionUID = -5145647028038928413L;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 获取Session 获取一个与当前request对象关联的session
		HttpSession session = req.getSession();
		// 设置属性值
		//session.setAttribute(name, value);
		//session.getAttribute(name);
		//session.getAttributeNames();
		//session.removeAttribute(name);
		// 获取sessionID
		System.out.println(session.getId());
		// 设置session的存活时间,  0  或者 负数  表示永远有效   服务器默认session失效是  30分钟
		//session.setMaxInactiveInterval(interval);
	}

}

Session案例

使用Session存储当前用户

private void login(HttpServletRequest req, HttpServletResponse resp) throws IOException {
	String userName = req.getParameter("userName");
	String password = req.getParameter("password");
	User user = userService.login(userName, password);
	if(user != null) {
		//跳转到学生列表 : 跳转到学生列表 : 学生列表页面必须要有数据
		//获取session
		HttpSession session = req.getSession();
		//将用户信息放入session
		session.setAttribute("user", user);
		resp.sendRedirect("student.do?service=list");
	}else {
		resp.sendRedirect("login.jsp");
	}
}
<p>欢迎您:${user.realName}</p>

Session验证码

hutool工具类方案:

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	// 生成验证码  200:宽度   100:高度  4:验证码字符数  10:干扰元素的个数
	AbstractCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 10);
	circleCaptcha = CaptchaUtil.createLineCaptcha(200, 100,4, 10);
	// 验证码对象中验证码字符串
	String code = circleCaptcha.getCode();
	System.out.println(code);
	// 获取缓存图片对象   
	BufferedImage image = circleCaptcha.getImage();
	// 将验证码图片进行输出
	circleCaptcha.write(resp.getOutputStream());
}

自定义验证码:

package com.sxt.controller;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @ClassName: CheckCodeServlet2 
 * @Description: 绘制 验证码
 * @author: Mr.T
 * @date: 2019年11月2日 下午2:06:23
 */
@WebServlet(urlPatterns = {"/checkCode2.do"})
public class CheckCodeServlet2 extends HttpServlet {

	private static final long serialVersionUID = -8930649588155434394L;
	
	private static final String[] str = {"1","2","3","4","5","6","7","8","9","A","B","C","D"};
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		/**
		 * 	1. 产生一个验证码字符串
		 * 	2. 将验证码字符串 绘制到图片
		 * 	3.将图片输出到页面
		 */
		String code = getCode(4);
		BufferedImage image = getImage(200, 100, code);
		ImageIO.write(image, "jpg", resp.getOutputStream());
	}
	
	/**
	 * @Title: getImage
	 * @author: Mr.T   
	 * @date: 2019年11月2日 下午2:15:20 
	 * @Description: 产生验证码图片
	 * @param w
	 * @param h
	 * @param code
	 * @return
	 * @return: BufferedImage
	 */
	private BufferedImage  getImage(int w,int h,String code) {
		//创建图片 画布
		BufferedImage image = new BufferedImage(w, h,BufferedImage.TYPE_INT_RGB);
		//获取画布相关画笔
		Graphics graphics = image.getGraphics();
		//设置画笔的颜色
		graphics.setColor(Color.WHITE);
		//绘制矩形
		graphics.fillRect(0, 0, 200, 100);
	
		//创建字体
		Font font = new Font("微软雅黑", Font.BOLD, 50);
		graphics.setFont(font);
		for (int i = 0; i < code.length(); i++) {
			//设置画笔颜色
			graphics.setColor(getColor());
			char c = code.charAt(i);
			graphics.drawString(""+c,10+(i*50),70);
		}
		//绘制干扰线
		for (int i = 0; i < 10; i++) {
			graphics.setColor(getColor());
			graphics.drawLine(getX1(w),getY(h), getX2(w),getY(h));
		}
		return image;
	}
	
	/**
	 * @Title: getCode
	 * @author: Mr.T   
	 * @date: 2019年11月2日 下午2:13:46 
	 * @Description: 产生验证码
	 * @param codeCount
	 * @return
	 * @return: String
	 */
	public String getCode(int codeCount) {
		String code = "";
		for (int i = 0; i < codeCount; i++) {
			int index = new Random().nextInt(str.length);
			code = code + str[index];
		}
		return code;
	}

	/**
	 * @Title: getColor
	 * @author: Mr.T   
	 * @date: 2019年11月2日 下午2:28:33 
	 * @Description: 获取颜色
	 * @return
	 * @return: Color
	 */
	public Color getColor() {
		Random random = new Random();
		int r = random.nextInt(255);
		int g = random.nextInt(255);
		int b = random.nextInt(255);
		Color color = new Color(r, g, b);
		return color;
	}
	/**
	 * @Title: getX1
	 * @author: Mr.T   
	 * @date: 2019年11月2日 下午2:41:22 
	 * @Description: 产生起点
	 * @param w
	 * @return
	 * @return: int
	 */
	public int getX1(int  w) {
		w = w/2;
		Random random = new Random();
		return random.nextInt(w);
	}
	/**
	 * @Title: getX2
	 * @author: Mr.T   
	 * @date: 2019年11月2日 下午2:43:54 
	 * @Description: 终点的X值
	 * @param w
	 * @return
	 * @return: int
	 */
	public int getX2(int  w) {
		w = w/2;
		Random random = new Random();
		return random.nextInt(w)+w;
	}
	
	/**
	 * @Title: getY
	 * @author: Mr.T   
	 * @date: 2019年11月2日 下午2:44:08 
	 * @Description: 随机产生Y轴值
	 * @param h
	 * @return
	 * @return: int
	 */
	public int getY(int  h) {
		Random random = new Random();
		return random.nextInt(h);
	}

	public static void main(String[] args) {
		String code = new CheckCodeServlet2().getCode(4);
		System.out.println(code);
	}
	
}

总结:

WEB会话技术.

​ HTTP协议的无状态,不会记录客户端的请求信息状态.

WEB技术两种解决方案:

​ 1.Cookie

​ 客户端请求时 ,返回Cookie给客户端,客户端每次请求将Cookie带过来.

​ 2.Session

​ 服务器将数据信息,存储在服务器(创建了一个Session对象),然后将这个Session对象的唯一标识(Session的ID),利用Cookie给客户端,客户端每次请求,会将这个唯一标识通过Cookie传给服务器.服务器通过唯一标识,找到对应Session.

局限性:

​ 1.Cookie存在客户端的,若多终端时,Cookie没法共享。

​ 2.Session存在服务器,多服务器是多节点,Session也无法做到完全共享。

原文地址:https://www.cnblogs.com/lyang-a/p/12562937.html