Servlet第六篇【Session介绍、API、生命周期、应用、与Cookie区别】

什么是Session

Session 是另外一种记录浏览器状态的机制。不一样的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录在服务器,这就是Session

若是说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是经过检查服务器上的”客户明细表“来确认用户的身份的。Session至关于在服务器中创建了一份“客户明细表”。javascript

为何要使用Session技术?

Session比Cookie使用方便,Session能够解决Cookie解决不了的事情【Session能够存储对象,Cookie只能存储字符串。】。html

Session API

  • long getCreationTime();【获取Session被建立时间】
  • String getId();【获取Session的id】
  • long getLastAccessedTime();【返回Session最后活跃的时间】
  • ServletContext getServletContext();【获取ServletContext对象】
  • void setMaxInactiveInterval(int var1);【设置Session超时时间】
  • int getMaxInactiveInterval();【获取Session超时时间】
  • Object getAttribute(String var1);【获取Session属性
  • Enumeration<String> getAttributeNames();【获取Session全部的属性名】
  • void setAttribute(String var1, Object var2);【设置Session属性】
  • void removeAttribute(String var1);【移除Session属性】
  • void invalidate();【销毁该Session】
  • boolean isNew();【该Session是否为新的】

Session做为域对象

从上面的API看出,Session有着request和ServletContext相似的方法。其实Session也是一个域对象。Session做为一种记录浏览器状态的机制,只要Session对象没有被销毁,Servlet之间就能够经过Session对象实现通信java

  • 咱们来试试吧,在Servlet4中设置Session属性
//获得Session对象
        HttpSession httpSession = request.getSession();
        
        //设置Session属性
        httpSession.setAttribute("name", "看完博客就要点赞!!");
  • 在Servlet5中获取到Session存进去的属性
//获取到从Servlet4的Session存进去的值
        HttpSession httpSession = request.getSession();
        String value = (String) httpSession.getAttribute("name");
        System.out.println(value);
  • 访问Servlet4,再访问Servlet5

  • 通常来说,当咱们要存进的是用户级别的数据就用Session,那什么是用户级别呢?只要浏览器不关闭,但愿数据还在,就使用Session来保存

Session的生命周期和有效期

  • Session在用户第一次访问服务器Servlet,jsp等动态资源就会被自动建立,Session对象保存在内存里,这也就为何上面的例子能够直接使用request对象获取获得Session对象
  • 若是访问HTML,IMAGE等静态资源Session不会被建立。
  • Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,不管是否对Session进行读写,服务器都会认为Session活跃了一次
  • 因为会有愈来愈多的用户访问服务器,所以Session也会愈来愈多。为了防止内存溢出,服务器会把长时间没有活跃的Session从内存中删除,这个时间也就是Session的超时时间
  • Session的超时时间默认是30分钟,有三种方式能够对Session的超时时间进行修改
  • 第一种方式:在tomcat/conf/web.xml文件中设置,时间值为20分钟,全部的WEB应用都有效
<session-config>
                <session-timeout>20</session-timeout>
            </session-config>

  • 第二种方式:在单个的web.xml文件中设置,对单个web应用有效,若是有冲突,以本身的web应用为准
<session-config>
                <session-timeout>20</session-timeout>
            </session-config>
  • 第三种方式:经过setMaxInactiveInterval()方法设置
//设置Session最长超时时间为60秒,这里的单位是秒
        httpSession.setMaxInactiveInterval(60);

        System.out.println(httpSession.getMaxInactiveInterval());

  • Session的有效期与Cookie的是不一样的


使用Session完成简单的购物功能

  • 咱们仍是以书籍为例,因此能够copy“显示浏览过的商品“例子部分的代码。
