一 会话跟踪
1 HTTP 无状态
HTTP 协议是无状态的,一问一答没有记忆,无法确定发出请求的用户身份。即各个请求的请求对象所包含的信息并不相同,一个会话中的多个请求之间无法共享数据,此时可以使用会话跟踪技术
2 会话跟踪技术
Cookie 客户端会话跟踪技术
Session 服务端会话跟踪技术(HttpSession)
3 案例
① 创建web项目,添加对应jar包(JSTL)
② login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="/http/login" method="post">
<p>账号:<input type="text" name="username"></p>
<p>密码:<input type="password" name="password"></p>
<p><input type="submit" value="登录"></p>
</form>
</body>
</html>
③ LoginServlet.java
package http;
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.io.IOException;
@WebServlet("/http/login")
public class LoginServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
if("admin".equals(username)&&"123".equals(password)){//登录成功
req.setAttribute("username",username);
req.getRequestDispatcher("/index.jsp").forward(req,resp);
}
}
}
④ index.jsp
<%--新建index.jsp,显示当前登录的用户名及提供点击查看收件箱--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
</head>
<body>
欢迎:${username} <br/>
<a href="/http/list">收件箱</a>
</body>
</html>
⑤ ListServlet.java
@WebServlet("/http/list")
public class ListServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
req.setAttribute("username",username);
/*查询邮件列表信息*/
List<String> list=new ArrayList<>();
list.add("邮件一");
list.add("邮件二");
list.add("邮件三");
req.setAttribute("list",list);
req.getRequestDispatcher("/list.jsp").forward(req,resp);
}
}
⑥ list.jsp
<%--显示当前用户名及其邮件,提供查询邮件内容--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>邮件列表</title>
</head>
<body>
欢迎:${username} <br/>
<c:forEach items="${list}" var="email">
<a href="/http/content">${email}</a> <br/>
</c:forEach>
</body>
</html>
⑦ ContentServlet.java
@WebServlet("/http/content")
public class ContentServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
req.setAttribute("username",username);
//跳转到详情页
req.getRequestDispatcher("/content.jsp").forward(req,resp);
}
}
⑧ content.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>邮件详情页</title>
</head>
<body>
<p>当前登录账号:${username}</p>
<p>这是邮件详情页面</p>
</body>
</html>
二 Cookie
1 概述
Cookie(客户端技术)程序把各个用户的数据以 cookie 的形式写给用户各自的浏览器。(服务器创建Cookie存到客户端浏览器)当用户使用浏览器访问服务器中的 Web 资源时(再次访问服务器时实现数据共享),就会带着各自的数据到服务器。Web 资源此时处理的是用户各自的数据。
传递方向:浏览器 -> 服务器(Cookie)-> 浏览器(存入)-> 服务器(获取Cookie 数据)
2 创建 Cookie 对象
Cookie cookie = new Cookie (String name, String value)
属性 | 方法 | 描述 |
---|---|---|
name | getName() | 共享数据名称(唯一) |
value | getValue() | 要共享的数据 |
3 响应 Cookie 给浏览器
// 使用响应对象中的 addCookie(Cookie 对象) 将数据响应给浏览器
resp.addCookie(cookie);
4 服务器端获取 Cookie
// 浏览器发请求时,自动将 Cookie 发送到服务器,服务器程序直接获取即可。
// 数据在请求中,使用请求对象中的 getCookies() 方法获取所有的 Cookie 对象。
Cookie[] cookies = request对象.getCookies();
5 修改 Cookie 数据
// 调用 Cookie 对象的 setValue 方法来覆盖原本的数据,或者重新创建一个同 name 的 Cookie 对象
cookie对象.setValue("大黄");
// 无论哪种方式,修改的都是服务器端内存中的 Cookie 数据,和浏览器中存的 Cookie 没有关系,所以需要重新响应新的 Cookie 到浏览器中进行更新。
resp.addCookie(新的Cookie对象);
6 Cookie 分类
Cookie 总是保存在客户端中,按在客户端中的存储位置,可分为内存 Cookie 和硬盘 Cookie。
内存 Cookie 由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。硬盘
Cookie 保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘 Cookie 不会被删
除,其存在时间是长期的。所以,按存在时间,可分为非持久 Cookie 和持久 Cookie。
默认情况下 Cookie 属于会话 Cookie,即浏览器关闭则失效,无法使用。
7 设置 Cookie 存活时间
// 在创建 Cookie 对象之后给其设置存活时间
Cookie对象.setMaxAge(int time);
expiry 数值 | 例子 | 含义 |
---|---|---|
大于 0 | setMaxAge(60) | Cookie 存活时间单位为秒 |
等于 0 | setMaxAge(0) | 立即删除当前 Cookie 对象 |
小于 0 | setMaxAge(-1) | 会话 Cookie,浏览器关闭则销毁 |
8 删除 Cookie
// 设置 Cookie 存活时间的方法即可进行删除,一般是中途删除 Cookie,不是创建后马上删除,所以在设置删除之后需要重新发送给浏览器去更新删除
Cookie对象.setMaxAge(0);
resp.addCookie(Cookie 对象);
9 例子
① login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="/cookie/login" method="post">
<p>账号:<input type="text" name="username"></p>
<p>密码:<input type="password" name="password"></p>
<p><input type="submit" value="登录"></p>
</form>
</body>
</html>
② LoginServlet
@WebServlet("/cookie/login")
public class LoginServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
if("admin".equals(username)&&"123".equals(password)){//登录成功
/*登录成功将账号保存到客户端cookie*/
/*name共享数据名称(唯一) value要共享的数据*/
/*new Cookie (String name, String value)*/
Cookie cookie=new Cookie("username",username);
Cookie cookie1=new Cookie("username","小黄");
cookie.setValue("大黄");
//设置有效时间
cookie.setMaxAge(120);
//设置路径
cookie.setPath("/");
resp.addCookie(cookie);
resp.addCookie(cookie1);
req.setAttribute("username",username);
req.getRequestDispatcher("/index.jsp").forward(req,resp);
}
}
}
③ index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
</head>
<body>
欢迎:${username} <br/>
<a href="/cookie/list">收件箱</a>
</body>
</html>
④ ListServlet
@WebServlet("/cookie/list")
public class ListServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*获取cookie信息*/
Cookie[] cookies = req.getCookies();
if (cookies!=null){
for (Cookie cookie : cookies) {
// 获取账号的cookie
if (cookie.getName().equals("username")){
// 删除cookie
cookie.setMaxAge(0);
resp.addCookie(cookie);
String username = cookie.getValue();
// 将账号存储到作用域
req.setAttribute("username",username);
}
}
}
/*查询邮件列表信息*/
List<String> list = new ArrayList<>();
list.add("邮件一");
list.add("邮件二");
list.add("邮件三");
req.setAttribute("list", list);
req.getRequestDispatcher("/list.jsp").forward(req, resp);
}
}
⑤ list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>邮件列表</title>
</head>
<body>
欢迎:${username} <br/>
<p>当前登录账号:${cookie.username.value}</p>
<c:forEach items="${list}" var="email">
<a href="/cookie/content">${email}</a> <br/>
</c:forEach>
</body>
</html>
⑥ ContentServlet
@WebServlet("/cookie/content")
public class ContentServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*获取cookie信息*/
Cookie[] cookies = req.getCookies();
if (cookies!=null){
for (Cookie cookie : cookies) {
//获取账号的cookie
if (cookie.getName().equals("username")){
String username = cookie.getValue();
//将账号存储到作用域
req.setAttribute("username",username);
}
}
}
//跳转到详情页
req.getRequestDispatcher("/content.jsp").forward(req,resp);
}
}
⑦ content.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>邮件详情页</title>
</head>
<body>
<p>当前登录账号:${username}</p>
<p>这是邮件详情页面</p>
</body>
</html>
10 Cookie 的域和路径
① 作用
使浏览器能够识别 Cookie 发送给对应的服务器,以及识别哪些请求需要携带 Cookie
默认Cookie 都带了服务器的识别标识以及需要带 Cookie 的资源标识,保护Cookie 中的数据不被带到其他服务器中去。
② 域
识别服务器,包含 IP:端口或域名:端口,可通过 Cookie 对象的 setDomain 方法设置。默认Cookie 中的域是创建 Cookie 的服务器的域名。域名分类:
一级(主)域名:bilibili.com
多级域名:news.bilibili.com
若想要在相同的主域名下来共享 Cookies 数据,例如,扣扣空间,扣扣音乐共用账号,则只需要
设置 Cookie 的 domain 即可。若主域不同,是无法共享 Cookie 数据。
cookie.setDomain(".bilibili.com");
③ 路径
识别资源,可通过 Cookie 对象的 setPath 方法设置。默认为创建 Cookie 的资源的路径。
例:/cookie/login 创建 Cookie,则 path 为 /cookie,则访问 /cookie 开头的资源都会携带该Cookie。
若想要在访问服务器上的任意资源都带上 Cookie,则只需要在创建 Cookie 之后设置下 path 为 / 即可。
cookie.setPath("/");
④ 小结
若主域不同,不管 path 如何,都无法带上其他主域的 Cookie。
若主域相同,且 path 也为 /,则访问该域下的任意资源都会携带该域的 Cookie。
三 Session
1 概述
Session 是服务器端技术(服务器创建,存在服务器),服务器运行时可为每个用户的浏览器创建一个其独享的 session 对象
用户在访问服务器的 Web 资源时,可以把各自的数据放在各自的 session 中,当用户再去访问服务器中的其它 Web 资源时(再次访问服务器时实现数据共享),其它 Web 资源再从用户各自的 session 中取出数据为用户服务。(通过sessionId识别不同的浏览器用户)
Session 底层依赖 Cookie 来传递 Session 的 id 值。所以浏览器关闭后 Session 就无法使用了(sessionId 丢失)。服务器会在 30 分钟内清除无操作的 Session 对象。存 sessionId 的 Cookie 为会话Cookie。
2 方法
① 获取session(HttpServletRequest的API)
方法 | 作用 |
---|---|
getSession(true) | 判断是否存在 Session,存在则获取,不存在则创建新 Session 对象返回 |
getSession(false) | 判断是否存在 Session,存在则获取,不存在则返回 null |
getSession() | 存在则获取,不存在则创建新 Session 对象返回 |
② 数据共享(HttpSession的API)
方法 | 作用 |
---|---|
setAttribute(String name, Object value) | 设置属性名和属性值 |
getAttribute(String name) | 通过属性名去获取属性值 |
removeAttribute(String name) | 从 Session 中移除指定属性名的属性值 |
invalidate() | 移除整个 Session 对象,删除所有的属性和属性值 |
3 例子
① login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="/session/login" method="post">
<p>账号:<input type="text" name="username"></p>
<p>密码:<input type="password" name="password"></p>
<p><input type="submit" value="登录"></p>
</form>
</body>
</html>
② LoginServlet
@WebServlet("/session/login")
public class LoginServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
if("admin".equals(username)&&"123".equals(password)){//登录成功
//账号存储session
HttpSession session = req.getSession();
//获取sessionid
String id = session.getId();
System.out.println(id);
//设置超时时间
session.setMaxInactiveInterval(60*5);
session.setAttribute("username",username);
req.getRequestDispatcher("/index.jsp").forward(req,resp);
}
}
}
③ index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
</head>
<body>
欢迎:${username} <br/>
<a href="/session/list">收件箱</a>
</body>
</html>
④ ListServlet
@WebServlet("/session/list")
public class ListServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*查询邮件列表信息*/
List<String> list=new ArrayList<>();
list.add("邮件一");
list.add("邮件二");
list.add("邮件三");
req.setAttribute("list",list);
// 从Session中获取数据
System.out.println(req.getSession().getAttribute("username"));
req.getRequestDispatcher("/list.jsp").forward(req,resp);
}
}
⑤ list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>邮件列表</title>
</head>
<body>
欢迎:${username} <br/>
<p>当前登录账号:${sessionScope.username}</p>
<c:forEach items="${list}" var="email">
<a href="/session/content">${email}</a> <br/>
</c:forEach>
</body>
</html>
⑥ ContentServlet
@WebServlet("/session/content")
public class ContentServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 从session中获取数据
System.out.println(req.getSession().getAttribute("username"));
//跳转到详情页
req.getRequestDispatcher("/content.jsp").forward(req,resp);
}
}
⑦ content.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>邮件详情页</title>
</head>
<body>
<p>当前登录账号:${username}</p>
<p>这是邮件详情页面</p>
</body>
</html>