声明
文章大部分内容转载自公众号(Java3y),如需转载请关注Java3y公众号联系作者 ;本文已经获得转载声明

 用户开一个浏览器,访问一个网站,只要不关闭该浏览器,不管该用户点击多少个超链接,访问多少资源,直到用户关闭浏览器,整个这个过程我们称为一次会话
 网页之间的交互是通过HTTP协议传输数据的,而Http协议是无状态的协议。无状态的协议是什么意思呢?一旦数据提交完后,浏览器和服务器的连接就会关闭,再次交互的时候需要重新建立新的连接。
 服务器无法确认用户的信息,于是乎,W3C就提出了:给每一个用户都发一个通行证,无论谁访问的时候都需要携带通行证,这样服务器就可以从通行证上确认用户的信息。通行证就是Cookie

Cookie的流程:

 浏览器访问服务器,如果服务器需要记录该用户的状态,就使用response向浏览器发送一个Cookie,浏览器会把Cookie保存起来。当浏览器再次访问服务器的时候,浏览器会把请求的网址连同Cookie一同交给服务器。

Cookie简单使用

//设置response的编码
    response.setContentType("text/html;charset=UTF-8");
//创建Cookie对象,指定名称和值
    Cookie cookie = new Cookie("username", "zhongfucheng");  
//设置Cookie的时间--秒
    cookie.setMaxAge(1000);   
//向浏览器给一个Cookie
    response.addCookie(cookie);
    response.getWriter().write("我已经向浏览器发送了一个Cookie");

Cookie细节

  • 1.Cookie不可跨域名性--可设置
     当我访问baidu的时候,浏览器只会把baidu颁发的Cookie带过去,而不会带上其他网站(域名)的Cookie。
  • 2.Cookie使用Unicode字符时需要对Unicode字符进行编码(比如说中文)
    //Cookie颁发
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter printWriter = response.getWriter();
    String name = "中国";
    //对Unicode字符进行编码
    Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
    cookie.setMaxAge(2000);
    response.addCookie(cookie);
    printWriter.write("我颁发了一个Cookie,值保存的是中文数据");
    //取出Cookie
    Cookie[] cookies = request.getCookies();
    for (int i = 0; cookies != null && i < cookies.length; i++) {
         String name = cookies[i].getName();
         //经过URLEncoding就要URLDecoding
         String value = URLDecoder.decode(cookies[i].getValue(), "UTF-8");
         printWriter.write(name + "------" + value);
    }
  • 3.Cookie有效期
     通过setMaxAge()来设置
    • 如果MaxAge为正数,浏览器会把Cookie写到硬盘中,只要还在MaxAge秒之前,登陆网站时该Cookie就有效【不论关闭了浏览器还是电脑】
    • 如果MaxAge为负数,Cookie是临时性的,仅在本浏览器内有效,关闭浏览器Cookie就失效了,Cookie不会写到硬盘中。Cookie默认值就是-1。这也就为什么在我第一个例子中,如果我没设置Cookie的有效期,在硬盘中就找不到对应的文件。
    • 如果MaxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie对应的方法,把MaxAge设置为0等同于删除Cookie
  • 4.Cookie的修改和删除
     Cookie的存储方式类似Map集合,Cookie的名称相同,通过response添加到浏览器中,会覆盖原来的Cookie。
     删除,修改Cookie时,新建的Cookie除了value、maxAge之外的所有属性都要与原Cookie相同。否则浏览器将视为不同的Cookie,不予覆盖,导致删除修改失败!
    String name = "new news";
    Cookie cookie = new Cookie("county",URLEncoder.encoder(name,"UTF-8"));
    response.addCookie(cookie);

     删除Cookie,把MaxAge设置为0

    String name = "new news";
    Cookie cookie = new Cookie("county",URLEncoder.encoder(name,"UTF-8"));
    cookie.setMaxAge(0);
    response.addCookie(cookie);
  • 5.设置跨域使用
    参考
     实现不同域名之间的互访(一级域名与子域名之间)
    Cookie cookie = new Cookie("name","fish");
    cookie.setMaxAge(1000);
    cookie.setDomain(".zhongfucheng.com");
    response.addCookie(cookie);
    printWriter.write("使用www.zhongfucheng.com域名添加了一个Cookie,只要一级是                                                        zhongfucheng.com即可访问");
  • 6.Cookie的路径
    参考
     设置特定的资源可以使用Cookie
    Cookie cookie = new Cookie("name","fish");
    cookie.setMaxAge(1000);
    cookie.setDomain("/Servlet1");
    response.addCookie(cookie);
    printWriter.write("该Cookie只有Servlet1获取(发给服务器使用)");

Cookie的应用

  • 1.显示用户上次访问时间

 先检查(遍历)所有的Cookie有没有需要的,如果没有则为null表示第一次登录,如果存在则显示后再更新

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    response.setContentType("text/html;chatset=UTF-8");
//获取网页上所有的cookie
    Cookie[] cookies = request.getCookies();
