提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
什么是会话 : 在web开发中的一次通话的过程,当打开浏览器,访问网站地址后,会话开始,当关闭浏览器(或者到了过期时间),会话结束。例如,你在给家人打电话,这时突然有送快递的配送员敲门,你放下电话去开门,收完快递回来后, 通话还在保持中,继续说话就行了。
会话的作用 : 是为我们共享数据用的,并且是在不同请求间实现数据共享。 也就是说,如果我们需要在多次请求间实现数据共享,就可以考虑使用会话管理技术了。例如:在我们的实际开发中,我们在论坛发帖,没有登录的游客 身份是不允许发帖的。所以当我们登录成功后,无论我们进入哪个版块发帖,只要权限允许的情况下, 服务器都会认识我们,从而让我们发帖,因为登录成功的信息一直保留在服务器端的会话中。
会话的分类 :
客户端会话管理技术 它是把要共享的数据保存到了客户端(也就是浏览器端)。每次请求时,把会话信息带到服务器, 从而实现多次请求的数据共享。
服务端会话管理技术 它本质仍是采用客户端会话管理技术,只不过保存到客户端的是一个特殊的标识,并且把要共享的 数据保存到了服务端的内存对象中。每次请求时,把这个标识带到服务器端,然后使用这个标识,找到 对应的内存空间,从而实现数据共享。
首先看一下官方文档的解释:
Creates a cookie, a small amount of information sent by a servlet to a Web browser, saved by the browser, and later sent back to the server. A cookie's value can uniquely identify a client, so cookies are commonly used for session management.
创建一个cookie,这是由servlet发送到Web浏览器的少量信息,由浏览器保存,稍后再发送回服务器。一个cookie的值可以唯一地标识一个客户端,因此cookie通常用于会话管理。
A cookie has a name, a single value, and optional attributes such as a comment, path and domain qualifiers, a maximum age, and a version number. Some Web browsers have bugs in how they handle the optional attributes, so use them sparingly to improve the interoperability of your servlets.
cookie有名称、单个值和可选属性,如注释、路径和域限定符、最大年龄和版本号。一些Web浏览器在处理可选属性方面存在bug,因此要谨慎使用它们以提高servlet的互操作性。
The servlet sends cookies to the browser by using the HttpServletResponse.addCookie(javax.servlet.http.Cookie) method, which adds fields to HTTP response headers to send cookies to the browser, one at a time. The browser is expected to support 20 cookies for each Web server, 300 cookies total, and may limit cookie size to 4 KB each.
servlet通过使用HttpServletResponse.addCookie(javax.servlet.http.Cookie)方法将cookie发送到浏览器,该方法将字段添加到HTTP响应报头中,一次发送一个cookie到浏览器。该浏览器预计将为每个Web服务器支持20个cookie,总共300个cookie,并且可能将每个cookie的大小限制为4 KB。
The browser returns cookies to the servlet by adding fields to HTTP request headers. Cookies can be retrieved from a request by using the HttpServletRequest.getCookies() method. Several cookies might have the same name but different path attributes.
浏览器通过向HTTP请求头添加字段将cookie返回给servlet。cookie可以通过使用HttpServletRequest.getCookies()方法从请求中检索。多个cookie可能具有相同的名称但不同的路径属性。
Cookies affect the caching of the Web pages that use them. HTTP 1.0 does not cache pages that use cookies created with this class. This class does not support the cache control defined with HTTP 1.1.
cookie会影响使用它们的Web页面的缓存。HTTP 1.0不缓存使用此类创建的cookie的页面。这个类不支持用HTTP 1.1定义的缓存控制。
This class supports both the Version 0 (by Netscape) and Version 1 (by RFC 2109) cookie specifications. By default, cookies are created using Version 0 to ensure the best interoperability.
这个类同时支持版本0(由Netscape提供)和版本1(由RFC 2109提供)cookie规范。默认情况下,cookie是使用版本0创建的,以确保最佳互操作性。
总结分析:
Cookie属性
属性名称 | 属性作用 | 是否重要 |
---|---|---|
name | cookie的名称 | 必要 |
value | cookie的值(不能是中文) | 必要 |
path | cookie的路径 | 重要 |
domain | cookie的域名 | 重要 |
maxAge | cookie的生存时间。 | 重要 |
version | cookie的版本号。 | 不重要 |
comment | cookie的说明。 | 不重要 |
注意细节:
Cookie方法
/**
* 通过指定的名称和值构造一个Cookie
*
* Cookie的名称必须遵循RFC 2109规范。这就意味着,它只能包含ASCII字母数字字符,
* 不能包含逗号、分号或空格或以$字符开头。
* 创建后无法更改cookie的名称。
*
* 该值可以是服务器选择发送的任何内容。
* 它的价值可能只有服务器才感兴趣。
* 创建之后,可以使用setValue方法更改cookie的值。
*/
Cookie(String name , String value);
/**
* 添加Cookie到响应中。此方法可以多次调用,用以添加多个Cookie。
*/
public void addCookie(Cookie cookie);
/**
* 这是HttpServletRequest中的方法。
* 它返回一个Cookie的数组,包含客户端随此请求发送的所有Cookie对象。
* 如果没有符合规则的cookie,则此方法返回null。
*/
public Cookie[] getCookies();
代码演示
/**
* 设置值
*/
@WebServlet("/demo01")
public class ServletDemo01 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 创建Cookie对象
Cookie cookie = new Cookie("test", "helloWord");
// 添加
response.addCookie(cookie);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
/**
* 获取值
*/
@WebServlet("/demo02")
public class ServletDemo02 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取
Cookie[] cookies = request.getCookies();
if (cookies.length > 0){
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
System.out.println("name = " + name);
System.out.println("value = " + value);
System.out.println("----------");
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
限制值 : Cookie 的值不能包含逗号、分号、空格,不能以$开头。
存活的时间 : 默认情况下,浏览器关闭默认销毁
-1 : 当前会话有效,浏览器关闭则清除
0 : 立即清除
正数 : 以秒为单位设置存活时间
代码演示
/**
* Cookie相关设置
* ①存活时长限制
*/
@WebServlet("/demo03")
public class ServletDemo03 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie("msg2","helloworld2");
//设置cookie存活时长=24小时
//-1 : 默认值, 会话结束就销毁
//0 : 立即销毁
//正数 : 存活多少秒
cookie.setMaxAge(24 * 60 * 60);
response.addCookie(cookie);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
访问路径限制 :
访问哪些资源时携带Cookie,默认值是"/项目名称"
"/项目名/目录名/资源名",访问路径完全匹配上"/项目名/目录名/资源名"才会携带cookie
比如 : "/web15/xyz/index.html" , 只有"/web15/xyz/index.html"才会携带cookie
"/项目名/目录名",访问路径前面匹配上"/项目名/目录名"就会携带cookie
比如:"/web15/xyz","/web15/xyz/index.html"、"/web15/xyz/demo01.html"都会携带Cookie
开发步骤 :
代码演示
/**
* Cookie手动销毁
*/
@WebServlet("/demo04")
public class ServletDemo04 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置相同name
Cookie cookie = new Cookie("test","helloword");
//设置相同path
cookie.setPath("/day16");
//立即销毁
cookie.setMaxAge(0);
//发送cookie到浏览器
response.addCookie(cookie);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
案例描述
显示商品的浏览记录
操作步骤:
web.xml配置前缀后缀视图
<context-param>
<param-name>view-prefixparam-name>
<param-value>/WEB-INF/pages/param-value>
context-param>
<context-param>
<param-name>view-suffixparam-name>
<param-value>.htmlparam-value>
context-param>
创建创建index.html、shop.html、history.html文件用来显示首页、商品列表、历史记录
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页title>
<base th:href="@{/}">
head>
<body>
<a th:href="@{demo04(method=toShopPage)}">查看商品a>
<a th:href="@{demo04(method=showHistory)}">查看历史记录a>
<a th:href="@{demo04(method=clearHistory)}">清空历史记录a>
body>
html>
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<base th:href="@{/}">
<title>商品列表title>
head>
<body>
<a th:href="@{demo04(method=addHistory,id=0)}">红楼梦a> <br>
<a th:href="@{demo04(method=addHistory,id=1)}">水浒传a> <br>
<a th:href="@{demo04(method=addHistory,id=2)}">西游记a> <br>
<a th:href="@{demo04(method=addHistory,id=3)}">三国演义a> <br>
body>
html>
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>历史记录title>
head>
<body>
<ul>
<li th:each="item : ${list}" th:text="${item}">li>
ul>
body>
html>
定义IndexServlet跳转至首页显示
@WebServlet("/index.html")
public class IndexServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 跳转页面
processTemplate("index",req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
定义HistoryServlet编写功能代码
@WebServlet("/demo04")
public class ServletDemo04 extends ModelBaseServlet {
// 跳转到shop页面
public void toShopPage(HttpServletRequest request, HttpServletResponse response) throws Exception{
processTemplate("shop",request,response);
}
// 跳转到history页面
public void toHistoryPage(HttpServletRequest request, HttpServletResponse response) throws Exception{
processTemplate("history",request,response);
}
// 添加记录方法
public void addHistory(HttpServletRequest request, HttpServletResponse response)throws Exception{
String id = request.getParameter("id");
Cookie historyCookie = null;
// 判断是否第一次添加
Cookie[] cookies = request.getCookies();
if (null != cookies && 0 != cookies.length){
for (Cookie cookie : cookies) {
if ("history".equals(cookie.getName())){
historyCookie = cookie;
}
}
}
if (historyCookie == null){
// 第一次创建
Cookie history = new Cookie("history", id);
// 添加到浏览其中
response.addCookie(history);
}else {
// 不是第一次添加
// 判断是否已经存在该值
// 1.获取值
String value = historyCookie.getValue();
if (!value.contains(id)){
value = value + "-" + id;
// 2.设置新值
Cookie history = new Cookie("history", value);
response.addCookie(history);
}
}
response.sendRedirect(request.getContextPath()+"/demo04?method=showHistory");
}
/**
* 访问历史记录
* @param request
* @param response
*/
public void showHistory(HttpServletRequest request, HttpServletResponse response) throws Exception{
Cookie[] cookies = request.getCookies();
String[] bookname = {"红楼梦","水浒传","西游记","三国演义"};
Cookie historyCookie = null;
if (cookies.length != 0 && cookies != null){
for (Cookie cookie : cookies) {
if ("history".equals(cookie.getName())){
historyCookie = cookie;
}
}
}
ArrayList<String> list = new ArrayList<>();
if (historyCookie != null){
String value = historyCookie.getValue();
String[] split = value.split("-");
for (String s : split) {
list.add(bookname[Integer.parseInt(s)]);
}
}
request.setAttribute("list",list);
processTemplate("history",request,response);
}
/**
* 清空历史记录
* @param request
* @param response
* @throws Exception
*/
public void clearHistory(HttpServletRequest request, HttpServletResponse response) throws Exception {
Cookie history = new Cookie("history", "");
history.setMaxAge(0);
history.setPath("/day16");
response.addCookie(history);
response.sendRedirect(request.getContextPath() + "/index.html");
}
}
首先看看官方解释:
Provides a way to identify a user across more than one page request or visit to a Web site and to store information about that user.
提供一种方法,用于跨多个页面请求或对Web站点的访问识别用户,并存储关于该用户的信息。
The servlet container uses this interface to create a session between an HTTP client and an HTTP server. The session persists for a specified time period, across more than one connection or page request from the user. A session usually corresponds to one user, who may visit a site many times. The server can maintain a session in many ways such as using cookies or rewriting URLs.
servlet容器使用这个接口在HTTP客户机和HTTP服务器之间创建会话。会话在指定的时间段内持续存在,跨越来自用户的多个连接或页面请求。一个会话通常对应一个用户,该用户可能多次访问一个站点。服务器可以通过多种方式维护会话,比如使用cookie或重写url。
This interface allows servlets to View and manipulate information about a session, such as the session identifier, creation time, and last accessed time Bind objects to sessions, allowing user information to persist across multiple user connections When an application stores an object in or removes an object from a session, the session checks whether the object implements HttpSessionBindingListener. If it does, the servlet notifies the object that it has been bound to or unbound from the session. Notifications are sent after the binding methods complete. For session that are invalidated or expire, notifications are sent after the session has been invalidated or expired.
这个接口允许servlet查看和操作会话的相关信息,如会话标识符、创建时间、最后一次访问时间等将对象绑定到会话,允许用户信息跨多个用户连接持久化当应用程序在会话中存储对象或从会话中删除对象时,会话检查该对象是否实现了HttpSessionBindingListener。如果是,servlet通知对象它已经绑定到会话或从会话取消绑定。在绑定方法完成后发送通知。对于失效或过期的会话,将在会话失效或过期后发送通知。
When container migrates a session between VMs in a distributed container setting, all session attributes implementing the HttpSessionActivationListener interface are notified.
当容器在分布式容器设置中的虚拟机之间迁移会话时,将通知实现httpessionactivationlistener接口的所有会话属性。
A servlet should be able to handle cases in which the client does not choose to join a session, such as when cookies are intentionally turned off. Until the client joins the session, isNew returns true. If the client chooses not to join the session, getSession will return a different session on each request, and isNew will always return true.
servlet应该能够处理客户端不选择加入会话的情况,比如cookie被故意关闭的情况。在客户端加入会话之前,isNew返回true。如果客户端选择不加入会话,getSession将对每个请求返回一个不同的会话,而isNew将始终返回true。
Session information is scoped only to the current web application (ServletContext), so information stored in one context will not be directly visible in another.
会话信息的作用域仅限于当前的web应用程序(ServletContext),因此存储在一个上下文中的信息在另一个上下文中不会直接可见
总结分析:
HttpSession是Servlet规范中提供的一个接口。该接口的实现由Servlet规范的实现提供商提供。我们使用的是 Tomcat服务器,它对Servlet规范进行了实现,所以HttpSession接口的实现由Tomcat提供。该对象用 于提供一种通过多个页面请求或访问网站来标识用户并存储有关该用户的信息的方法。简单说它就是一 个服务端会话对象,用于存储用户的会话数据。 同时,它也是Servlet规范中四大域对象之一的会话域对象。并且它也是用于实现数据共享的。但它与我 们之前讲解的应用域和请求域是有区别的。
三大域对象
域对象 | 作用范围 | 使用场景 |
---|---|---|
ServletContext | 整个引用范围 | 当i项目中需要数据共享时,可以使用此域对象 |
ServletRequest | 当前请求范围 | 在请求或当前请求转发时需要数据共享时,可以使用此对象 |
HttpSession | 会话返回 | 在当前会话范围中实现数据共享。它可以在多次请求中实现数据共享 |
常用方法:
案例: 在请求ServletDemo05这个Servlet时,携带用户名信息,并且把信息保存到会话域中,然后从ServletDemo06这个Servlet中获取登录信息。
代码实现 :
/**
* 设置HttpSession值
*/
@WebServlet("/demo05")
public class ServletDemo05 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 在HttpSession中设置值
HttpSession session = request.getSession();
session.setAttribute("test","helloword");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
/**
* 获取HttpSession值
*/
@WebServlet("/demo06")
public class ServletDemo06 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取HttpSession值
HttpSession session = request.getSession();
Object test = session.getAttribute("test");
System.out.println("test = " + test);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
HttpSession,它虽然是服务端会话管理技术的对象,但它本质仍是一个Cookie。是一个由服务器自动 创建的特殊的Cookie,Cookie的名称就是JSESSIONID,Cookie的值是服务器分配的一个唯一的标识。 当我们使用HttpSession时,浏览器在没有禁用Cookie的情况下,都会把这个Cookie带到服务器端,然 后根据唯一标识去查找对应的HttpSession对象,找到了,我们就可以直接使用了。下图就是我们入门 案例中,HttpSession分配的唯一标识,同学们可以看到两次请求的JSESSIONID的值是一样的
钝化活化的概述
持久化的时机
注意事项
生命周期 : 在web.xml中进行配置
<session-config>
<session-timeout>10session-timeout>
session-config>
HttpSession销毁 : invalidate():立即销毁session
案例描述 : 定义一个网页,模拟登录显示用户名与注销。若登录成功,在当前页面上方显示用户名。注销登录,销毁用户名的操作。
开发步骤:
代码实现 :
login.html
DOCTYPE html >
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录演示title>
<base th:href="@{/}">
head>
<body>
<div>
<span style="font-size: 20px; color:green" th:if="${session.user==null}">
用户名
span>
<span style="font-size: 20px; color:red" th:unless="${session.user==null}" th:text="${session.user}">
用户名
span>
|
<span style="font-size: 20px; color:red" >
<a th:href="@{demo07(method=cancellation)}">注销a>
span>
div>
<form method="get" action="demo07">
<input name="method" value="login" type="hidden">
用户名<input type="text" name="username"><br>
密码<input type="password" name="password"><br>
<button type="submit">登录button>
form>
body>
html>
ServletDemo07.java
@WebServlet("/demo07")
public class ServletDemo07 extends ModelBaseServlet {
/**
* 跳转页面
* @param request
* @param response
* @throws Exception
*/
public void toLoginPage(HttpServletRequest request,HttpServletResponse response) throws Exception{
processTemplate("login",request,response);
}
/**
* 登录演示
* @param request
* @param response
* @throws Exception
*/
public void login(HttpServletRequest request,HttpServletResponse response) throws Exception{
// 获取值
String username = request.getParameter("username");
String password = request.getParameter("password");
// 获取Session对象
HttpSession session = request.getSession();
// 设置假数据,直接登录
if ("root".equals(username)&&"root".equals(password)){
session.setAttribute("user",username);
// 重定向该页面被
response.sendRedirect(request.getContextPath()+"/demo07?method=toLoginPage");
}else {
// 失败转发该页面
toLoginPage(request,response);
}
}
/**
* 注销登录
* @param request
* @param response
* @throws Exception
*/
public void cancellation(HttpServletRequest request,HttpServletResponse response) throws Exception{
// 获取Session对象
HttpSession session = request.getSession();
// 调用立即注销方法
session.invalidate();
// 重定向该页面被
response.sendRedirect(request.getContextPath()+"/demo07?method=toLoginPage");
}
}