response.setContentType("text/html;charset=UTF-8");
        PrintWriter printWriter = response.getWriter();

        printWriter.write("网页上全部的书籍:" + "<br/>");

        //拿到数据库全部的书
        LinkedHashMap<String, Book> linkedHashMap = DB.getAll();
        Set<Map.Entry<String, Book>> entry = linkedHashMap.entrySet();

        //显示全部的书到网页上
        for (Map.Entry<String, Book> stringBookEntry : entry) {

            Book book = stringBookEntry.getValue();

            String url = "/ouzicheng/Servlet6?id=" + book.getId();
            printWriter.write(book.getName());
            printWriter.write("<a href='" + url + "'>购买</a>");
            printWriter.write("<br/>");
        }
  • 在购物车页面上,获取到用户想买的书籍【用户可能不单想买一本书,因而乎,就用一个List容器装载书籍】,有了:先遍历Cookie,再判断是不是第一次访问Servlet的逻辑思路,咱们就能够先获取到Session的属性,若是Session的属性为null,那么就是尚未该属性
//获得用户想买书籍的id
        String id = request.getParameter("id");

        //根据书籍的id找到用户想买的书
        Book book = (Book) DB.getAll().get(id);

        //获取到Session对象
        HttpSession httpSession = request.getSession();

        //因为用户可能想买多本书的,因此咱们用一个容器装着书籍
        List list = (List) httpSession.getAttribute("list");
        if (list == null) {
            
            list = new ArrayList();
            
            //设置Session属性
            httpSession.setAttribute("list",list);
        }
        //把书籍加入到list集合中
        list.add(book);
  • 按咱们正常的逻辑思路:先建立一个ArrayList对象,把书加到list集合中,而后设置Session的属性。这样是行不通的。每次Servlet被访问的时候都会建立一个ArrayList集合,书籍会被分发到不一样的ArrayList中去。因此下面的代码是不行的!
//获得用户想买书籍的id
        String id = request.getParameter("id");

        //根据书籍的id找到用户想买的书
        Book book = (Book) DB.getAll().get(id);

        //获取到Session对象
        HttpSession httpSession = request.getSession();

        //建立List集合
        List list = new ArrayList();
        list.add(book);

        httpSession.setAttribute("list", list);
  • 既然用户已经购买了书籍,那么也应该给提供页面显示用户购买过哪些书籍
//获得用户想买书籍的id
        String id = request.getParameter("id");

        //根据书籍的id找到用户想买的书
        Book book = (Book) DB.getAll().get(id);

        //获取到Session对象
        HttpSession httpSession = request.getSession();

        //因为用户可能想买多本书的,因此咱们用一个容器装着书籍
        List list = (List) httpSession.getAttribute("list");
        if (list == null) {

            list = new ArrayList();

            //设置Session属性
            httpSession.setAttribute("list",list);
        }
        //把书籍加入到list集合中
        list.add(book);

        String url = "/ouzicheng/Servlet7";
        response.sendRedirect(url);
  • 列出用户购买过的书籍
//要获得用户购买过哪些书籍,获得Session的属性遍历便可
        HttpSession httpSession = request.getSession();
        List<Book> list = (List) httpSession.getAttribute("list");

        if (list == null || list.size() == 0) {
            printWriter.write("对不起,你尚未买过任何商品");

        } else {
            printWriter.write("您购买过如下商品:");
            printWriter.write("<br/>");
            for (Book book : list) {
                printWriter.write(book.getName());
                printWriter.write("<br/>");
            }
        }
  • 效果以下


Session的实现原理

  • 用现象说明问题,我在Servlet4中的代码设置了Session的属性
//获得Session对象
        HttpSession httpSession = request.getSession();

        //设置Session属性
        httpSession.setAttribute("name", "看完博客就要点赞!!");
  • 接着在Servlet7把Session的属性取出来
