1. 会话跟踪
背景:传统HTTP协议的服务端并不能存储任何有关用户状态的信息
会话跟踪:上次请求传递、修改的数据能够影响到下次请求,并且能识别出是相同客户端发送出来的。
一次会话的简单流程
1.1 Cookie - 重要数据写给客户端
前提:确保浏览器允许使用Cookie
数据保存位置: 客户端上 ---- 一个Cookie对应一个键值对
跟踪思想: 客户端第一次请求,服务器在返回报文上将Cookie发给客户端,客户端将Cookie信息存储在一个文件上,客户端每次请求时,便Cookie信息放在请求报文里面,服务器根据请求报文的信息从而进行比对、确认客户端身份。
注意1: 任何身份都有时效性,例如自己身份证有效期,Cookie也是一样,时效一过,只能下次请求时,服务器自动颁发一张新的身份证给你。
注意2: 客户端收到的Cookie都是 resp.addCookie (Cookie)、换句话说服务器给客户端的Cookie都需要自己写代码给客户端,而客户端Cookie会自动给服务器,客户无需任何动作
注意3: Cookie的键值对不能有空格符,非要有空格必须将其进行转码。
1.1.1 Cookie在B/S的流程图
Cookie流程图
1.1.2 Cookie类、缺点
此是 javax.servlet.http.Cookie,不是 java.net.HttpCookie;
HttpServletRequest.getCookies() → 得到请求报文中的所有Cookies
HttpServletResponese.addCoooke( Coookie ) → 将Cookie放入回复报文上
1.1.3 代码测试
@WebServlet(urlPatterns = {"/CookieTest.do"})
public class CookieTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie ck_name = new Cookie("name","lrc");
Cookie ck_year = new Cookie("year","18");
ck_name.setDomain("localhost"); // 满足1:域名是localhost
ck_year.setDomain("localhost");
ck_name.setPath("/"); // 满足2:地址栏 localhost/* 客户端就可以发送cookie给服务器
ck_year.setPath("/JavaWeb_learning"); // 地址栏 localhost/JavaWeb_learning/* 客户端就会发送Cookie给服务器
ck_name.setMaxAge(240); // Cookie在客户端的存活时间4分钟
ck_year.setMaxAge(240);
resp.addCookie(ck_name); // 将Cookie放置在 返回报文 给客户端
resp.addCookie(ck_year);
PrintWriter pw = resp.getWriter();
pw.write("<h1>A new Cooking is being retured to the client</h1>");
pw.flush();
pw.close();
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
}
}
运行上述代码测试步骤
-
Tomcat服务器已经加载了两个应用程序
-
地址栏输入:http://localhost:8080/JavaWeb_learning/CookieTest.do – 生成Cookie给客户端
-
地址栏输入这几个地址:localhost:8080、localhost:8080/任意层级域名 – 都没有出现year这个Cookie
-
地址栏输入:http://localhost:8080/JavaWeb_learning – 只有匹配URL:localhost/JavaWeb_learning/* 才会将year Cookie给服务器
1.2 Session - 数据写给服务器
1. 依然使用了Cookie、不过只用Cookie的话,会把大量的状态信息存到客户端主机上,而使用Cookie-Session结合,客户端只需要存储SessionID就可以了,大量的状态信息存在服务器Session这个内存空间上,减少了HTTP请求携带大量的用户状态Cookie信息
2. 服务器只要新生成Session,则自动会将sessionID发送给客户端
3. 浏览器关闭则客户端的Cookie-SessionID自动删除,但服务器的session并没有销魂
1.2.1 Session在B/S的流程图
1.2.2 Session类
生成HttpSession对象: HttpServletRequest.getSession()
1.2.3 Session失效时间设置
服务器级session配置
项目级session配置
代码级session配置
1.2.4 代码测试
@WebServlet (urlPatterns = {"/cookie.do"})
public class TestCookie1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 如果客户端请求中没有sessionID,服务器会自动创建一个新的session,并且将新的sessionID给客户端
req.getSession();
}
}
第一次请求 – 请求报文中没有sessionID
第二次请求 – 客户端自动将sessionID给服务器
第三次请求 – 浏览器关闭(或者换个浏览器),打开新浏览器 → 上次的sessionID(Cookie)已经被删除,服务器重新发送新的sessionID,但服务器原来的session并没有删除
1.3 URL重写
背景: 客户端禁用Cookie,导致不能存储sessionID,所以只能通过后台程序员给请求的URL进行补充sessionID,或者客户端人员自己手动在地址栏补充sessionID ---- 即增加会话标识
超链接、表单的action、重定向地址 都必须重写URL(JSP页面) ---- 静态html页面不可以动态重写
注意: 请求报文中有sessionID则使用请求中的sessionID,即使地址栏你手动拼接了另一个sessionID,则依然使用请求报文中的sessionID。
1.3.1 URL重写方法
1.3.2 代码测试
servlet代码 - TestCookie1.java
@WebServlet (urlPatterns = {"/cookie.do"})
public class TestCookie1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
HttpSession hs = req.getSession();
hs.setAttribute("sessionID", hs.getId());
hs.setAttribute("用户", "小明");
}
}
jsp代码 - TestSession.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String scheme = request.getScheme();
String server = request.getServerName();
int port = request.getServerPort();
String project = request.getContextPath();
String base = scheme + "://" + server + ":" + port + project + "/";
%>
<!DOCTYPE html>
<html>
<head>
<base href="<%=base%>">
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
sessionID:<%= session.getAttribute("sessionID") %>
<br>
用户名:<%= session.getAttribute("用户") %>
</body>
</html>
未禁用Cookie时
禁用Cookie时
1.3.2.1 客户端地址栏手动输入sessionID
1.3.2.2 encodeRedirectURL(String)=encodeURL(String) - 自动填充sessionID
重定向引用的时上面的jsp页面
@WebServlet (urlPatterns = {"/cookie.do"})
public class TestCookie1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
HttpSession hs = req.getSession();
hs.setAttribute("sessionID", hs.getId());
hs.setAttribute("用户", "小明");
resp.sendRedirect("/JavaWeb_servlet/TestSession.jsp"); // ①
// String bringSessionPath = resp.encodeRedirectURL("/JavaWeb_servlet/TestSession.jsp"); // ②
// resp.sendRedirect( bringSessionPath ); // ③
}
}
运行①代码 - 请求localhost:8080/cookie.do
运行②③代码、注释①代码 - 请求localhost:8080/cookie.do
1.4 隐藏的表单域 - 利用标签存储session
背景:浏览器禁用Cookie,可以在给客户端的每个JSP页面保存一个进行存储sessionID
1.4.1 时序过程图
1.4.2 代码示例
文件结构
hiddenForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String scheme = request.getScheme(); // http
String server = request.getServerName(); // localhost
int port = request.getServerPort(); // 8080
String project = request.getContextPath(); // /项目名
String base = scheme + "://" + server + ":" + port + project + "/"; // http://localhost:8080/homework/
%>
<!DOCTYPE html>
<html>
<head>
<base href="<%=base%>">
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
HttpSession hs = request.getSession();
String sessionID = hs.getId();
hs.setAttribute("user", "小明");
hs.setAttribute("password", "123456");
%>
<form action="./cookie.do" method="post">
<input type="hidden" name="sessionID" value="<%= sessionID %>">
</form>
<a href="">重定向到用户信息页面</a>
</body>
<script>
var a = document.getElementsByTagName("a")[0];
var form = document.getElementsByTagName("form")[0];
a.onclick = function() {
form.submit();
return false; // 取消a标签默认行为
}
</script>
</html>
TestCoookie1.java
@WebServlet (urlPatterns = {"/cookie.do"})
public class TestCookie1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
String sessionID = req.getParameter("sessionID");
resp.sendRedirect("/JavaWeb_servlet/message.jsp" + ";jsessionid=" + sessionID);
}
}
message.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String scheme = request.getScheme(); // http
String server = request.getServerName(); // localhost
int port = request.getServerPort(); // 8080
String project = request.getContextPath(); // /项目名
String base = scheme + "://" + server + ":" + port + project + "/"; // http://localhost:8080/homework/
%>
<!DOCTYPE html>
<html>
<head>
<base href="<%=base%>">
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
用户:<%= session.getAttribute("user")%>
密码:<%= session.getAttribute("password") %>
<form method="post">
<input type="hidden" name="sessionID" value="<%= session.getId() %>" >
</form>
</body>
</html>
运行结果图: