Servlet中不可不知的Cookie技术

目录

介绍

  什么是会话?会话可以简单的理解为:用户开一个浏览器,点击多个超链接,访问服务器多个Web资源,然后关闭浏览器,整个过程称之为会话。
  Cookie是客户端技术,程序把每个用户的数据以Cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的Web资源时,就会带着各自的数据去。这样,Web资源处理的就是用户各自的数据了。

Servlet中的Cookie

  javax.servlet.http.Cookie类用于创建一个Cookie,在response接口中也定义一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。同样,request接口中也定义了一个getCookies方法,它用于获取客户端中提交的所有Cookie信息。
  Cookie类的常用方法:

  • public Cookie(String name, String value)
  • setValue与getValue方法
  • setMaxAge与getMaxAge方法
  • setPath与getPath方法
  • setDomain与geDomain方法
  • getName
      注:
      1. Cookie如果没有调用setMaxAge设置有效期限,则默认在浏览器关闭时Cookie的失效。
      2. Servlet设置Cookie后,默认Cookie的有效路径为Servlet所在目录。如:访问/servlet/ServletDemo01,在ServletDemo01中设置返回Cookie,则该Cookie的默认有效路径为 /servlet,即当用户访问 /servlet 下的Servlet时,浏览器才会发送Cookie过去。

Cookie重要知识点

  • 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称和设置值。
  • 一个Web站点可以给一个Web浏览器发送多个Cookie,一个浏览器也可以存储多个Web站点提供的Cookie。
  • 浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4kb。
  • 如果创建了一个Cookie,并将它发送到浏览器,默认情况下它是一个会话级别的Cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该Cookie存储在磁盘上,则需要设置maxAge,并给出一个以秒为单位的时间。将最大失效设置为0,则是命令浏览器删除该Cookie。
  • 删除cookie时,path必须一致,否则不会删除。

通过Cookie技术显示用户上次访问时间

  删除cookie时,path必须一致,否则不会删除。
示例:
CookieDemo1.java

package com.wm103.cookie;

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;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

/**
 * Created by DreamBoy on 2017/5/1.
 */

/**
 * 通过Cookie技术显示用户上次访问时间
 */
@WebServlet(name = "CookieDemo1", urlPatterns = {"/CookieDemo1"})
public class CookieDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        out.print("<a href='/day07/CookieDemo2'>清除上次访问时间</a><br/>");
        out.print("您上次访问的时间是:");

        // 获取用户的Cookie
        Cookie[] cookies = request.getCookies();
        for (int i = 0; cookies != null && i < cookies.length; i++) {
            if(cookies[i].getName().equals("LastAccessTime")) {
                long cookieValue = Long.parseLong(cookies[i].getValue());// 得到了用户的上次访问时间
                Date date = new Date(cookieValue);
                out.print(date.toLocaleString());
            }
        }

        // 给用户回送最新的访问时间
        Cookie cookie = new Cookie("LastAccessTime", System.currentTimeMillis() + "");
        cookie.setMaxAge(30 * 24 * 3600);
        cookie.setPath("/day07/");
        response.addCookie(cookie);
    }
}

CookieDemo2.java

package com.wm103.cookie;

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;
import java.io.IOException;

/**
 * Created by DreamBoy on 2017/5/1.
 */
@WebServlet(name = "CookieDemo2", urlPatterns = {"/CookieDemo2"})
public class CookieDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie cookie = new Cookie("LastAccessTime", System.currentTimeMillis() + "");
        cookie.setMaxAge(0);
        cookie.setPath("/day07/"); // 删除cookie时,path必须一致,否则不会删除
        response.addCookie(cookie);
    }
}

使用Cookie技术实现记录用户浏览过的商品

显示商品列表和浏览过的商品

  这里使用Db类模拟数据库中存储的商品信息,并以静态代码块的方式初始化集合中保存的商品信息。
CookieDemo3.java

package com.wm103.cookie;

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;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by DreamBoy on 2017/5/1.
 */

/**
 * 代表首页的servlet
 */
@WebServlet(name = "CookieDemo3", urlPatterns = {"/CookieDemo3"})
public class CookieDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        // 1. 输出网站所有商品
        out.print("<div style='margin: 20px 50px; padding: 10px 30px; border: 1px solid #eee; box-shadow: 0 2px 2px #ede'>");
        out.write("<h3>本网站有如下商品:</h3>");
        out.print("<ul>");
        Map<String, Book> map = Db.getAll();
        for (Map.Entry<String, Book> entry: map.entrySet()) {
            Book book = entry.getValue();
            out.print("<li style='line-height: 2'><a href='/day07/CookieDemo4?id=" + book.getId() + "' target='_blank'>" + book.getName() + "</a></li>");
        }
        out.print("</ul>");
        out.print("</div>");


        // 2. 显示用户曾经看过的商品
        out.print("<div style='margin: 20px 50px; padding: 10px 30px; border: 1px solid #eee; box-shadow: 0 2px 2px #ede'>");
        out.write("<h3>最近您浏览过的商品:</h3>");
        out.print("<ul>");
        Cookie[] cookies = request.getCookies();
        for (int i = 0; cookies != null && i < cookies.length; i++) {
            if(cookies[i].getName().equals("BookHistory")) {
                String[] ids = cookies[i].getValue().split("#"); // 以 # 分隔
                for (String id: ids) {
                    Book book = Db.getAll().get(id);
                    out.print("<li style='line-height: 2'><a href='/day07/CookieDemo4?id=" + book.getId() + "' target='_blank'>" + book.getName() + "</a></li>");
                }
            }
        }
        out.print("</ul>");
        out.print("</div>");

    }
}

