Session&Cookie

会话技术

会话

一次会话中包含多次请求和响应。

一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止

功能

在一次会话的范围内多次请求间,共享数据

方式

  1. 客户端会话技术:Cookie
  2. 服务器端会话技术:Session

客户端会话技术,将数据保存到客户端

快速入门

使用步骤

  1. 创建Cookie对象绑定数据

    1
    new Cookie(String name,String value)
  2. 发送Cookie对象

    1
    response.addCookie(Cookie cookie);
  3. 获取Cookie,拿到数据

    1
    Cookie[] ck = request.getCookies();

实现原理

  • 基于响应头set-cookie和请求头cookie实现
    • 客户端请求服务器资源,服务器资源设置cookie,响应回客户端
    • 再次请求其他资源,会在请求头中携带第一次返回的cookie信息给服务器端

image-20230521154954746

Cookie的细节

  1. 一次可不可以发送多个cookie?

    可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。

  2. cookie在浏览器中保存多长时间

    • 默认情况下,当浏览器关闭后,Cookie数据被销毁
    • 持久化存储
      • setMaxAge(int seconds)
        • 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
        • 负数:默认值
        • 零:删除cookie信息
  3. cookie能不能存中文

    • 在Tomcat8之前cookie中不能直接存储中文数据。需要将中文数据转码(一般采用URL编码%十六进制,表示一个字节,多少个%表示多少个字节)
    • 在Tomcat8之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
  4. cookie共享问题

    • 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享
      • 默认情况下cookie不能共享
      • setPath(String path):设置cookie的取值范围。默认情况下,设置当前的虚拟目录。如果要共享则可以将path设置为”/“
    • 不同tomcat服务器件cookie共享问题
      • setDomain(String path);如果设置一级域名相同,那么多个服务器之间cookie可以共享
      • setDomain(“.baidu.com”),那么tieba.baidu.com和news.baidu.com中cookie可以共享

Cookie的特点和作用

特点

  1. cookie存储数据在客户端浏览器
  2. 浏览器对于单个cookie的大小有限制(4kb)以及对同一个域名下的总cookie数量也有限制(20个)

作用

  1. cookie一般用于存储少量的不太敏感的数据
  2. 在不登录的情况下,完成服务器对客户端的身份识别

案例

记住上一次的访问时间。

需求:

  1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问,
  2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串

分析:

  1. 采用Cookie完成
  2. 在服务器中的Servlet判断是否有一个名为lastTime的cookie
    1. 有:不是第一次访问
      1. 响应数据:欢迎回来,您上次访问时间为:xxxx年xx月xx日 xx时:xx分:xx秒
      2. 写回cookie:lastTime=时间
    2. 没有:是第一次访问
      1. 响应数据:您好,欢迎您首次访问
      2. 写回Cookie:lastTime=时间

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package cn.zhuixun.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* 在服务器中的Servlet判断是否有一个名为lastTime的cookie
* 1. 有:不是第一次访问
* 1. 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
* 2. 写回Cookie:lastTime=2018年6月10日11:50:01
* 2. 没有:是第一次访问
* 1. 响应数据:您好,欢迎您首次访问
* 2. 写回Cookie:lastTime=2018年6月10日11:50:01
*/
@WebServlet("/cookieTest")
public class CookieTest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应的消息体的数据格式以及编码
response.setContentType("text/html;charset=utf-8");
//1.获取所有Cookie
Cookie[] cookies = request.getCookies();
boolean flag = false;//没有cookie为lastTime
// 2.遍历cookie数组
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
//3.获取cookie的名称
String name = cookie.getName();
//4.判断名称是否是:lastTime
if ("lastTime".equals(name)) {
//有该Cookie,不是第一次访问
flag = true;
//有lastTime的cookie 设置Cookie的value 获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
System.out.println("编码前:" + str_date);
//URL编码
str_date = URLEncoder.encode(str_date, "utf-8");
System.out.println("编码后:" + str_date);
cookie.setValue(str_date);
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
//
response.addCookie(cookie);
//响应数据
// 获取Cookie的value,时间
String value = cookie.getValue();
System.out.println("解码前:" + value);
//URL解码:
value = URLDecoder.decode(value, "utf-8");
System.out.println("解码后:" + value);
response.getWriter().write("<h1>欢迎回来,您上次访问时间为:" + value + "</h1>");
break;
}
}
}
if (cookies == null || cookies.length == 0 || flag == false) {
//没有,第一次访问 设置Cookie的value 获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
System.out.println("编码前:" + str_date);
//URL编码
str_date = URLEncoder.encode(str_date, "utf-8");
System.out.println("编码后:" + str_date);
Cookie cookie = new Cookie("lastTime", str_date);
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
response.addCookie(cookie);
response.getWriter().write("<h1>您好,欢迎您首次访问</h1>");
}
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}

JSP入门学习

概念

Java Server Pages:java服务器端页面

  1. 可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码
  2. 用于简化书写

原理

JSP本质上就是一个Servlet

image-20230521164629772

JSP的脚本

JSP定义Java代码的方式

  1. <% 代码 %>

    定义的java代码,在service方法中,service方法中可以定义什么,该脚本中就可以定义什么

  2. <%! 代码 %>

    定义的java代码,在jsp转换后的java类中的成员位置(成员变量或成员方法)

  3. <%= 代码%>

    定义的java代码,会输出到页面上。输出语句中可以定义什么,该脚本就可以定义什么(包括其他位置定义的变量)