String value = (String) request.getSession().getAttribute("name");

        printWriter.write(value);
  • 天然地,咱们能取到在Servlet4中Session设置的属性

  • 接着,我在浏览器中新建一个会话,再次访问Servlet7

  • 发现报了空指针异常的错误

  • 如今问题来了:服务器是如何实现一个session为一个用户浏览器服务的?换个说法:为何服务器可以为不一样的用户浏览器提供不一样session?
  • HTTP协议是无状态的,Session不能依据HTTP链接来判断是否为同一个用户。因而乎:服务器向用户浏览器发送了一个名为JESSIONID的Cookie,它的值是Session的id值。其实Session依据Cookie来识别是不是同一个用户。
  • 简单来讲:Session 之因此能够识别不一样的用户,依靠的就是Cookie
  • 该Cookie是服务器自动颁发给浏览器的,不用咱们手工建立的。该Cookie的maxAge值默认是-1,也就是说仅当前浏览器使用,不将该Cookie存在硬盘中
  • 咱们来捋一捋思路流程:当咱们访问Servlet4的时候,服务器就会建立一个Session对象,执行咱们的程序代码,并自动颁发个Cookie给用户浏览器

  • 当咱们用同一个浏览器访问Servlet7的时候,浏览器会把Cookie的值经过http协议带过去给服务器,服务器就知道用哪一Session

  • 而当咱们使用新会话的浏览器访问Servlet7的时候该新浏览器并无Cookie,服务器没法辨认使用哪个Session,因此就获取不到值

浏览器禁用了Cookie,Session还能用吗?

上面说了Session是依靠Cookie来识别用户浏览器的。若是个人用户浏览器禁用了Cookie了呢?绝大多数的手机浏览器都不支持Cookie,那个人Session怎么办?web

  • 好的,咱们来看看状况是怎么样的。用户浏览器访问Servlet4的时候,服务器向用户浏览器颁发了一个Cookie

  • 可是呢,当用户浏览器访问Servlet7的时候,因为咱们禁用了Cookie,因此用户浏览器并无把Cookie带过去给服务器

  • 一看,Session好像不能用了。可是Java Web提供了解决方法:URL地址重写
  • HttpServletResponse类提供了两个URL地址重写的方法:数据库

    • encodeURL(String url)
    • encodeRedirectURL(String url)
  • 须要值得注意的是:这两个方法会自动判断该浏览器是否支持Cookie,若是支持Cookie,重写后的URL地址就不会带有jsessionid了【固然了,即便浏览器支持Cookie,第一次输出URL地址的时候仍是会出现jsessionid(由于没有任何Cookie可带)】
  • 下面咱们就以上面“购物”的例子来作试验吧!首先咱们来看看禁用掉Cookie对原来的小例子有什么影响
  • 访问Servlet1,随便点击一本书籍购买

  • 不管点击多少次,都会直接提示咱们有买过任何商品

  • 缘由也很是简单,没有Cookie传递给服务器,服务器每次建立的时候都是新的Session,致使最后获取到的List集合必定是空的。
  • 不一样Servlet获取到的Session的id号都是不一样的

  • 下面咱们就对URL进行重写,看看能不能恢复没有禁掉Cookie以前的效果。
  • 原则:把Session的属性带过去【传递给】另一个Servlet,都要URL地址重写
  • 在跳转到显示购买过商品的Servlet的时候,URL地址重写。
String url = "/ouzicheng/Servlet7";

        response.sendRedirect(response.encodeURL(url));
  • 再次访问Servlet1,当我点击javaweb的时候,已经可以成功出现我买过的商品了。而且Session的id经过URL地址重写,使用的是同一个Session

  • URL地址重写的原理:将Session的id信息重写到URL地址中服务器解析重写后URL,获取Session的id。这样一来,即便浏览器禁用掉了Cookie,但Session的id经过服务器端传递,仍是可使用Session来记录用户的状态。

Session禁用Cookie

  • Java Web规范支持经过配置禁用Cookie
  • 禁用本身项目的Cookie跨域

    • 在META-INF文件夹下的context.xml文件中修改(没有则建立)
