一、会话
1.会话概述:
用户第一次打开浏览器去访问服务器,就是会话的开始;
用户发送请求给服务器,服务器返回响应给浏览器渲染表现,就是会话的过程;
用户关闭浏览器,才是会话的结束,只要没有关闭浏览器,期间的每次访问都属于同义词会话;
2.会话技术:
2.1 会话技术的作用:
由于Http协议时无状态的协议,所以会话技术就是用来保存用户产生的数据,方便判断用户是谁,做了什么;
2.2 两种会话技术:
-
cookie:
客户端会话技术:会话数据保存到浏览器端
-
session:
服务器会话技术:会话数据存储到服务器端
二、Cookie
1.Cookie使用场景
因为cookie是存储在浏览器端的数据,由服务器返回给浏览器,浏览器接受并保存到电脑的某个位置,下次打开这个网页的时候,自动读取存储的数据,并在需要的时候发送给服务器端;
eg:
浏览器某些网页的时候的自动登录功能;
Cookie其实就是存储在客户机上的一个文件,方便下次使用的时候免于再次录入信息;
Cookie保存服务器返回的数据;
2.代码实现返回Cookie给浏览器
@WebServlet(name = "CookieServlet")
public class CookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置返回编码和数据类型
response.setContentType("text/html;charset=utf-8");
//2.获得输出流
PrintWriter out = response.getWriter();
out.print("存储cookie");
//3.创建cookie信息
Cookie cookie = new Cookie("user", "admin");
//4.返回cookie给浏览器,浏览器获得数据后,自动保存
response.addCookie(cookie);
}
}
3.Cookie运行原理
- 浏览器第一次访问服务器没有cookie数据
- 服务器创建cookie对象,封装之后以响应头的形式,返回给浏览器
- 浏览器接受到cookie之后,将它保存到本地
- 浏览器再次访问的时候,浏览器发送cookie以请求头的形式给服务器
- 服务器读取浏览器发送的cookie数据
4.Cookie过期时间设置
cookie的默认过期时间:浏览器关闭即消失失效;
@WebServlet(name = "CookieServlet")
public class CookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置返回编码和数据类型
response.setContentType("text/html;charset=utf-8");
//2.获得输出流
ServletOutputStream out = response.getOutputStream();
out.print("存储cookie");
//3.创建cookie信息
Cookie cookie = new Cookie("user", "admin");
//设置cookie过期时间;单位:秒;
//如果数值为负,则自动设置为默认值,负数无效;设置为0,删除cookie
cookie.setMaxAge(600);
//4.返回cookie给浏览器,浏览器获得数据后,自动保存
response.addCookie(cookie);
}
}
由于功能需要,所以在某些情况下需要删除Cookie
实现方式:
- 创建一个同名的cookie,有效路径也要一直,但是value无所谓
- 设置过期时间为0
- 返回给浏览器端;
代码实现:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
ServletOutputStream out = response.getOutputStream();
out.print("删除cookie");
Cookie cookie = new Cookie("user", "admin");
cookie.setMaxAge(0);
cookie.setPath(request.getContextPath()+"");
response.addCookie(cookie);
}
5.代码读取cookie
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置返回数据编码和类型,避免乱码
response.setContentType("text/html;charset=utf-8");
//获得cookie
Cookie[] cookies = request.getCookies();
if(cookies !=null){
//获得字节输出流
ServletOutputStream out = response.getOutputStream();
//循环输出cookie到浏览器显示
for (Cookie cookie : cookies) {
out.print(cookie.getName()+"\t"+cookie.getValue()+"\t");
}
}
}
6.设置Cookie有效路径
为什么要设置?
因为保存在浏览器的数据,在浏览器访问服务器其他所有页面的时候,默认都会携带cookie;
这样就会造成数据量变大,设置有效路径之后,可以减少数据量的传输;
@WebServlet(name = "CookieServlet")
public class CookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置返回编码和数据类型
response.setContentType("text/html;charset=utf-8");
//2.获得输出流
ServletOutputStream out = response.getOutputStream();
out.print("存储cookie");
//3.创建cookie信息
Cookie cookie = new Cookie("user", "admin");
//设置cookie过期时间
cookie.setMaxAge(60 * 60 * 24 * 7);
//设置cookie有效路径或,访问路径
//设置要以项目名为第一个访问路径开头,然后再设置要访问的html或网页
// “/项目名/要网文的网页、jsp、servlet”
//或者可以用代码来实现: request.getContextPath()
cookie.setPath("/WebApp/login");
//4.返回cookie给浏览器,浏览器获得数据后,自动保存
response.addCookie(cookie);
}
}
问题:如果访问路径是
setPath("/day-cookie")
,以下路径哪些可以正常访问?
访问地址 | 能否访问到 Cookie |
---|---|
http://localhost:8080/day-cookie/ | 能 |
http://localhost:8080/day-cookie/aa/bb | 能 |
http://localhost:8080/day/ | 不能 |
http://localhost:8080/ | 不能 |
注意:设置有效路径之后,设置路径的子路径也可以访问,但是其他路径无法访问
7.Cookie使用非法字符:
由于在设置cookie时,无法使用使用特殊字符,但是难免会用到这些非法字符,所以要做相应的设置来使用非法字符,并使之有效;
那么就需要先对包含非法字符的字符串进行url编码,将编码后的结果作为value返回给浏览器;
当浏览器发送这个数据给服务器的时候,要再进行url解码,才能还原数据;
//假设这里有可能会出现非法字符,那么接下来就进行处理
//把username加密之后再传输
username = URLEncoder.encode(username, "utf8");
//读取时候也要进行相应的解码
//获取Cookie
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
//找到保存相应信息的cookie
if (cookie.getName().equals("username")){
//把内容解码
String encode = URLEncoder.encode(cookie.getValue(), "utf8");
}
}
8.拓展:实现自动登录功能:
- 如果要实现自动登录,那么就要记录好用户输入的用户名和密码
- 然后再特定页面把信息填入应该填入的地方
- 自动点击提交登录,等待登录成功
而自动登录的实现主要是需要获得本地存储的信息,所以需要使用cookie来实现!
Servlet代码:
@WebServlet(urlPatterns = "/AutoServlet")
public class AutoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.转换编码格式,防止乱码
request.setCharacterEncoding("utf8");
response.setContentType("text/html;charset=utf-8");
//2.获得用户登录信息
String username = request.getParameter("username");
String password = request.getParameter("password");
String remember = request.getParameter("remember");
//3.判断用户登录是否成功
if ("admin".equals(username) && "123".equals(password)) {
//4.登录成功,判断是否需要存储cookie信息,下次免登录
if (remember != null) {
//6.保存用户信息到cookie并返回给浏览器保存
Cookie uCookie = new Cookie("username", username);
Cookie pCookie = new Cookie("password", password);
response.addCookie(uCookie);
response.addCookie(pCookie);
}
//7.跳转到登录成功后看到的页面
response.sendRedirect("index.jsp");
} else {
//5.登录失败,返回页面
response.sendRedirect("login.html");
}
}
}
前端页面代码:
<h2>用户登录</h2>
<form action="login" method="post" id="loginForm">
<table>
<tr>
<td width="60">用户名</td>
<td><input type="text" name="username" id="username"/></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password" id="password"/></td>
</tr>
<tr>
<td>记住我</td>
<!--没有value属性的前提下,点中它的值是on-->
<td><input type="checkbox" name="remember"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="登录"/></td>
</tr>
</table>
</form>
JS代码:(用来实现自动点击登录按钮)
/**
* 页面加载完成,读取cookie的信息
* 如果有username和password
* 则将用户名和密码发送给服务器,实现自动登录
* 如果没有,则显示登录页面
*/
window.onload = function () {
// 读取Cookie信息
var cookies = document.cookie;
// 如果cookie不为空
if (cookies) {
// 得到用户名和密码
var username = getCookie("username"); // jack
var password = getCookie("password"); // 123
// 设置文本框的值
document.getElementById("username").value = username;
document.getElementById("password").value = password;
// 提交表单
document.getElementById("loginForm").submit();
}
};
/*
* 得到指定cookie的值
*/
function getCookie(cname) {
var ca = document.cookie.split(';'); // [username=admin;password=123]
for(var i = 0; i < ca.length; i++) {
var c = ca[i]; // "password=123"
var arr = c.split("="); // ["password",123]
if (arr[0].trim() == cname){ // password
return arr[1];
}
}
return "";
}
三、Session
1.Session应用场景
数据存储在服务器端,一般用于对比用户传入的信息;
eg:验证码的实现;
Session也是servlet三大作用域中的会话域;
Session是什么?
因为是Servlet中的会话域,所以也是服务器中的一小块内存,每个会话域都有自己的内存区域,不同的会话之间不能共享数据,底层是map结构;
session的作用就是用于同一次会话时,把数据存储在Session中共享;
2.session运行原理:
- 服务器第一次调用请求对象的getSession()方法时,创建一个内存区域分配给这个session,并且指定一个唯一的会话id;
- 浏览器第一次访问没有会话id
- 服务器有了session之后,会将会话id以cookie的形式返回给浏览器,浏览器把数据保存到本地
- 浏览器再次访问服务器的时候,就会把会话id以请求头的方式发送到服务器;
- 服务器根据会话id找到session分配好的内存,对其中的数据增删查改;
3.Session常用方法:
HttpSession接口方法 | 作用 |
---|---|
String getId() | 获得会话ID |
long getCreationTime() | 获得会话创建时间:毫秒值 |
long getLastAccessedTime() | 获得上一次访问会话域的时间:毫秒值 |
boolean isNew() | 判断是否是新的会话 |
ServletContext getServletContext() | 获得上下文对象 |
4.Session常见问题:
-
浏览器关闭,还能不能得到之前会话域中的信息?
不能获得会话域中的数据,因为会话域中的id,默认在会话结束(浏览器关闭)之后就会销毁;
-
如果浏览器关闭,服务器上的会话信息是否还存在?
还存在,服务器会话域中的数据过期时间默认是30分钟;(含义是:在30分钟之内,没有操作才会自动销毁,但是如果你再次访问,则会再次刷新)
-
如果让浏览器关闭之后还可以访问服务器上没有消失的信息?
自己保存会话id,设置过期时间;
5.保存会话ID
@WebServlet(urlPatterns = "/SessionServlet")
public class SessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取session对象
HttpSession session = request.getSession();
//2.获取会话id
String sessionId = session.getId();
//3.新建cookie保存会话id
//注意,这里要设置成服务器可以自动读取的id,不然无法是西安
Cookie cookie = new Cookie("JSESSIONID", sessionId);
//4.把设置好的cookie返回给浏览器
response.addCookie(cookie);
}
}
保存会话id其实没有什么难度,只需要把该注意的注意到了即可
6.设置会话过期时间
设置会话的过期时间,其实某种程度上来说是为了避免有些用户不小心关闭浏览器,导致信息丢失;
设置合理的会话过期时间,一方面可以提高用户体验,另一方面可以管理服务器;
6.1 通过代码:
session.setMaxInactiveInterval(60 * 60 * 30);
6.2 配置xml文件:
<!--设置会话过期时间,单位分钟-->
<session-config>
<session-timeout>1</session-timeout>
</session-config>
6.3 调用销毁方法:
session.invalidate();
四、Cookie、Session的比较和选择
1.如何选择Cookie和Session
如果数据类型比较大,或者包含隐私数据,选择session,否则的话可以选择cookie
2.对比图表
技术类型 | 数据存储位置 | 键值对的数据类型 | |
---|---|---|---|
Cookie | 浏览器端会话技术 | 保存在客户端的一个文件中 | 键和值都是String类型 |
Session | 服务器端的会话技术 | 保存服务器的内存中 | 键是String类型 值是Object类型 |
五、Servlet三个作用域的比较和总结
1.作用域的创建和销毁
作用域 | 接口名 | 作用范围 | 生命周期 |
---|---|---|---|
请求域 | HttpServletRequest | 同一个请求有效 | 请求开始到请求结束 |
会话域 | HttpSession | 同一个会话有效 | 会话开始到会话结束 |
上下文域 | ServletContext | 同一应用有效 | 服务器启动到服务器关闭 |
2.作用域共同的方法
功能 | 方法名 |
---|---|
存放数据 | setAttribute |
获取数据 | getAttribute |
删除数据 | removeAttribute |
3.如何选择作用域
- 如果小范围的作用域能够满足需要就使用小范围的作用域
- 请求域 < 会话域 < 上下文域