JSP的内置对象

  • 在Jsp页面不需要获取和创建,可以直接使用的对象

  • jsp一共有9个内置对象

    • request

    • response

    • out

      字符输出流对象。可以将数据输出到页面上。和response.getWriter()类似

response.getWriter()和out.write()区别

  • 在tomcat服务器真正给客户端做出响应之前,会先找response缓冲区数据,再找out缓冲区数据
  • response.getWriter()数据输出永远在out.write()之前

Session

概念

服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession

快速入门

  1. 获取HttpSession对象

    1
    HttpSession session = request.getSession();
  2. 使用HttpSession对象

    1
    2
    3
    Object getAttribute(String name);
    void setAttribute(String name,Object value);
    void removeAttribute(String name);

原理

image-20230521171831307

Session的实现是依赖于Cookie的

细节

  1. 当客户端关闭后,服务器不关闭,两次获取Session是否为同一个

    • 默认情况下:不是,因为客户端关闭了,表示这次会话结束了。

    • 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存

      1
      2
      3
      Cookie c = new Cookie("JSESSIONID",session.getId());
      c.setMaxAge(60*60);
      response.addCookie(c);
  2. 客户端不关闭,服务端关闭后,两次获取的Session同一个吗?

    • 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作

      • session的钝化

        在服务器正常关闭之前,将session对象系列化到硬盘上

      • session的活化

        在服务器启动后,将session文件转化为内存中的session对象即可。

  3. session什么时候被销毁

    • 服务器关闭

    • session对象调用invalidate()

    • session默认失效时间为30分钟

      1
      2
      3
      4
      <!--可以选择性配置修改-->
      <session-config>
      <session-timeout>30</session-timeout>
      </session-config>

session的特点

  1. session用于存储一次会话的多次请求数据,存在服务器端
  2. session可以存储任意类型,任意大小的数据

session和Cookie的区别

  1. session存储数据在服务器端,Cookie在客户端
  2. session没有数据大小限制,Cookie有
  3. session数据安全,Cookie相对于不安全

案例:验证码

案例需求:

  1. 访问带有验证码的登录页面login.jsp
  2. 用户输入用户名,密码以及验证码。
  • 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
  • 如果验证码输入有误,跳转登录页面,提示:验证码错误
  • 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您

案例分析

image-20230521173554467

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>


<script>
window.onload = function(){
document.getElementById("img").onclick = function(){
this.src="/day16/checkCodeServlet?time="+new Date().getTime();
}
}


</script>
<style>
div{
color: red;
}

</style>
</head>
<body>

<form action="/day16/loginServlet" method="post">
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>验证码</td>
<td><input type="text" name="checkCode"></td>
</tr>
<tr>
<td colspan="2"><img id="img" src="/day16/checkCodeServlet"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="登录"></td>
</tr>
</table>


</form>


<div><%=request.getAttribute("cc_error") == null ? "" : request.getAttribute("cc_error")%></div>
<div><%=request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error") %></div>

</body>
</html>





<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>

<h1><%=request.getSession().getAttribute("user")%>,欢迎您</h1>

</body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138


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;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


int width = 100;
int height = 50;

//1.创建一对象,在内存中图片(验证码图片对象)
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);


//2.美化图片
//2.1 填充背景色
Graphics g = image.getGraphics();//画笔对象
g.setColor(Color.PINK);//设置画笔颜色
g.fillRect(0,0,width,height);

//2.2画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width - 1,height - 1);

String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
//生成随机角标
Random ran = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 4; i++) {
int index = ran.nextInt(str.length());
//获取字符
char ch = str.charAt(index);//随机字符
sb.append(ch);

//2.3写验证码
g.drawString(ch+"",width/5*i,height/2);
}
String checkCode_session = sb.toString();
//将验证码存入session
request.getSession().setAttribute("checkCode_session",checkCode_session);

//2.4画干扰线
g.setColor(Color.GREEN);

//随机生成坐标点

for (int i = 0; i < 10; i++) {
int x1 = ran.nextInt(width);
int x2 = ran.nextInt(width);

int y1 = ran.nextInt(height);
int y2 = ran.nextInt(height);
g.drawLine(x1,y1,x2,y2);
}


//3.将图片输出到页面展示
ImageIO.write(image,"jpg",response.getOutputStream());


}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}



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;
import java.io.IOException;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置request编码
request.setCharacterEncoding("utf-8");
//2.获取参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String checkCode = request.getParameter("checkCode");
//3.先获取生成的验证码
HttpSession session = request.getSession();
String checkCode_session = (String) session.getAttribute("checkCode_session");
//删除session中存储的验证码
session.removeAttribute("checkCode_session");
//3.先判断验证码是否正确
if(checkCode_session!= null && checkCode_session.equalsIgnoreCase(checkCode)){
//忽略大小写比较
//验证码正确
//判断用户名和密码是否一致
if("zhangsan".equals(username) && "123".equals(password)){//需要调用UserDao查询数据库
//登录成功
//存储信息,用户信息
session.setAttribute("user",username);
//重定向到success.jsp
response.sendRedirect(request.getContextPath()+"/success.jsp");
}else{
//登录失败
//存储提示信息到request
request.setAttribute("login_error","用户名或密码错误");
//转发到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
}


}else{
//验证码不一致
//存储提示信息到request
request.setAttribute("cc_error","验证码错误");
//转发到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);

}

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}


Session&Cookie
http://example.com/2023/05/23/JavaWeb/Session&Cookie/
作者
zhuixun
发布于
2023年5月23日
许可协议