Cookie和Session会话管理基础

Cookie和Session会话管理基础


      • Cookie和Session会话管理基础
        • 概述
        • 问题定义
        • 解决方案
        • 会话技术
          • 会话技术分类
          • Cookie技术
            • Cookie技术原理
            • Cookie技术使用实例
            • Cookie技术细节
            • Cookie技术实际案例
          • Session技术
            • Session技术原理
            • Session技术使用实例
            • Session技术细节
            • Session技术实际案例


概述


我们从打开浏览器到关闭浏览器属于一次会话,从开始选购商品到支付也称为一次会话,在这个过程中会产生很多的数据,我们需要保存产生的数据,前提是不会保存在数据库中,那么究竟是怎么保存会话中产生的数据呢?这就是本文将要深入学习的问题。

问题定义


会话管理的根本性问题:怎么管理会话中产生的数据,前提是不使用数据库

解决方案


使用域对象,域对象就是实现资源之间的数据共享。使用session域对象来保存会话数据。

会话技术


会话技术分类

目前会话技术只有两种,分别是:

  • Cookie技术:会话数据保存在浏览器客户端
  • Session技术:会话数据保存在服务器端
Cookie技术

Cookie技术的特点是会话数据保存在浏览器客户端,其核心就在一个类中,该类就是Cookie类,学号这个类就学好了Cookie技术,Cookie类用于存储会话数据。

  • 构造Cookie对象
Cookie(String name , String value);
  • 设置Cookie
void setPath(String uri);   //设置Cookie的有效访问路径
void setMaxAge(int expiry);  //设置Cookie的有效时间
void setValue(String newValue); //设置Cookie的值
  • 发送Cookie到浏览器保存
//在HttpServletResponse中存在下面的方法
void response.addCookie(Cookie cookie); //避免手动发送Cookie信息
  • 服务器接收Cookie信息
//在HttpServletRequest中存在下面的方法
Cookie[] request.getCookies();  //接收cookie
Cookie技术原理

  • 服务器创建一个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); } } } }
Cookie技术细节

  • 设置Cookie的有效路径 void setPath(String uri); 其中有效路径是指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]"); //设置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); } } } }
  • 设置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]"); //设置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); } } } }
  • Cookie只能保存非中文的字符串数据类型,可以保存多个Cookie,但是浏览器一般只允许保存300个Cookie信息,每个站点最多存放20个Cookie,每个Cookie的大小限制为4kB。
Cookie技术实际案例

案例一:显示用户上次访问的时间,具体的要求是:当我们首次登陆该网站时,显示:”您首次访问该网站,时间为:…”,当您第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技术

Session技术和Cookie技术本质是一样的,都是为了保存会话数据,那么我们已经学习了Cookie技术,为什么还需要Session技术呢?原因是:Cookie技术存在局限性,因为Cookie技术只能保存字符串,并且只能存储英文字符,数据的容量不能超过4KB,Cookie也能被浏览器清楚,出于上面种种的限制,我们需要改进Cookie技术,此时我们只能使用Session技术。Session技术的特点是:会话数据保存在服务器端(具体是保存到服务器宿主机的内存中)。

Session技术原理

学习Session其实就是学习一个HttpSession类,但是我们发现HttpSession其实是一个接口,所有的Session相关的方法都在HttpServletRequest中,按照下面的步骤学习:

  • 创建或者得到HttpSession的对象
//在HttpServletRequest中存在下面的函数
HttpSession getSession();   //创建Session对象,并给Session对象分配一个唯一的ID,叫作JSESSIONID,并把JSESSIONID作为Cookie的值发送给浏览器保存,第二次访问的时候,浏览器会带着JSESSIONID的Cookie访问服务器,服务器得到JSESSIONID,会在服务器的内存中搜索是否存在对应编号的Session对象,如果找到对应编号的Session对象,直接返回该对象,如果找不到对应编号的Session对象,创建新的Session,然后递归的重复上述的步骤。
HttpSession getSession(boolean create);
  • 设置Session对象
void SetMaxInactivInterval(int interval); //设置Session对象的有效时间
void invalidate();   //销毁Session对象
String getId();   // 得到Session的编号
  • 保存会话数据到Session对象中
void setAttribute(String name, String value);   //保存会话数据的方法
Object getAttribute();   //共享域对象
void removeAttribute(String name);  //清楚域对象Session
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,接着在控制台就看到了输出的结果。

在测试时出现了下述的现象,现象描述:

  • 打开浏览器1:创建Session对象并保存Session会话数据 –保存数据
  • 打开浏览器1的新窗口:得到Session对象的会话数据 –可以取出数据
  • 关闭浏览器1
  • 重新打开浏览器1:得到Session对象数据 –不能取出数据
  • 浏览器2:得到Session的会话数据 –不能取出数据

在哪个Session域对象保存数据,就必须从哪个域对象取出会话数据,具体原因的解释参见Session技术原理部分,结论:通过JSESSIONID在服务器中找对应的Session。

Session技术细节

  • 得到Session编号
String getId();   //得到Session编号
  • 两个getSession方法的原因
void getSession(true);  //创建或者得到Session对象,没有匹配的Session编号,自动创建Session编号,默认情况下是该种情况
void getSession(false);  //得到Session对象,没有匹配的Session,不会自动的创建Session,而是返回null
  • Session对象销毁的时间

默认情况下30分钟后服务器自动回收,那么我们可以自己设置时间吗?可以,采用下面的两种方法:

void SetMaxInactivInterval(int interval);

还可以直接在web.xml文件中增加配置修改,所有的Session都直接配置好。


 
  <session-config>
      <session-timeout>1session-timeout>
  session-config>
  • 手动销毁Session对象
void invalidate();   //销毁Session对象
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>

你可能感兴趣的:(Java)