HTTP协议的特点:
- 应答式,必须先有请求才有响应.
- 明文传输.不安全.
- 无状态.服务器不会记录客户端的访问信息.
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
-
创建Session
req.getSession(); //若当前不存在session 则创建新的session 否则返回当前session req.getSession(true); //若当前不存在session 则创建新的session 否则返回当前session req.getSession(false); //若当前存在session 则返回当前session 否则返回null
-
设置session的有效期
session.setMaxInactiveInterval(interval); //设置session的有效期(单位是秒),若不大于0 则表示永久有效
-
设置session失效
invalidate(); // 不让任何对象绑定这个session. 则request 找不到这个session.
-
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也无法做到完全共享。