Cookie作为一个客户端技术被广泛的应用着。我今天也来谈一谈我对Cookie的理解。

先来一个小菜(实现“上次登录时间”)


具体的思路如下:

  • 通过request.getCookies()方法找到目标Cookie,然后获取内容
  • 将最新的时间记录存储到Cookie中,并进行更新的操作

    下面是详细的代码:
package cookie;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class MyCookieDemo
 */
@WebServlet("/MyCookieDemo")
public class MyCookieDemo extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public MyCookieDemo() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());

        response.setContentType("text/html;charset=UTF-8");

        PrintWriter writer = response.getWriter();
        writer.write("<br>这是网站首页!<br/><br/>");
        writer.write("您上次的访问时间是:");
        //得到上次访问的时间
        Cookie [] cookies = request.getCookies();
        for(int i=0; cookies!=null&&i<cookies.length;i++){
            Cookie cookie = cookies[i];
            if(cookie.getName().equals("lastAccessTime")){
                Long time = Long.parseLong(cookie.getValue());
                Date date = new Date(time);
                writer.write(date.toLocaleString());

            }
        }

        //给用户以cookie的形式发送更新过的时间
        Cookie cookie = new  Cookie("lastAccessTime",System.currentTimeMillis()+"");
        response.addCookie(cookie);

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

需要注意的是以下问题:

  • 有中文出现时记得使用response.setContentType("text/html;charset=UTF-8");
  • 获得Cookie是获取了一个cookie的数组,我们需要找出符合名字的目标Cookie才能对其进行操作
  • 更新数据需要调用response.addCookie(targetCookie);即可

Cookie实例(显示用户浏览商品记录)


说是商品记录,这里只是一个简单的示意,所以并没有连接数据库进行相关的操作,而是利用一个DB类进行了模拟。下面是我的思路:


商品首页:

  • 首先是要显示网站上所拥有的商品的名称,用户可以通过点击超链接浏览商品的详细的信息
  • 显示用户的商品浏览记录(tongguo cookie 进行实现)

商品的详细的信息界面:

  • 首先是从超链接中获取到用户点击的商品的id,然后通过这个id 来从模拟的数据库中获得商品的详细的信息。
  • 更新用户的商品浏览历史信息(这里发生的情况较为的复杂,详见代码中的注释信息)

下面是代码详情:

首先是WebTitle.java(实际是一个Servlet文件):

package lastskim;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class WebTitle
 */
