我们从打开浏览器到关闭浏览器属于一次会话,从开始选购商品到支付也称为一次会话,在这个过程中会产生很多的数据,我们需要保存产生的数据,前提是不会保存在数据库中,那么究竟是怎么保存会话中产生的数据呢?这就是本文将要深入学习的问题。
会话管理的根本性问题:怎么管理会话中产生的数据,前提是不使用数据库。
使用域对象,域对象就是实现资源之间的数据共享。使用session域对象来保存会话数据。
目前会话技术只有两种,分别是:
Cookie技术的特点是会话数据保存在浏览器客户端,其核心就在一个类中,该类就是Cookie类,学号这个类就学好了Cookie技术,Cookie类用于存储会话数据。
Cookie(String name , String value);
void setPath(String uri); //设置Cookie的有效访问路径
void setMaxAge(int expiry); //设置Cookie的有效时间
void setValue(String newValue); //设置Cookie的值
//在HttpServletResponse中存在下面的方法
void response.addCookie(Cookie cookie); //避免手动发送Cookie信息
//在HttpServletRequest中存在下面的方法
Cookie[] request.getCookies(); //接收cookie
服务器创建一个Cookie对象,然后将会话数据存储到Cookie中
服务器会发送Cookie的信息到浏览器
浏览器得到服务器发送的Cookie,然后保存在浏览器端
浏览器下次访问服务器时,会带着Cookie信息
服务器会接收到浏览器带来的Cookie信息
package com.jpzhutech.cookie_test;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CookieDemo1 extends HttpServlet {
/**
* The doGet method of the servlet.
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1. 创建Cookie对象
Cookie cookie1 = new Cookie("name","eric");
Cookie cookie2 = new Cookie("email", "[email protected]");
//2. 把Cookie的数据发送到浏览器,通过响应头set-cookie发送
//response.setHeader("set-cookie", "name=eric,[email protected]"); //需要自己去拼接,建议使用addCookie()方法
response.addCookie(cookie1);
response.addCookie(cookie2);
/** 查看响应头信息,发现Cookie信息已经保存到浏览器端
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: name=eric
Set-Cookie: email="[email protected]"; Version=1
Content-Length: 0
Date: Thu, 08 Sep 2016 08:16:32 GMT
*/
//3. 接受浏览器发送的Cookie信息
//String header = request.getHeader("cookie"); //这种方法得到的信息还得自己去拆分
//System.out.println(header);
Cookie[] cookies = request.getCookies(); //服务器拿到浏览器带来的Cookie信息
if(cookies != null){
for(Cookie c:cookies){
String name = c.getName();
String value = c.getValue();
System.out.println(name+"="+value);
}
}
}
}
package com.jpzhutech.cookie_test;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CookieDemo1 extends HttpServlet {
/**
* The doGet method of the servlet.
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1. 创建Cookie对象
Cookie cookie1 = new Cookie("name","eric");
Cookie cookie2 = new Cookie("email", "[email protected]");
//设置Cookie的有效路径,默认情况:有效路径在当前web应用下
cookie2.setPath("/jpzhu"); //当我们访问http://localhost:8080/Cookie_Test/CookieDemo1时不会看到cookie2的任何信息,这就是所谓的访问路径
//2. 把Cookie的数据发送到浏览器,通过响应头set-cookie发送
//response.setHeader("set-cookie", "name=eric,[email protected]"); //需要自己去拼接,建议使用addCookie()方法
response.addCookie(cookie1);
response.addCookie(cookie2);
/** 查看响应头信息,发现Cookie信息已经保存到浏览器端
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: name=eric
Set-Cookie: email="[email protected]"; Version=1
Content-Length: 0
Date: Thu, 08 Sep 2016 08:16:32 GMT
*/
//3. 接受浏览器发送的Cookie信息
//String header = request.getHeader("cookie"); //这种方法得到的信息还得自己去拆分
//System.out.println(header);
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie c:cookies){
String name = c.getName();
String value = c.getValue();
System.out.println(name+"="+value);
}
}
}
}
package com.jpzhutech.cookie_test;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CookieDemo1 extends HttpServlet {
/**
* The doGet method of the servlet.
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1. 创建Cookie对象
Cookie cookie1 = new Cookie("name","eric");
Cookie cookie2 = new Cookie("email", "[email protected]");
//设置Cookie的有效路径,默认情况:有效路径在当前web应用下
cookie2.setPath("/jpzhu"); //当我们访问http://localhost:8080/Cookie_Test/CookieDemo1时不会看到cookie2的任何信息,这就是所谓的访问路径
//设置Cookie的有效时间
//cookie1.setMaxAge(20); // 20代表的是20s,此时Cookie信息只会保存20s,正整数时间只要不超过指定的时间,尽管你关闭了浏览器,重启浏览器还是能访问到该Cookie信息
//cookie1.setMaxAge(-1); //保存在浏览器内存中,当浏览器关闭时,Cookie数据就会消失,只要不关闭浏览器,任何时间都能获取到该Cookie信息,这种Cookie也叫作会话Cookie
cookie1.setMaxAge(0); //意味着删除同名的Cookie数据
//2. 把Cookie的数据发送到浏览器,通过响应头set-cookie发送
//response.setHeader("set-cookie", "name=eric,[email protected]"); //需要自己去拼接,建议使用addCookie()方法
response.addCookie(cookie1);
response.addCookie(cookie2);
/** 查看响应头信息,发现Cookie信息已经保存到浏览器端
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: name=eric
Set-Cookie: email="[email protected]"; Version=1
Content-Length: 0
Date: Thu, 08 Sep 2016 08:16:32 GMT
*/
//3. 接受浏览器发送的Cookie信息
//String header = request.getHeader("cookie"); //这种方法得到的信息还得自己去拆分
//System.out.println(header);
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie c:cookies){
String name = c.getName();
String value = c.getValue();
System.out.println(name+"="+value);
}
}
}
}
案例一:显示用户上次访问的时间,具体的要求是:当我们首次登陆该网站时,显示:”您首次访问该网站,时间为:…”,当您第n次访问该网站时,显示:”欢迎您再次访问该网站,您上次访问的时间为:…,本次访问时间为:…” ,我们肯定是将访问的时间保存在Cookie域对象中,并且在拿到数据时,要能精细的操作访问时间。
//注意在测试该端代码之前,一定要加上Servlet的jar包
package com.jpzhutech.cookie;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.mail.internet.NewsAddress;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CookieDemo2 extends HttpServlet {
/**
* The doGet method of the servlet.
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
//用户上次访问时间cookie联系
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8"); //设置响应能显示中文
//获取系统时间
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String currentTime = format.format(new Date());
//首先确定第一次访问,或者是没有Cookie或者是没有名字为LastTime的Cookie
Cookie[] cookies = request.getCookies();
String LastTime = null; //用来存储访问的时间,如果开始检查cookie数组发现其中有内容,说明不是第一次访问
if(cookies != null){
for(Cookie cookie : cookies){
if(cookie.getName().equals("LastTime")){
//有LastTime的cookie,已经是第n次访问该网站
LastTime = cookie.getValue();
//第n次访问
response.getWriter().write("欢迎回来,你上次访问的时间是:"+LastTime+" 当前时间是:"+currentTime);
//更新Cookie数据
cookie.setValue(currentTime);
cookie.setMaxAge(1*30*24*3600);
//将更新后的Cookie发送到浏览器
response.addCookie(cookie);
break;
}
}
}
if(cookies == null || LastTime==null){
//显示当前时间到浏览器
response.getWriter().write("你是首次访问本网站,当前时间是:"+currentTime);
//创建一个Cookie对象
Cookie cookie = new Cookie("LastTime", currentTime);
cookie.setMaxAge(1*30*24*3600);
response.addCookie(cookie); //写入cookie
}
}
/**
* 测试结果为:你是首次访问本网站,当前时间是:2016-09-08 07:45:52
* 欢迎回来,你上次访问的时间是:2016-09-08 07:45:52 当前时间是:2016-09-08 07:45:54
* 当你关闭浏览器之后还是可以访问到保存到硬盘中的Cookie信息
*/
}
案例二:显示用户最近浏览过的商品,基本需求是:用户会进入商品列表具体去查看某一商品的详细信息,当我们再次打开该网站时,会显示改用户之前浏览过的商品,第一次进入网站时,没有浏览过商品,不进行显示,当查看过商品之后就会显示详情信息,要求显示的商品不能超过三个,并且最后浏览的商品应该放在最前面。
代码见附件中。
Session技术和Cookie技术本质是一样的,都是为了保存会话数据,那么我们已经学习了Cookie技术,为什么还需要Session技术呢?原因是:Cookie技术存在局限性,因为Cookie技术只能保存字符串,并且只能存储英文字符,数据的容量不能超过4KB,Cookie也能被浏览器清楚,出于上面种种的限制,我们需要改进Cookie技术,此时我们只能使用Session技术。Session技术的特点是:会话数据保存在服务器端(具体是保存到服务器宿主机的内存中)。
学习Session其实就是学习一个HttpSession类,但是我们发现HttpSession其实是一个接口,所有的Session相关的方法都在HttpServletRequest中,按照下面的步骤学习:
//在HttpServletRequest中存在下面的函数
HttpSession getSession(); //创建Session对象,并给Session对象分配一个唯一的ID,叫作JSESSIONID,并把JSESSIONID作为Cookie的值发送给浏览器保存,第二次访问的时候,浏览器会带着JSESSIONID的Cookie访问服务器,服务器得到JSESSIONID,会在服务器的内存中搜索是否存在对应编号的Session对象,如果找到对应编号的Session对象,直接返回该对象,如果找不到对应编号的Session对象,创建新的Session,然后递归的重复上述的步骤。
HttpSession getSession(boolean create);
void SetMaxInactivInterval(int interval); //设置Session对象的有效时间
void invalidate(); //销毁Session对象
String getId(); // 得到Session的编号
void setAttribute(String name, String value); //保存会话数据的方法
Object getAttribute(); //共享域对象
void removeAttribute(String name); //清楚域对象Session
package com.jpzhutech.session;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class SessionDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到Session对象
HttpSession session = request.getSession();
//保存会话数据
session.setAttribute("name", "rose");
}
}
package com.jpzhutech.session;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class SessionDemo2 extends HttpServlet {
/***
* 保存会员数据到Session域对象
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//创建Session对象
HttpSession session = request.getSession();
//取出数据
String attribute = (String) session.getAttribute("name");
System.out.println("name="+attribute);
}
}
部署上述的项目并启动tomcat,首先在浏览器中启动SessionDemo1,然后再启动SessionDemo2,接着在控制台就看到了输出的结果。
在测试时出现了下述的现象,现象描述:
在哪个Session域对象保存数据,就必须从哪个域对象取出会话数据,具体原因的解释参见Session技术原理部分,结论:通过JSESSIONID在服务器中找对应的Session。
String getId(); //得到Session编号
void getSession(true); //创建或者得到Session对象,没有匹配的Session编号,自动创建Session编号,默认情况下是该种情况
void getSession(false); //得到Session对象,没有匹配的Session,不会自动的创建Session,而是返回null
默认情况下30分钟后服务器自动回收,那么我们可以自己设置时间吗?可以,采用下面的两种方法:
void SetMaxInactivInterval(int interval);
还可以直接在web.xml文件中增加配置修改,所有的Session都直接配置好。
<session-config>
<session-timeout>1session-timeout>
session-config>
void invalidate(); //销毁Session对象
案例:实现用户登录注册功能,首先我们需要写一个登陆的页面,之后会要求我们输入用户名和密码,提交之后就到后台去处理,后台使用Servlet去接收,查询数据库,判断是否存在该用户名和密码,存在话登陆成功,不存在的话登陆失败。如果失败的话就跳转到失败的页面,如果成功的话就去到主页,成功的主页我用Servlet来实现,显示欢迎回来某某某,我们需要从会话信息中得到用户的名字并且显示出来。
package com.jpzhutech.loginservlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginServlet extends HttpServlet {
/**
* The doGet method of the servlet.
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
//1. 接收参数
String userName = request.getParameter("username");
String userPassword = request.getParameter("userpassword");
//2. 判断逻辑,采用硬编码而不是去查询数据库,真实的场景应该是去数据库中做查询
if("eric".equals(userName) && "123456".equals(userPassword)){
//登录成功
//将用户数据保存到session对象中
HttpSession session = request.getSession();
//将数据保存到session对象中
session.setAttribute("loginName", userName);
//跳转到用户主页
response.sendRedirect(request.getContextPath()+"/IndexServlet");
}else{
//登录失败,重定向到失败页面
response.sendRedirect(request.getContextPath()+"/fail.html");
}
}
/**
* The doPost method of the servlet.
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
package com.jpzhutech.loginservlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class IndexServlet extends HttpServlet {
/**
* The doGet method of the servlet.
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
//接收request数据
HttpSession session = request.getSession();
if(session == null){
//没有登录成功,跳转到登录页面
response.sendRedirect(request.getContextPath()+"/LoginServlet");
return;
}
//取出会话数据
String userName = (String) session.getAttribute("loginName");
//检查是否执行到该步骤
//System.out.println("哈哈,欢迎回来");
String html = "";
html = "欢迎回来,"+userName+"" ;
writer.write(html);
}
/**
* The doPost method of the servlet.
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
<--- login.html---->
<html>
<head>
<meta name="content-type" content="text/html; charset=utf8">
<title>登录页面title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
head>
<body>
<form action="/Login/LoginServlet" method="post">
用户名:<input type="text" name="username" />
<br/>
密码:<input type="password" name="userpassword" />
<br/>
<input type="submit" value="登录" />
form>
body>
html>
<html>
<head>
<meta name="content-type" content="text/html; charset=utf8">
<title>信息提示页面title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
head>
<body>
<font color='red'>亲,你的用户名或密码错误,请重新输入!font>
<a href="/Login/login.html">返回登录页面a>
body>
html>