![](http://i.imgur.com/Szu5o1m.png)

```xml

        <?xml version='1.0' encoding='utf-8'?>
        
        <Context path="/ouzicheng" cookies="false">
        </Context>
```
  • 禁用所有web应用的Cookie浏览器

    • 在conf/context.xml中修改
![](http://i.imgur.com/dFrvztb.png)

注意:该配置只是让服务器不能自动维护名为jsessionid的Cookie,并不能阻止Cookie的读写。缓存


Session案例

使用Session完成用户简单登录

  • 先建立User类
private String username = null;
    private String password = null;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    ....各类set、get方法
  • 使用简单的集合模拟一个数据库
private static List<User> list = new ArrayList<>();

    //装载些数据进数据库
    static {

        list.add(new User("aaa","111"));
        list.add(new User("bbb","222"));
        list.add(new User("ccc","333"));
    }

    //经过用户名和密码查找用户
    public static User find(String username, String password) {

        for (User user : list) {
            if (user.getUsername().equals(username) && user.getPassword().equals(password)) {
                
                return user;
            }
        }
        
        return null;
    }
  • 表单提交的工做我就在jsp写了,若是在Servlet写太麻烦了!
<form action="/ouzicheng/LoginServlet" method="post">
    用户名:<input type="text" name="username"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="submit" value="提交">

</form>
  • 获取到表单提交的数据,查找数据库是否有相对应的用户名和密码。若是没有就提示用户名或密码出错了,若是有就跳转到另一个页面
String username = request.getParameter("username");
        String password = request.getParameter("password");

        User user = UserDB.find(username, password);

        //若是找不到,就是用户名或密码出错了。
        if (user == null) {
            response.getWriter().write("you can't login");
            return;
        }

        //标记着该用户已经登录了!
        HttpSession httpSession = request.getSession();
        httpSession.setAttribute("user", user);

        //跳转到其余页面,告诉用户成功登录了。
        response.sendRedirect(response.encodeURL("index.jsp"));
  • 咱们来试试下数据库没有的用户名和密码,提示我不能登录。

  • 试试数据库存在的用户名和密码


利用Session防止表单重复提交

  • 重复提交的危害:tomcat

    • 在投票的网页上不停地提交,实现了刷票的效果。
    • 注册多个用户,不断发帖子,扰乱正常发帖秩序。
  • 首先咱们来看一下常见的重复提交。安全

    • 在处理表单的Servlet中刷新。
    • 后退再提交
    • 网络延迟,屡次点击提交按钮
  • 下面的gif是后退再提交在处理提交请求的Servlet中刷新

  • 下面的gif是网络延迟,屡次点击提交按钮

  • 对于网络延迟形成的屡次提交数据给服务器,实际上是客户端的问题。因而,咱们可使用javaScript来防止这种状况
  • 要作的事情也很是简单:当用户第一次点击提交按钮时,把数据提交给服务器。当用户再次点击提交按钮时,就不把数据提交给服务器了。
  • 监听用户提交事件。只能让用户提交一次表单!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>表单提交</title>

    <script type="text/javascript">

        //定义一个全局标识量:是否已经提交过表单数据
        var isCommitted = false;

        function doSubmit() {

            //false表示的是没有提交过,因而就可让表单提交给Servlet
            if(isCommitted==false) {

                isCommitted = true;
                return true;
            }else {
                return false;
            }
        }
    </script>
</head>
<body>

<form action="/ouzicheng/Servlet7" onsubmit="return doSubmit()">

    用户名:<input type="text" name="username">
    <input type="submit" value="提交">
</form>

</body>
</html>
  • 好的,咱们来试一下是否是真的能够解决网络延迟所形成的屡次提交表单数据,注意鼠标,我已经点击过不少次的了!

  • 因为网络延迟形成的屡次提交数据给服务器,咱们还可使用javaScript代码这样解决:当我点击过一次提交按钮时,我就把提交的按钮隐藏起来。不能让用户点击了
  • 想要让按钮隐藏起来,也很简单。只要获取到按钮的节点,就能够控制按钮的隐藏或显示了!
<script type="text/javascript">
        function doSubmit() {
            var button = document.getElementById("button");

            button.disabled = disabled;

            return true;
        }
    </script>
  • 咱们再来看一下效果

  • 在处理表单的Servlet中刷新后退再提交这两种方式不能只靠客户端来限制了。也就是说javaScript代码没法阻止这两种状况的发生。
  • 因而乎,咱们就想得用其余办法来阻止表单数据重复提交了。咱们如今学了Session,Session能够用来标识一个用户是否登录了。Session的原理也说了:不一样的用户浏览器会拥有不一样的Session。而request和ServletContext为何就不行呢?request的域对象只能是一次http请求提交表单数据的时候request域对象的数据取不出来。ServletContext表明整个web应用,若是有几个用户浏览器同时访问ServletContext域对象的数据会被屡次覆盖掉,也就是说域对象的数据就毫无心义了。
  • 可能到这里,咱们会想到:在提交数据的时候,存进Session域对象的数据,在处理提交数据的Servlet中判断Session域对象数据????。究竟判断Session什么?判断Session域对象的数据不为null?没用呀,既然已经提交过来了,那确定不为null。
  • 此时,咱们就想到了,在表单中还有一个隐藏域,能够经过隐藏域把数据交给服务器

    • 判断Session域对象的数据和jsp隐藏域提交的数据是否对应
    • 判断隐藏域的数据是否为空【若是为空,就是直接访问表单处理页面的Servlet
    • 判断Session的数据是否为空【servlet判断完是否重复提交,最好能立马移除Session的数据,否则尚未移除的时候,客户端那边儿的请求又来了,就又能匹配了,产生了重复提交。若是Session域对象数据为空,证实已经提交过数据了!
  • 咱们向Session域对象的存入数据到底是什么呢?简单的一个数字?好像也行啊。由于只要Session域对象的数据和jsp隐藏域带过去的数据对得上号就好了呀,反正在Servlet上判断完是否重复提交,会立马把Session的数据移除掉的。更专业的作法是:向Session域对象存入的数据是一个随机数【Token--令牌】。
  • 生成一个独一无二的随机数
/*
* 产生随机数就应该用一个对象来生成,这样能够避免随机数的重复。
* 因此设计成单例
* */
public class TokenProcessor {


    private TokenProcessor() {
    }

    private final static TokenProcessor TOKEN_PROCESSOR = new TokenProcessor();

    public static TokenProcessor getInstance() {
        return TOKEN_PROCESSOR;
    }


    public static String makeToken() {


        //这个随机生成出来的Token的长度是不肯定的
        String token = String.valueOf(System.currentTimeMillis() + new Random().nextInt(99999999));

        try {
            //咱们想要随机数的长度一致,就要获取到数据指纹
            MessageDigest messageDigest = MessageDigest.getInstance("md5");
            byte[] md5 = messageDigest.digest(token.getBytes());

            //若是咱们直接 return  new String(md5)出去,获得的随机数会乱码。
            //由于随机数是任意的01010101010,在转换成字符串的时候,会查gb2312的码表,gb2312码表不必定支持该二进制数据,获得的就是乱码
            
            //因而乎通过base64编码成了明文的数据
            BASE64Encoder base64Encoder = new BASE64Encoder();
            return base64Encoder.encode(md5);

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return null;

    }

}
  • 建立Token随机数,并跳转到jsp页面
//生出随机数
        TokenProcessor tokenProcessor = TokenProcessor.getInstance();
        String token = tokenProcessor.makeToken();

        //将随机数存进Session中
        request.getSession().setAttribute("token", token);

        //跳转到显示页面
        request.getRequestDispatcher("/login.jsp").forward(request, response);
  • jsp隐藏域获取到Session的值
<form action="/ouzicheng/Servlet7" >

    用户名:<input type="text" name="username">
    <input type="submit" value="提交" id="button">

    <%--使用EL表达式取出session中的Token--%>
    <input type="hidden" name="token" value="${token}" >

</form>
  • 在处理表单提交页面中判断:jsp隐藏域是否有值带过来,Session中的值是否为空,Session中的值和jsp隐藏域带过来的值是否相等
String serverValue = (String) request.getSession().getAttribute("token");
        String clientValue = request.getParameter("token");

        if (serverValue != null && clientValue != null && serverValue.equals(clientValue)) {

            System.out.println("处理请求");

            //清除Session域对象数据
            request.getSession().removeAttribute("token");

        }else {

            System.out.println("请不要重复提交数据!");
        }
  • 下面咱们再来看一下,已经能够解决表单重复提交的问题了!

实现原理是很是简单的:

  • 在session域中存储一个token
  • 而后前台页面的隐藏域获取获得这个token
  • 在第一次访问的时候,咱们就判断seesion有没有值,若是有就比对。对比正确后咱们就处理请求,接着就把session存储的数据给删除了
  • 等到再次访问的时候,咱们session就没有值了,就不受理前台的请求了!

一次性校验码

  • 一次性校验码其实就是为了防止暴力猜想密码
  • 在讲response对象的时候,咱们使用response对象输出过验证码,可是没有去验证!
  • 验证的原理也很是简单:生成验证码后,把验证码的数据存进Session域对象中,判断用户输入验证码是否和Session域对象的数据一致
  • 生成验证码图片,并将验证码存进Session域中
//在内存中生成图片
        BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);

        //获取到这张图片
        Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();

        //设置背景色为白色
        graphics2D.setColor(Color.white);
        graphics2D.fillRect(0, 0, 80, 20);

        //设置图片的字体和颜色
        graphics2D.setFont(new Font(null, Font.BOLD, 20));
        graphics2D.setColor(Color.BLUE);

        //生成随机数
        String randomNum = makeNum();

        //往这张图片上写数据,横坐标是0,纵坐标是20
        graphics2D.drawString(randomNum, 0, 20);

        //将随机数存进Session域中
        request.getSession().setAttribute("randomNum", randomNum);

        //控制浏览器不缓存该图片
        response.setHeader("Expires", "-1");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        //通知浏览器以图片的方式打开
        response.setHeader("Content-type", "image/jpeg");

        //把图片写给浏览器
        ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
  • 生成随机数的方法:
private String makeNum() {

        Random random = new Random();

        //生成0-6位的随机数
        int num = random.nextInt(999999);

        //验证码的数位全都要6位数,因而将该随机数转换成字符串,不够位数就添加
        String randomNum = String.valueOf(num);

        //使用StringBuffer来拼凑字符串
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < 6 - randomNum.length(); i++) {
            stringBuffer.append("0");
        }

        return stringBuffer.append(randomNum).toString();


    }
  • jsp显示页面
<form action="/ouzicheng/Login2Servlet">

    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    验证码:<input type="text" name="randomNum">
    <img src="/ouzicheng/ImageServlet" ><br><br>

    <input type="submit" value="提交">

</form>
  • 处理提交表单数据的Servlet,判断用户带过来验证码的数据是否和Session的数据相同。
//获取用户输入验证码的数据
        String client_randomNum = request.getParameter("randomNum");

        //获取Session中的数据
        String session_randomNum = (String) request.getSession().getAttribute("randomNum");

        //判断他俩数据是否相等,用户是否有输入验证码,Session中是否为空
        if (client_randomNum == null || session_randomNum == null || !client_randomNum.equals(session_randomNum)) {
            System.out.println("验证码错误了!!!");
            return ;
        }

        //下面就是验证用户名和密码...................
  • 显示页面是这样子的

  • 咱们来看一下效果!

对于校验码实现思路是这样子的:

  • 使用awt语法来描写一张验证码,生成随机数保存在seesion域中,咱们让验证码不能缓存起来【作到验证码都不同】
  • 页面直接访问Servlet来获取咱们的验证码,因而咱们验证码的值就会改变【同时session的值也会被改变】
  • 当用户验证的时候,就是session内的值的验证了。

Session和Cookie的区别

  • 从存储方式上比较

    • Cookie只能存储字符串,若是要存储非ASCII字符串还要对其编码。
    • Session能够存储任何类型的数据,能够把Session当作是一个容器
  • 从隐私安全上比较

    • Cookie存储在浏览器中,对客户端是可见的。信息容易泄露出去。若是使用Cookie,最好将Cookie加密
    • Session存储在服务器上,对客户端是透明的。不存在敏感信息泄露问题。
  • 从有效期上比较

    • Cookie保存在硬盘中,只须要设置maxAge属性为比较大的正整数,即便关闭浏览器,Cookie仍是存在的
    • Session的保存在服务器中,设置maxInactiveInterval属性值来肯定Session的有效期。而且Session依赖于名为JSESSIONID的Cookie,该Cookie默认的maxAge属性为-1。若是关闭了浏览器,该Session虽然没有从服务器中消亡,但也就失效了。
  • 从对服务器的负担比较

    • Session是保存在服务器的,每一个用户都会产生一个Session,若是是并发访问的用户很是多,是不能使用Session的,Session会消耗大量的内存。
    • Cookie是保存在客户端的。不占用服务器的资源。像baidu、Sina这样的大型网站,通常都是使用Cookie来进行会话跟踪。
  • 从浏览器的支持上比较

    • 若是浏览器禁用了Cookie,那么Cookie是无用的了!
    • 若是浏览器禁用了Cookie,Session能够经过URL地址重写来进行会话跟踪。
  • 从跨域名上比较

    • Cookie能够设置domain属性来实现跨域名
    • Session只在当前的域名内有效,不可夸域名

Cookie和Session共同使用

  • 若是仅仅使用Cookie或仅仅使用Session可能达不到理想的效果。这时应该尝试一下同时使用Session和Cookie
  • 那么,何时才须要同时使用Cookie和Session呢?
  • 在上一篇博客中,咱们使用了Session来进行简单的购物,功能也的确实现了。如今有一个问题:我在购物的途中,不当心关闭了浏览器。当我再返回进去浏览器的时候,发现我购买过的商品记录都没了!!为何会没了呢?缘由也很是简单:服务器为Session自动维护的Cookie的maxAge属性默认是-1的,当浏览器关闭掉了,该Cookie就自动消亡了。当用户再次访问的时候,已经不是原来的Cookie了。
  • 咱们如今想的是:即便我不当心关闭了浏览器了,我从新进去网站,我还能找到个人购买记录
  • 要实现该功能也十分简单,问题其实就在:服务器为Session自动维护的Cookie的maxAge属性是-1,Cookie没有保存在硬盘中。我如今要作的就是:把Cookie保存在硬盘中,即便我关闭了浏览器,浏览器再次访问页面的时候,能够带上Cookie,从而服务器识别出Session。
  • 第一种方式:只须要在处理购买页面上建立Cookie,Cookie的值是Session的id返回给浏览器便可
Cookie cookie = new Cookie("JSESSIONID",session.getId());
        cookie.setMaxAge(30*60);
        cookie.setPath("/ouzicheng/");
        response.addCookie(cookie);
  • 第二种方式: 在server.xml文件中配置,将每一个用户的Session在服务器关闭的时候序列化到硬盘或数据库上保存。但此方法不经常使用,知道便可!
  • 下面看一下效果


若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章的同窗,能够关注微信公众号:Java3y
相关文章
相关标签/搜索