//判断cookie值是否为空
    String cookieValue = null;
    for(int i = 0;cookies != null && i <cookie.length;i++) {
//取得指定的cookie
        if(cookies[i].getName().equals("time")) {
            printWriter.write("你上次登录的时间为:");
            cookieValue = cookies[i].getValue();
            printWriter.write(cookieValue);
            cookies[i].setValue(simpleDateFormat.format(new Date()));
            response.addCookie(cookies[i]);
            break;
        }
    }
//如果Cookie的值是空的,那么就是第一次访问
    if(cookieVaule == null) {
//创建一个Cookie对象,日期为当前时间
        Cookie cookie = new Cookie("time",simpleDateFormat(new Date()));
        cookie.setMaxAge(20000);
        response.addCookie(cookie);
        printWrite.write("你是第一次登录");
    }
  • 显示上次浏览过的商品(比如书本)

 搞一个book类

//搞个对象出来
    private String id;
    private String name;
    private String author;
    public Book(){
    }
    public Book(String id,String name,String author){
        this.id = id;
        this.name = name;
        this.author = author;
    }
    ...get/set方法

 简单的数据库存储结构DB--根据id找书籍(map),删改较多(Linked)

    private static LinkedHashMap<String,Book> linkedHashMap = new LinkedHashMap();
//book的id和商品的id相同
    static {
        linkedHashMap.put("1",new Book("1","javaweb","javaweb-author"));
        linkedHashMap.put("2",new Book("2","ajax","ajax-author"));
        linkedHashMap.put("3",new Book("3","mysql","mysql-author"));
        linkedHashMap.put("4",new Book("4","oracle","oracle-author"));
    }    
    public static LinkedHashMap getAll() {
        return linkedHashMap;
    }

 显示网页上所有的书籍,和浏览记录

    printWriter.write("网页上所有书籍:");
    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();
        printWriter.write("<a href='/ouzicheng/Servlet2?id=" + book.getId() + "''target=_blank' +" + book.getName() + "</a>");
        printWriter.write("<br/>");
    }
//用户点击书籍返回后,在后面显示浏览记录
    printWriter.write("你曾经浏览过的商品");
    Cookie[] cookies = request.getCookies();
    for(int i=0;cookies != null && i<cookies.length;i++) {
        if(cookies[i].getName().equal("bookHistory")) {
            String bookHistory = cookies[i].getValue();
            String[] ids = bookHistory.split("\\_");
            for(String id : ids) {
                Book book = linkedHashMap.get(id);
                printWriter.write(book.getName);
            }
            break;
        }
    }

 Servlet记录用户点击的操作.用户点击了书籍,那么服务器就颁发Cookie给浏览器,记住用户点击了该书籍.服务器遍历request中的Cookie获取记录时分几种情况:
 Cookie的值为null--直接把传入进来的id当做是Cookie的值
 Cookie的值长度有3个了--把排在最后的id去掉,把传进来的id排在最前边
 Cookie的值已经包含有传递进来的id了--把已经包含的id先去掉,再把id排在最前面
 Cookie的值就只有1个或2个--直接把id排在最前边

    String id = request.getParameter("id");
//由于book的id和商品的id是一致的。获取到用户点击的书,DB为前面书本数据的对象,用get取出链表中数据
    Book book = (Book) DB.getAll().get(id);
//输出书的详细信息
    printWriter.write("书的编号是:" + book.getId()+"<br/>");
    printWriter.write("书的名称是:" + book.getName()+"<br/>");
    printWriter.write("书的作者是:" + book.getAuthor()+"<br/>");

//返回浏览器Cookie
//定义Cookie获取的数据--书本的id(格式id1_id2_id3),仅保存三个记录
//先遍历下Cookie,看下有没有我们想要的Cookie。如果找到想要的Cookie,那就取出Cookie的值
    public String makeHistory(HttpServletRequest request,String id) {
        String bookHistory = null;
        Cookie[] cookies = request.getCookies();
        for(int i=0;cookies != null && i<cookies.length;i++) {
            if(cookies[i].getName().equals("bookHistory")) {
                bookHistory = cookies[i].getValue();
            }
        }

//为空表示第一次点击
        if(bookHistory == null) 
            return id;

//否则取出bookHistory中的cookie值(id1_id2_id3)
        String[] strings = bookHistory.split("\\_");
        List list = Arrays.aslist(strings);
        ListedList<String> linkedList = new LinkedList<>();
        linkedList.addAll(list);

//如果cookie中存在新点击的书本id就把它排在开头
        if(linkedList.contains(id){
            linkedList.remove(id);
            linkedList.addFirst(id);
        } else {
//cookie数量超过3个
            if(linkedList.size() >= 3) {
                linkedList.removeLast();
                linkedList.addFirst(id);
            } else {
//其他情况直接在头部添加
                linkedList.addFirst(id);
            }
        }

//拼接Cookie传回浏览器
        StringBuffer stringBuffer = new StringBuffer();
        for(String s:linkedList) {
            stringBuffer.append(s + "_");
        }
//把最后的_去掉
        return stringBuffer.deleteCharAt(stringBuffer.length() - 1).toString();
    }

    String bookHistory = makeHistory(request,id);
    Cookie cookie = new Cookie("bookieHistory",bookHistory);
    cookie.setMaxAge(30000);
    response.addCookie(cookie);