class Db {
    private static Map<String, Book> map = new LinkedHashMap<>();
    static { // 静态代码块
        map.put("1", new Book("1", "JavaWeb开发", "007号", "一本关于JavaWeb开发的书"));
        map.put("2", new Book("2", "JDBC开发", "008号", "一本关于JDBC开发的书"));
        map.put("3", new Book("3", "Spring开发", "009号", "一本关于Spring开发的书"));
        map.put("4", new Book("4", "Struts开发", "010号", "一本关于Struts开发的书"));
        map.put("5", new Book("5", "Android开发", "011号", "一本关于Android开发的书"));
    }

    public static Map<String, Book> getAll() {
        return map;
    }
}

class Book {
    private String id;
    private String name;
    private String author;
    private String description;

    public Book() {
    }

    public Book(String id, String name, String author, String description) {
        this.id = id;
        this.name = name;
        this.author = author;
        this.description = description;
    }

    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 getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

查看商品详情(使用Cookie记录浏览信息)

  注意点:1. 记录商品浏览信息时,要求记录的所有浏览记录条数不能超过预设的长度,如果超出将删除掉最旧的记录信息。2. 访问商品后,发现商品已在保存在浏览记录中,则应调整该商品在浏览记录中的位置,将该商品的浏览记录设置为最新。
CookieDemo4.java

package com.wm103.cookie;

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;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by DreamBoy on 2017/5/1.
 */

/**
 * 显示商品详细信息的Servlet
 */
@WebServlet(name = "CookieDemo4", urlPatterns = {"/CookieDemo4"})
public class CookieDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        // 1. 根据用户带过来的ID,显示相应的商品详细信息
        String id = request.getParameter("id");
        Book book = Db.getAll().get(id);

        out.print("<div style='margin: 20px 50px; padding: 10px 30px; border: 1px solid #eee; box-shadow: 0 2px 2px #ede'>");
        out.write("<h3>" + book.getName() + "-" + book.getAuthor() + "</h3>");
        out.print("<p>编号:" + book.getId() + "</p>");
        out.print("<p>名称:" + book.getName() + "</p>");
        out.print("<p>作者:" + book.getAuthor() + "</p>");
        out.print("<p>描述:" + book.getDescription() + "</p>");
        out.print("</div>");


        // 2. 构建cookie,回写给浏览器
        // String val = buildCookieVal(id, request);
        String val = buildCookie(id, request);
        Cookie cookie = new Cookie("BookHistory", val);
        cookie.setMaxAge(3600 * 24 * 30);
        cookie.setPath("/day07/");
        response.addCookie(cookie);
    }

    /**
     * 方法一:
     * @param id
     * @param request
     * @return
     */
    private String buildCookie(String id, HttpServletRequest request) {
        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();
                break;
            }
        }

        if(bookHistory == null) {
            return id;
        }

        int maxLen = 3;
        LinkedList<String> list = new LinkedList<>(Arrays.asList(bookHistory.split("#")));
        if(list.contains(id)) {
            list.remove(id);
        } else {
            if(list.size() >= maxLen) {
                list.removeLast();
            }
        }
        list.addFirst(id);

        StringBuffer sb = new StringBuffer();
        for (String bid: list) {
            sb.append(bid + "#");
        }
        return sb.deleteCharAt(sb.length() - 1).toString();
    }

    /**
     * 方法二:
     * @param id
     * @param request
     * @return
     */
    private String buildCookieVal(String id, HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        Cookie bookHistory = null;
        for(int i = 0; cookies != null && i < cookies.length; i++) {
            if(cookies[i].getName().equals("BookHistory")) {
                bookHistory = cookies[i];
                break;
            }
        }

        // 1. 未存在cookie记录
        if(bookHistory == null) {
            return id;
        }

        // 2. 存在cookie记录
        // 2.1 检测Cookie中的ID个数是否大于或等于设置的最大存储个数
        int maxLen = 3;
        String[] ids = bookHistory.getValue().split("#");
        List<String> list = new ArrayList<>(Arrays.asList(ids));
        if(ids.length >= maxLen) {
            list = list.subList(0, maxLen - 1);
        }

        // 2.2 判断将要保存到Cookie的ID是否已经在已有的Cookie中存在
        int pos = list.indexOf(id);
        if(pos != -1) {
            list.remove(pos);
        }
        list.add(0, id);
        // 2.3 返回Cookie保存的IDs
        boolean isFirst = true;
        String res = "";
        for (String strId :list) {
            if(!isFirst) {
                res += "#";
            } else {
                isFirst = false;
            }
            res += strId;
        }
        return res;
    }
}

  注意:使用“,”分隔保存商品ID,设置Cookie时,可能会发生如下错误:

java.lang.IllegalArgumentException: An invalid character [44] was present in the Cookie value

  因此,这里采用“#”对商品ID进行分隔保存。

示例效果

  • 商品列表和商品浏览记录
    商品列表和商品浏览记录
  • 商品详情
    商品详情
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值