- session+cookie,做web开发必须知道的东西
5.session+cookie
5.1 实现用户登录功能
实现登录功能:
- 步骤1:数据库当中添加一个用户表:t_user
- t_user 表当中存储的是用户的登录信息,最基本的包括:登录的用户名和登录的密码。
- 密码一般在数据库表当中存储的是密文,一般不以明文的形式存储。
- 向 t_user 表中插入用户的数据。
- 步骤2:再实现一个登录页面。
- 登录页面上应该有一个登录的表单,有用户名和密码的输入框。
- 用户点击登录,提交表单,提交用户名和密码,以 post 方式提交。
- 步骤3:后台要有一个对应的 Servlet 来处理登录的请求。
- 登录成功:跳转到部门列表页面。
- 登录失败:跳转到失败的页面。
- 步骤1:数据库当中添加一个用户表:t_user
登录功能实现了,目前存在的最大的问题:
- 这个登录功能目前只是一个摆设,没有任何作用。只要用户知道后端的请求路径,照样可以在不登录的情况下访问。
- 这个登录没有真正起到拦截的作用。怎么解决? -> 使用
session
机制。
5.2 ★★★web应用的session机制
什么是会话?
会话对应的英语单词:session。
用户打开浏览器,进行一系列操作,然后最终将浏览器关闭,这个整个过程叫做:一次会话。
会话在服务器端也有一个对应的 java 对象,这个 java 对象叫做:
session
。什么是一次请求:用户在浏览器上点击了一下,然后到页面停下来,可以粗略认为是一次请求。
请求对应的服务器端的 java 对象是:
request
。request 和 session 都是服务器端的 java 对象,都在 JVM 中。
- request 对象代表了一次请求,一次请求对应一个 request 对象,两次请求就会对应两个不同的 request 对象。
- session 对象代表了一次会话,一次会话对应一个 session 对象。
一个会话当中包含多次请求(一次会话对应 N 次请求)。
在 java 的 servlet 规范当中,session 对应的类名:
HttpSession(jarkata.servlet.http.HttpSession)
。session 机制属于 B/S 结构的一部分,如果使用 php 语言开发 WEB 项目,同样也是有 session 这种机制的,session 机制实际上是一个规范,不同的语言对这种会话机制都有实现。
session 对象最主要的作用是:保存会话状态(用户登录成功了,这是一种登录成功的状态,你怎么把登录成功的状态一直保存下来呢?使用 session 对象可以保留会话状态)。
- 为什么需要 session 对象来保存会话状态呢?
- 因为 HTTP 协议是一种无状态协议。
- 什么是无状态:请求的时候,B 和 S 是连接的,但是请求结束之后,连接就断了。可以理解为,在请求时,浏览器和服务器之间会建立管道,进行数据的传输,一但数据传输完成,那么这条管道就会断开。为什么要这么做?HTTP 协议为什么要设计成这样?
- 因为这样的无状态协议,可以降低服务器的压力。请求的瞬间是连接的,请求结束之后,连接断开,这样服务器压力小。
- 只要 B 和 S 断开了,那么关闭浏览器这个动作,服务器知道吗?
- 不知道,服务器是不知道浏览器关闭的。
- 为什么需要 session 对象来保存会话状态呢?
张三打开一个浏览器 A,李四打开一个浏览器 B,访问服务器之后,在服务器端会生成:
- 张三专属的 session 对象。
- 李四专属的 session 对象。
为什么不使用 request 对象保存会话状态?为什么不使用 ServletContext 对象保存会话状态?
比如用
request.setAttribute()
存,用request.getAttribute()
取。类似的,
ServletContext
也有这两个方法。- 因为
request
对象的生命周期太短,request 是一次请求对应一个request
对象,请求结束后request
对象就销毁了。 - 因为
ServletContext
对象的域太大,ServletContext
对象是服务器启动的时候创建,服务器关闭的时候销毁,这个ServletContext
对象只有一个,如果将会话状态放在ServletContext
对象中,那所有用户都共享保存的会话状态了。
- 因为
request 请求域(
HttpServletRequest
)、session 会话域(HttpSession
)、application 应用域(ServletContext
)。- 这三个域的大小:
request < session < application
- 这三个域的大小:
★★★session的实现原理
思考一下:
session
对象的实现原理。HttpSession session = request.getSession();
- 这行代码很神奇,张三访问的时候获取的 session 对象就是张三的,李四访问的时候获取的 session 对象就是李四的。
session 的实现原理:

session
对象是存储在服务器端的。一个
session
对象对应一个会话。一次会话中包含多次请求。session
对象怎么获取?HttpSession session = request.getSession();
从 Web 服务器当中获取当前的 session 对象,如果 session 对象没有,则新建。
HttpSession session = request.getSession(false);
从 Web 服务器当中获取当前的 session 对象,如果 session 对象没有,并不会新建,返回 null。
session
的实现原理:在 web 服务器中有一个 session 列表,类以于 map 集合。
这个 map 集合的 key 存储的是 sessionid,value 存储的是对应的 session 对象。
用户发送第一次请求的时候:服务器会创建一个新的 session 对象,同时给 session 对象生成一个 id,然后 web 服务器会将 session 的 id 发送给浏览器,浏览器将 session 的 id 保存在浏览器的缓存中。
- 在第一次请求时,服务器的响应中有
JSESSIONID=xxxxxx
,这个是以cookie
的形式保存在浏览器的内存中的,只要浏览器关闭了,这个 cookie 就没有了。
用户发送第二次请求的时候:会自动将浏览器缓存中的 sessionid 自动发送给服务器,服务器获取到 sessionid,然后从 session 列表中查找到对应的 session 对象。
- 在第一次请求时,服务器的响应中有
为什么关闭浏览器,会话结束?
关闭浏览器之后,浏览器中保存的 sessionid 消失,下次重新打开浏览器之后,浏览器缓存中没有这个 sessionid,自然找不到服务器中对应的 session 对象,session 对象找不到等同于会话结束。
注意:此时并不代表服务器端相应的 session 对象被销毁。
session 对象什么时候被销毁?
- 一种销毁:是超时销毁。
- 一种销毁:是手动销毁。
浏览器关闭的时候,服务器是不知道的,服务器无法监测到浏览器关闭了(因为 HTTP 是无状态协议),所以 session 的销毁要依靠
“session 超时机制”
。但也有一种可能,系统提供了“安全退出”,用户可以点击这个按钮,这样服务器就知道你退出了,然后服务器会自动销毁 session 对象。设置 session 对象的超时销毁的配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<!-- session的超时时长为30分钟 -->
<!-- 如果30分钟过去了,session对象仍然没有被访问,那么session对象会被销毁 -->
<!-- 默认值为30 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
思考
- cookie 禁用了,session 还能找到吗?
- cookie 禁用是什么意思?
- 服务器正常发送 cookie 给浏览器,但是浏览器不要了,拒收了,并不是服务器不发了。
- 找不到 session 了,每一次请求都会在服务器创建新的 session 对象,服务器没有收到浏览器的 sessionid,无法查找之前创建的 session 对象。
- cookie 禁用了,session 机制还能实现吗?
- 可以。需要使用 URL 重写机制。
- http://localhost:8080/servlet11/test/session;jsessionid=19D1C99560DCBF84839FA43D58F56E16
- URL 重写机制会提高开发者的成本,开发人员在编写任何请求路径的时候,后面都要添加一个 sessionid,给开发带来了很大的难度,很大的成本。所以大部分的网站都是这样设计的:你要是禁用 cookie,你就别用了。
- cookie 禁用是什么意思?
目前所学的域对象
总结一下到目前为止我们所了解的域对象:
request
(对应的类名:HttpServletRequest
)- 请求域(请求级别的)
session
(对应的类名:HttpSession
)- 会话域(用户级别的)
application
(对应的类名:ServletContext
)- 应用域(项目级别的,所有用户共享的)
这三个域对象的大小关系
request
<session
<application
他们三个域对象都有以下三个公共的方法:
setAttribute
(向域当中绑定数据)getAttribute
(从域当中获取数据)removeAttribute
(删除域当中的数据)
使用原则:尽量使用小的域。
session改造oa项目
session 掌握之后,我们怎么解决 oa 项目中的登录问题,怎么能让登录起作用,而不是“只要用户知道后端的请求路径,照样可以在不登录的情况下访问”。
登录成功之后,可以将用户的登录信息存储到 session 当中,也就是说 session 中如果有用户的信息就代表用户登录成功了;session 中没有用户信息,表示用户没有登录过,则跳转到登录页面。
1
2
3
4
5
6
7
8
9
10
11
12
13protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取session对象,如果session对象不存在,则返回null
HttpSession session = request.getSession(false);
if (session != null && session.getAttribute("username") != null) { // session条件判断
// 这里写的比较简陋,完整的应该是如果条件成立,
// 就会执行数据相关的crud操作,然后带着数据跳转到相应的页面
// 所以如果直接访问 ip:port/xxx/xxx.jsp 是不会显示数据的
response.sendRedirect(request.getContextPath() + "/success.jsp");
} else {
response.sendRedirect(request.getContextPath());
}
}
JSP 的九大内置对象中有 session,所以一访问
index.jsp
页面就会创建一个相应的 session 会话对象。而不是按照我们希望的那样,在用户登录成功以后,才创建 session 对象。所以如果要让在访问
index.jsp
页面的时候不生成 session 对象,同时在该页面中也不能使用 session 内置对象:1
2<%-- 访问JSP页面时不生成session对象,同时在该JSP页面中也不能使用session内置对象 --%>
<%"false" %> session =销毁 session 对象:
1
session.invalidate();
5.3 ★★★Cookie
cookie的理论基础
session 的实现原理中,每一个 session 对象都会关联一个 sessionid,例如:
JSESSIONID=41C481F0224664BDB28E95081D23D5B8
以上的这个键值对数据其实就是 cookie 对象。
对于 session 关联的 cookie 来说,这个 cookie 是被保存在浏览器的 “运行内存” 当中。只要浏览器不关闭,用户再次发送请求的时候,会自动将运行内存中的 cookie 发送给服务器。
- 例如,这个
Cookie:JSESSIONID=41C481F0224664BDB28E95081D23D5B8
就会再次发送给服务器。服务器就是根据41C481F0224664BDB28E95081D23D5B8
这个值来找到对应的 session 对象的。
- 例如,这个
cookie 怎么生成?cookie 保存在什么地方?cookie 有啥用?浏览器什么时候会发送 cookie,发送哪些 cookie 给服务器?
cookie 怎么生成?
- Cookie 是由服务器生成并发送给客户端的小型数据文件。
- 在 Java 程序中通过
response.addCookie(cookie);
,服务器将 cookie 发送给浏览器。
- 在 Java 程序中通过
- Cookie 是由服务器生成并发送给客户端的小型数据文件。
cookie 保存在什么地方?
cookie 最终是保存在浏览器客户端上的。
- 可以保存在运行内存中(浏览器只要关闭 cookie 就消失了)。
- 也可以保存在硬盘文件中(永久保存)。
关于 cookie 的有效时间及保存方式:
- 怎么用 java 设置 cookie 的有效时间:
cookie.setMaxAge(60 * 60);
设置 cookie 在一小时之后失效。
- 没有设置有效时间:默认保存在浏览器的运行内存中,浏览器关闭则 cookie 消失。
- 只要设置 cookie 的有效时间 > 0,这个 cookie 一定会存储到硬盘文件当中。
- 设置 cookie 的有效时间 = 0 呢?
- 表示该 cookie 被删除,主要应用在:使用这种方式删除浏览器客户端上的同名 cookie。
- 设置 cookie 的有效时间 < 0 呢?
- 保存在浏览器运行内存中,和不设置时一样。
cookie 有啥用呢?
cookie 和 session 机制其实都是为了保存会话的状态。
cookie 是将会话的状态保存在浏览器客户端上( cookie 数据是存储在浏览器客户端上的)。
session 是将会话的状态保存在服务器端上( session 对象是存储在服务器上的)。
为什么要有 cookie 和 session 机制呢?
- 因为 HTTP 协议是无状态无连接协议。
浏览器什么时候会发送 cookie,发送哪些 cookie 给服务器?
在 HTTP 协议中是这样规定的:当浏览器发送请求的时候,会自动携带该 path 下的 cookie 数据给服务器(URL)。
关于 cookie 的 path,cookie 关联的路径:
假设现在在服务端生成 cookie,发送给浏览器的是请求路径为 “http://localhost:8080/servlet13/cookie/generate” 生成的 cookie(cookie 在服务端生成,发送给浏览器客户端),如果该 cookie 没有设置 path,默认的 path 是什么?
默认的 path 是:http://localhost:8080/servlet13/cookie 以及它的子路径。
也就是说,以后只要浏览器的请求路径是 http://localhost:8080/servlet13/cookie 这个路径以及这个路径下的子路径,该 cookie 都会被浏览器发送给服务器。
默认情况下,**如果不设置 Cookie 的 path,默认是
“/项目名/当前路径的上一层地址”
**,如:在请求路径:/cookie/cookieDome/servlet/login
下,服务端生成的 cookie 发送给了浏览器;则后面 Cookie 会被浏览器发送给服务端的请求路径为/cookie/cookieDome/servlet
及这个路径下的子路径。
手动设置 cookie 的 path
cookie.setPath(“/servlet13”);
表示只要是这个 servlet13 项目的请求路径,都会提交这个 cookie 给服务器。
cookie 的经典案例:
- 京东商城,在未登录的情况下,向购物车中放几件商品。然后关闭商城,再次打开浏览器,访问京东商城的时候,购物车中的商品还在,这是怎么做的?我没有登录,为什么购物车中还有商品呢?
- 将购物车中的商品编号放到 cookie 当中,cookie 保存在硬盘文件当中。这样即使关闭浏览器。硬盘上的 cookie 还在。下一次再打开京东商城,查看购物车的时候,会自动读取本地硬盘中存储的 cookie,拿到商品编号,动态展示购物车中的商品。
- 京东存储购物车中商品的 cookie 可能是这样的:
productIds=xxxxx,yyyy,zzz,kkkk
。 - 注意:cookie 如果清除掉,购物车中的商品就消失了。
- 京东存储购物车中商品的 cookie 可能是这样的:
- 将购物车中的商品编号放到 cookie 当中,cookie 保存在硬盘文件当中。这样即使关闭浏览器。硬盘上的 cookie 还在。下一次再打开京东商城,查看购物车的时候,会自动读取本地硬盘中存储的 cookie,拿到商品编号,动态展示购物车中的商品。
- 126 邮箱中有一个功能:十天内免登录
- 这个功能也是需要 cookie 来实现的。
- 怎么实现的呢?
- 用户输入正确的用户名和密码,并且同时选择十天内免登录。登录成功后。浏览器客户端会保存一个 cookie,这个 cookie 中保存了用户名和密码等信息,这个 cookie 是保存在硬盘文件当中的,十天有效。在十天内用户再次访问 126 的时候,浏览器自动提交 126 的关联的 cookie 给服务器,服务器接收到 cookie 之后,获取用户名和密码,验证,通过之后,自动登录成功。
- 怎么让 cookie 失效?
- 十天过后自动失效。
- 或者改密码。
- 或者在客户端浏览器上清除 cookie。
- 京东商城,在未登录的情况下,向购物车中放几件商品。然后关闭商城,再次打开浏览器,访问京东商城的时候,购物车中的商品还在,这是怎么做的?我没有登录,为什么购物车中还有商品呢?
在Java中使用cookie
cookie 机制和 session 机制其实都不属于 java 中的机制,实际上 cookie 机制和 session 机制都是 HTTP 协议的一部分。
php 开发中也有 cookie 和 session 机制,只要是你是做 web 开发,不管是什么编程语言,cookie 和 session 机制都是需要的。
HTTP 协议中规定:任何一个 cookie 都是由 name 和 value 组成的。name 和 value 都是
字符串类型
的。在 HTTP 协议中是这样规定的:当浏览器发送请求的时候,会自动携带该 path 下的 cookie 数据给服务器(URL)。
在 java 的 servlet 中,对 cookie 提供了哪些支持呢?
- 提供了一个 Cookie 类来专门表示 cookie 数据。
jakarta.servlet.http.Cookie;
- java 程序怎么把 cookie 数据发送给浏览器呢?
response.addCookie(cookie);
- 提供了一个 Cookie 类来专门表示 cookie 数据。
浏览器发送 cookie 给服务器了,服务器中的 java 程序怎么接收?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cookie[] cookies = request.getCookies(); // 这个方法可能返回null,没有提交cookie的时候
if (cookies != null) {
for (Cookie cookie : cookies) {
// 获取cookie的name
String name = cookie.getName();
// 获取cookie的value
String value = cookie.getValue();
System.out.println(name + " = " + value);
}
}
}Java 中 Cookie 对象的常用相关方法小结:
cookie.setMaxAge(60 * 60);
设置 cookie 在一小时之后失效。cookie.setPath(“/servlet13”);
手动设置 cookie 的路径。response.addCookie(cookie);
java 程序把 cookie 数据发送给浏览器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 创建cookie对象
Cookie cookie1 = new Cookie("productId", "A123");
Cookie cookie2 = new Cookie("name", "zhangsan");
// 设置cookie在一小时之后失效(保存在硬盘文件中)
//cookie.setMaxAge(60 * 60);
// 设置cookie的有效期为0,表示该cookie被删除,主要应用在:使用这种方式删除浏览器客户端上的同名cookie
//cookie.setMaxAge(0);
// 设置cookie的有效期 < 0,表示该cookie不会被存储在硬盘,只是保存在浏览器运行内存中
//cookie.setMaxAge(-1);
// 默认情况下,没有设置path的时候,cookie关联的路径是什么,是 `“/项目名/当前路径的上一层地址”
// 设置cookie的路径
cookie1.setPath(request.getContextPath()); //表示只要是在该应用下,都发送这个cookie给服务端
cookie2.setPath(request.getContextPath());
// 将cookie响应到浏览器
response.addCookie(cookie1);
response.addCookie(cookie2);
}Cookie[] cookies = request.getCookies();
获取浏览器客户端发送给服务端的 cookie 数据。String name = cookie.getName();
获取 cookie 的 name。String value = cookie.getValue();
获取 cookie 的 value。