@WebServlet("/WebTitle")
public class WebTitle extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public WebTitle() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.setContentType("text/html;charset=UTF-8");
        //1.显示所有的商品信息
        PrintWriter out = response.getWriter();
        out.write("本网站有如下商品,任君挑选:"+"<br><br>");

        Set<Map.Entry<String , Item>> set = DB.getItems().entrySet();
        for(Map.Entry<String, Item> me: set){
            Item item = me.getValue();
            out.write("<a href='/ServletStudy/ItemInfo?id="+item.getId()
            +"' target='_blank'>"+item.getName()+"</a>");
            out.write("<br>");
        }

        //2.显示已经浏览过的商品的信息
        out.write("<br>您曾经浏览过的商品的信息如下:<br><br>");
        Cookie [] cookies = request.getCookies();
        for(int i=0 ;cookies!=null && i<cookies.length;i++){
            Cookie cookie = cookies[i];
            if(cookie.getName().equals("itemHistory")){
                String itemHistory = cookie.getValue();
                //使用正则表达式,确保以下划线进行分割!
                String[] ids = itemHistory.split("\\_");
                for(String id : ids){
                    Item item = (Item) DB.getItems().get(id);
                    out.write(item.getName()+"<br>");
                }
            }
        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

//模拟数据库进行加载商品信息
class DB {
    private static Map<String ,Item> map = new LinkedHashMap<String ,Item>();

    //由于需要在初始化的时候进行加载数据,所以在同步的静态的代码块中进行声明即可
    static{
        map.put("1", new Item("1","C语言入门","小郭","19$"));
        map.put("2", new Item("2","C++语言入门","赵老师","21$"));
        map.put("3", new Item("3","Java语言入门","Jemas","32$"));
        map.put("4", new Item("4","JUnit","Juit","12$"));
        map.put("5", new Item("5","PHP","老毛","32$"));
        map.put("6", new Item("6","JavaScript","阿布","27$"));
    }

    public static Map getItems(){
        return map;
    }
}

//模拟的商品Item信息
class Item {
    private String id;
    private String name;
    private String author;
    private String price;

    public Item() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Item(String id, String name, String author, String price) {
        super();
        this.id = id;
        this.name = name;
        this.author = author;
        this.price = price;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }

}

注意:

  • 里面有bean层(item),数据库操作层(DB),和界面显示View层
  • 注意超链接的写法,是服务器内部进行的跳转,所以应该用网站目录进行使用

然后是商品详情界面:

package lastskim;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ItemInfo
 */
@WebServlet("/ItemInfo")
public class ItemInfo extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public ItemInfo() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.setContentType("text/html;charset=UTF-8");
        //1.根据用户带过来的id号,现实上皮的详细的信息
        String id  = request.getParameter("id");
        Item item = (Item) DB.getItems().get(id);

        PrintWriter out = response.getWriter();
        out.write("<br>您所浏览的商品的详细的信息如下:<br>");
        out.write(item.getId()+"<br>");
        out.write(item.getName()+"<br>");
        out.write(item.getAuthor()+"<br>");
        out.write(item.getPrice()+"<br>");

        //2.将更新的cookie信息写回到原来的Cookie中
        String itemHistory = makeItemHistory(request, id);
        Cookie cookie = new Cookie("itemHistory",itemHistory);
        response.addCookie(cookie);
    }

    private String makeItemHistory(HttpServletRequest request, String id) {
        // TODO Auto-generated method stub
        String itemHistory =null;

        Cookie cookies[] = request.getCookies();
        for(int i=0 ;cookies!=null && i<cookies.length;i++){
            if(cookies[i].getName().equals("itemHistory")){
                itemHistory = cookies[i].getValue();
            }
        }

        //一般来说在浏览记录中添加数据呼吁道如下几种情况
        //itemHistory= null         1    itemHistory = 1
        //超过了一页显示的最大个数 :itemHistory= 2_3_4         1    itemHistory = 1_2_3
        //itemHistory= 2_3_4         1    itemHistory = 1_2_3
        //itemHistory= 2_1_4         1    itemHistory = 1_2_4

        //itemHistory= null         1    itemHistory = 1
        if(itemHistory== null){

            return id;
        }

        //这个代码块的作用是分解出一个个的信息,并用于字符串内容的验证
        List l = (List) Arrays.asList(itemHistory.split("\\_"));
        LinkedList<String> list = new LinkedList();
        list.addAll(l);

        if(list.contains(id)){
            list.remove(id);
            list.addFirst(id);
        }else{
            //超过了一页显示的最大个数 :itemHistory= 2_3_4         1    itemHistory = 1_2_3
            if(list.size()>=3){
                list.removeLast();
                list.addFirst(id);
            }else{
                //未超过一页显示的最大个数 :itemHistory= 2_3         1    itemHistory = 1_2_3
                list.addFirst(id);
            }
        }

        StringBuilder sb = new StringBuilder();
        for(String listId : list){
            sb.append(listId+"_");
        }

        return sb.deleteCharAt(sb.length()-1).toString();
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

总结:

  • 含金量第一层就是makeItemHistory方法,其处理了开发中可能遇到的很多的信息。
  • LinkedList的使用是为了判断分解后的元素列表中是否有正在访问的id信息

下面是代码的测试结果:

第一次访问网站:

第一次点击超链接可以看到商品的详细的信息

第二次点击超链接返回后,刷新首页即可看到商品浏览的历史

第三次点击超链接后就达到了商品历史记录的上限

第四次访问后,返回首页,刷新一下,便会将第一次的浏览历史记录去除,添加上最新的浏览记录

在包含有三个历史记录中访问了其中一个,便会更新历史记录的顺序:


总结:

  • Cookie技术应用到的地方很广泛,应该对其进行更加灵活的研究
  • 上述案例应该加上cookie生存期限。否则用户退出后就会清空cookie的历史记录

Cookie 进阶的更多相关文章

  1. javascript 进阶篇1 正则表达式,cookie管理,userData

    首先,什么事正则表达式呢,其实引入概念很多时候并不能帮我们明白它到底是什么,所以我先简单描述下,正则表达式,其实就是一个记录字符串规则则的字符串,等我们看完这一部分,也就能明白它到底是什么了. 基本语 ...

  2. 进阶——scrapy登录豆瓣解决cookie传递问题并爬取用户参加过的同城活动©seven_clear

    最近在用scrapy重写以前的爬虫,由于豆瓣的某些信息要登录后才有权限查看,故要实现登录功能.豆瓣登录偶尔需要输入验证码,这个在以前写的爬虫里解决了验证码的问题,所以只要搞清楚scrapy怎么提交表单 ...

  3. (进阶篇)浅谈COOKIE和SESSION关系和区别

    COOKIE介绍 cookie 常用于识别用户.cookie 是服务器留在用户计算机中的小文件.每当相同的计算机通过浏览器请求页面时,它同时会发送 cookie.通过 PHP,您能够创建并取回 coo ...

  4. (进阶篇)Cookie与 Session使用详解

    1.Cookie和Session简介与区别 在非常多时候,我们需要跟踪浏览者在整个网站的活动,对他们身份进行自动或半自动的识别(也就是平时常说的网站登陆之类的功能),这时候,我们常采用Cookie与 ...

  5. AngularJS进阶(十五)Cookie 'data' possibly not set or overflowed because it was too large

    Cookie 'data' possibly not set or overflowed because it was too large (5287 > 4096 bytes)! 注:请点击此 ...

  6. 性能测试六:jmeter进阶之Cookie与header管理器

    一.http cookie管理器 可以在浏览器中抓取到cookie信息,然后通过http cookie管理器为http请求添加cookie信息 添加cookie管理器后,Jmeter可以自动处理coo ...

  7. Django进阶(路由系统、中间件、缓存、Cookie和Session、Ajax发送数据

    路由系统 1.每个路由规则对应一个view中的函数 url(r'^index/(\d*)', views.index), url(r'^manage/(?P<name>\w*)/(?P&l ...

  8. 【JavaScript-基础-cookie从入门到进阶】

    cookie 关于cookie 用于方便服务端管理客户端状态提出的一种机制. document.cookie 客户端JavaScript可通过document.cookie方式获取非HTTPOnly状 ...

  9. django 2 ORM操作 ORM进阶 cookie和session 中间件

    ORM操作 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,ORM是通过使用描述 ...

随机推荐

  1. (MariaDB/MySQL)之DML(2):数据更新、删除

    本文目录:1.update语句2.delete语句 2.1 单表删除 2.2 多表删除3.truncate table 1.update语句 update用于修改表中记录. # 单表更新语法: UPD ...

  2. 为什么Unix只允许对非目录文件实行勾链?

    Unix文件系统的目录结构中带有交叉勾链,用户可以用不同的文件路径名共享一个文件,即文件的勾链在用户看来是为了一个已存在的文件另起一个路径名.在Unix的多级目录结构中勾链的结果表现为一个文件由多个目 ...

  3. mysql中binlog与存储引擎的2PC

    mysql内部的2PC mysql开启binlog后实际上可以认为其数据有两份,binlog中一份,引擎中一份(这里先把存储引擎中数据看成整体的单独一份,另外也可以把binlog看成是一个引擎).既然 ...

  4. eclipse maven could not resolve archetype之类的错误

    先说下网上有种联网导入的方法 而我的是本地导入的方法 就是导入原型特慢 或者 原型下载都下载不了的问题 解决方法只能 把那个文件下载搞到本地 没有被墙 就是速度慢 http://repo1.maven ...

  5. JNI 方法注册与签名+BufferedReader使用readLine问题

    最近了解了关于JavaJNI接口的一些关于方法注册与签名相关的知识,在此进行一下总结. 使用JNI接口时,我们首先需要把Java方法声明为native: public native void f(); ...

  6. Async分析

     1:android在新版本中不允许UI线程访问网络,但是如果需要访问网络又改怎么办呐?这里有很多解决方案,比如新开一个线程,在新线程中进行访问,然后访问数据,返回后可能会更新界面也可能不更新界面,这 ...

  7. Kinect2.0 MultiSourceFrameReader 的 AcquireLatestFrame 方法获取不到帧的解决方案

    先把大致要写的东西写一下,手里的活忙完了再完善. 在代码中使用下边的语句,获取Kinect中,colorFrame, depthFrame, bodyIndex三种帧,但是经常会遇到在后边的程序中处理 ...

  8. CMCC验证绕过POC

    大学的时候无意间发现绕过CMCC验证的方法(贫穷使人进步...),写了段POC脚本,时过两年,漏洞应该已经失效了(我猜 --),刚刚发现有人私信问我要,都那么久了鬼还记得写的什么啊,但确实看到了又不能 ...

  9. 01_自动化构建工具之Maven

    目前技术中存在问题(为什么使用Maven): 一个项目就是一个工程: 缺陷:如果项目太过庞大,就不适合使用package来划分层次,最好是一个模块就是一个工程,利于分工协作. 解决:Maven可以将一 ...

  10. Java内存泄漏分析系列之二:jstack生成的Thread Dump日志结构解析

    原文地址:http://www.javatang.com 一个典型的thread dump文件主要由一下几个部分组成: 上图将JVM上的线程堆栈信息和线程信息做了详细的拆解. 第一部分:Full th ...