Cookie技术
Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
Cookie是服务端发送给客户端的一小段信息(键值对的形式),有名字有值,随着浏览器发出新的请求的时候,同时返回给服务器
数据存储在客户端(默认存储在客户端浏览器的缓存里面)
1.Cookie的特性
属性:
1) name: Cookie的名字(必须写)
2) value: Cookie的值(必须写)
3) path : 可选的,Cookie的存储路径 默认情况下存储的路径是访问的Servlet所在的路径
4) MaxAge: 可选,最大的存活时间,默认情况下是存放在缓存区中的.,生命周期就是一个会话。
version: Cookie的版本
domain: 域名(那个网站)
Comment: 备注:Cookie是什么,做什么用的
CookieDemo1:
@WebServlet("/cookieDemo1")
public class CookieDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie("msg","hello");
response.addCookie(cookie);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
CookieDemo2:
@WebServlet("/cookieDemo2")
public class CookieDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
if(cookies!=null){
for(Cookie cookie : cookies){
String name = cookie.getName();
String value = cookie.getValue();
//msg:hello
System.out.println(name+":"+value);
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
过程如下:
分析:访问http://localhost:8080/tomcatdemo/cookieDemo1时,在响应头里面带了Set-Cookie
访问:http://localhost:8080/tomcatdemo/cookieDemo2时,在请求头里带了Cookie
2.服务端如何发送cookie给浏览器
//向客户端发送Cookie:
Cookie c = new Cookie("lastaccesstime",new Date().getTime() + "") ;
//发送到客户端
response.addCookie(c) ;
服务端发送了Cookie给浏览器之后,客户端在下一次访问Servlet的时候又会携带着这个Cookie
每个网站最多支持20个Cookie,总共支持最多300个,每个Cookie最大4kb.
(Cookie的资源是非常稀少的,Cookie中存储的数据都是非常必要的重要的数据)
@WebServlet("/cookieDemo1")
public class CookieDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie("name","hello");
Cookie cookie1 = new Cookie("age","15");
response.addCookie(cookie);
response.addCookie(cookie1);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
Cookie默认是存储在客户端的缓存里面,现在希望存到硬盘上,把数据一直记录下来:
采用setMaxAge(int seconds):设置Cookie的存活时间;
- 正数:将Cookie数据写到硬盘的文件中,持久化存储
- 负数:默认值(浏览器关闭,cookie消失)
- 零:删除cookie信息
3.服务端如何获得浏览器所携带的Cookie
//拿到客户端携带的所有的Cookie
Cookie[] cs = request.getCookies() ;
//循环判断拿到我们需要的Cookie
for (int i = 0; cs!=null && i < cs.length; i++) { //第一次访问的时候什么都没携带,所以是null
Cookie c = cs[i] ;
if(c.getName().equals("lastaccesstime")){
//说明找到了需要的Cookie
String time = c.getValue() ;
//将time转换成long类型的值
long t = Long.parseLong(time) ;
//格式化为我们需要的格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss") ;
//创建一个date对象
Date d = new Date(t) ;
//将数据输出到页面上
out.write(sdf.format(d) + " <a href = '"+ request.getContextPath()+"/servlet/ServletCookie2'>清除Cookie</a>") ;
}
}
4.服务端如何删除Cookie
要想删除客户端存储的Cookie,sun公司没有提供相应的删除方法,所以采用的办法就是创建一个同名的cookie,将存活时间设置为0,然后覆盖客户端存储的Cookie
package com.hcx.cookie;
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;
//删除客户端存储的Cookie
public class ServletCookie2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//要想删除客户端存储的Cookie,sun公司没有提供相应的删除方法,
//所以采用的办法就是创建一个同名的cookie,将存活时间设置为0,然后覆盖客户端存储的Cookie
Cookie c = new Cookie("lastaccesstime","") ;
c.setMaxAge(0) ;
//设置路径
c.setPath(request.getContextPath()) ;
//发送到客户端
response.addCookie(c) ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意:在tomcat8之前,cookie中不能存储中文数据(需要将中文数据转码,一般采用url编码),tomcat8之后,cookie支持中文数据,但对于特殊字符扔不支持,所以建议使用url编码存储,再使用url解码来解析
编码:URLEncoder.encode(“需要编码的字符串”,"字符集")
解码:URLDecoder.decode(“需要解码的字符串”,"字符集")
5.如何唯一地确定一个Cookie
域名+ 访问路径 + Cookie的名字
6.浏览器是否携带Cookie由谁决定(Cookie共享问题)
6.1 同一个服务器下不同项目之间的cookie共享
在一个tomcat服务器中,部署了多个web项目,这些wbe项目的cookie是否共享?
默认不共享,使用setPath(String path):设置cookie的获取范围,默认设置当前的虚拟目录,如果需要共享,则将path设置为"/"
path的作用:
用来告诉浏览器,存储到客户端的路径,就是用来判断是否携带Cookie的依据。
//设置浏览器携带Cookie的路径
c.setPath(request.getContextPath()) ;
//设置路径如果是/,那就意味着你访问服务器上的任意工程资源都会携带此Cookie
//c.setPath("/") ; //设置路径是服务器的根路径 : 协议 + 主机名 + 端口号
浏览器到底带不带Cookie是由浏览器说了算。
浏览器通过判断
你在地址栏中敲入的资源地址. starWith(在硬盘上存储的Cookie里面存储的路径),为true ,那就带,否则就不带.
设置路径如果是/,那就意味着你访问服务器上的任意工程资源都会携带此Cookie
c.setPath("/"):设置路径是服务器的根路径 协议 + 主机名 + 端口号
默认情况下(即没有设置setPath):
即没有设置path:客户端存储的Cookie的路径就是发送Cookie的servlet路径
设置了path:
当url以path开头:url.startWith(path);
cookieDemo/ServletCookie3.startWith(“cookieDemo”);
查看url是不是以存储路径开始的,是就带,不是就不带;
6.2 不同服务器之间的cookie共享
setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享。
setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享。
7.应用
package com.hcx.cookie;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
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 ServletCookie1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
//拿到客户端携带的Cookie:
out.write("您上次访问的时间是: ") ;
//拿到客户端携带的记录上次访问时间的Cookie : 假设Cookie的名字是lastaccesstime , 值是一个long类型的数字
//拿到客户端携带的所有的Cookie
Cookie[] cs = request.getCookies() ;
//循环判断拿到我们需要的Cookie
for (int i = 0; cs!=null && i < cs.length; i++) { //第一次访问的时候什么都没携带,所以cs是null
Cookie c = cs[i] ;
if(c.getName().equals("lastaccesstime")){
//说明找到了需要的Cookie
String time = c.getValue() ;
//将time转换成long类型的值
long t = Long.parseLong(time) ;
//格式化为我们需要的格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss") ;
//创建一个date对象
Date d = new Date(t) ;
//将数据输出到页面上
out.write(sdf.format(d) + " <a href = '"+ request.getContextPath()+"/servlet/ServletCookie2'>清除Cookie</a>") ;
//您上次访问的时间是: 2016-12-07 10:16:35 清除Cookie
}
}
//向客户端发送Cookie:
Cookie c = new Cookie("lastaccesstime",new Date().getTime() + "") ;
//设置Cookie的存活时间(只要设置了存活时间,那么此Cookie就将存储到客户端的硬盘上,不会在缓存中存储)
c.setMaxAge(Integer.MAX_VALUE) ;
//设置浏览器携带Cookie的路径
c.setPath(request.getContextPath()) ;
//设置路径如果是/,那就意味着你访问服务器上的任意工程资源都会携带此Cookie
//c.setPath("/") ; //设置路径是服务器的根路径 协议 + 主机名 + 端口号
//发送到客户端
response.addCookie(c) ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
清除cookie:
package com.hcx.cookie;
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;
//删除客户端存储的Cookie
public class ServletCookie2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//要想删除客户端存储的Cookie,sun公司没有提供相应的删除方法,
//所以采用的办法就是创建一个同名的cookie,将存活时间设置为0,然后覆盖客户端存储的Cookie
Cookie c = new Cookie("lastaccesstime","") ;
c.setMaxAge(0) ;
//设置路径
c.setPath(request.getContextPath()) ;
//发送到客户端
response.addCookie(c) ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
对于字符串的连接:
String xxx = "hello";
//<from action='xxx'></from>
String str1 = "<from action='" +xxx+ "'></from>";
//<from action="xxx"></from>
String str2 = "<from action=\"" +xxx+ "\"></from>";
2.记住用户名和密码
package hcx;
import java.io.IOException;
import java.io.PrintWriter;
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 ServletUI extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset = utf-8");
PrintWriter out = response.getWriter();
//拿到错误信息
String info = (String) request.getAttribute("error");
if(info!=null){
out.write("<font color = red>"+info+"</font>");
}
String username = "";
String pass = "";
//拿到客户端的记录
Cookie[] cs = request.getCookies();
for (int i = 0;cs!=null&& i < cs.length; i++) {
Cookie c = cs[i];
if(c.getName().equals("name")){
username = c.getValue();
}
if(c.getName().equals("pass")){
pass = c.getValue();
}
}
out.write("<form action = '"+request.getContextPath()+"/servlet/LoginServlet' method = 'post'>");
out.write("姓名:<input type = 'text' name = 'username' value = '"+username+"'><br>");
out.write("密码:<input type = 'text' name = 'password' value = '"+pass+"'><br>");
out.write("<input type = 'checkbox' name = 'remember' value = 'on'>记住密码两周<br>");
out.write("<input type = 'submit' value = '登录'><br>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
LoginServlet:
package com.hcx;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 此Servlet做两件事情:
* 1. 判断用户是否是合法用户
* 2. 看用户是否选择了记录用户名和密码
*/
//向客户端发送清除或者记录用户名和密码的Cookie
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
//拿取浏览器器传递的数据
String name = request.getParameter("username") ;
String pass = request.getParameter("password") ;
String remeber =request.getParameter("remeber") ;
//判断用户是否是合法用户 : 假定name和pass的逆序一样就是合法用户
//拿到密码的逆序
String pass1 = new StringBuffer(pass).reverse().toString() ;
//判断
if(name.equals(pass1)){
//是合法用户
//判断用户是否选择了记住用户名和密码
//说明用户选择了记录
Cookie c = new Cookie("name",name) ;
Cookie c1 = new Cookie("pass",pass) ;
if("on".equals(remeber)){
//设定存储到客户端的硬盘上
c.setMaxAge(Integer.MAX_VALUE) ;
c1.setMaxAge(Integer.MAX_VALUE) ;
}else{
//设定客户端存储的用户名和密码立刻失效
c.setMaxAge(0) ;
c1.setMaxAge(0) ;
}
//设定访问路径
c.setPath(request.getContextPath()) ;
c1.setPath(request.getContextPath()) ;
//向客户端发送Cookie
response.addCookie(c) ;
response.addCookie(c1) ;
request.setAttribute("name", name) ;
request.getRequestDispatcher("MainServlet").forward(request, response) ;
}else{
//非法用户
request.setAttribute("error", "用户名或者密码错误") ;
request.getRequestDispatcher("ServletUI").forward(request, response) ;
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
MainServlet:
package com.hcx;
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;
public class MainServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
String name = (String) request.getAttribute("name") ;
out.write(name + ",欢迎你") ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.记住网站历史浏览记录
package com.hcx.bean;
public class Book {
private String id ;
private String bookName ;
private String author ;
private float price ;
private String description ;
public Book(String id, String bookName, String author, float price,
String description) {
this.id = id;
this.bookName = bookName;
this.author = author;
this.price = price;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Book [id=" + id + ", bookName=" + bookName + ", author="
+ author + ", price=" + price + ", description=" + description
+ "]";
}
}
BookUtils.java:存放所有的书,相当于数据库
package com.hcx.utils;
import java.util.HashMap;
import java.util.Map;
import com.hcx.bean.Book;
public class BookUtils {
private static Map<String,Book> map = new HashMap<String,Book>() ;
static{
map.put("1", new Book("1","葵花宝典","安倍晋三",100,"欲练神功,必须先练好基本功")) ;
map.put("2", new Book("2","辟邪剑谱","陈冠希",80,"绝世好书")) ;
map.put("3", new Book("3","西游记","吴承恩",50,"一群小猴子的故事")) ;
map.put("4", new Book("4","水浒传","施耐庵",90,"三个女人和105个男人的故事")) ;
map.put("5", new Book("5","西厢记","阿娇",70,"好好看啊。。。。。。")) ;
map.put("6", new Book("6","神雕侠侣","金庸",100,"感天动地的旷世绝恋")) ;
map.put("7", new Book("7","红楼梦","葫芦娃",60,"男人的梦想。。。。。。。")) ;
}
//获取所有的书
public static Map<String,Book> getAllBook(){
return map ;
}
//根据书的id获取谋一本书
public static Book getBookById(String id){
return map.get(id) ;
}
}
ShowAllBookServlet.java:
package com.hcx.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hcx.bean.Book;
import com.hcx.utils.BookUtils;
/**
* 功能有两个:
* 1. 显示所有的书的信息
* 2. 显示浏览的历史记录
* @author Administrator
*
*/
public class ShowAllBookServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
out.write("本站有以下好书:<br>") ;
//1.显示所有的书
//获取所有的书的集合
Map<String ,Book> map = BookUtils.getAllBook() ;
//遍历集合
for (Map.Entry<String, Book> entry : map.entrySet()) {
//拿到每一本的id
String id = entry.getKey() ;
//拿到每一本书
Book book = entry.getValue() ;
//输出书的名字
out.write(book.getBookName() + " <a href = '"+ request.getContextPath()+"/servlet/ShowBookDetailServlet?id=" + id +"'>显示详细信息</a><br>") ;
}
out.write("<br><br><br><br>") ;
//2显示浏览的历史记录: 假设存放历史记录的Cookie的名字叫history : 值的形式: 1-2-3
//拿到客户端携带的所有的Cookie
Cookie[] cs = request.getCookies() ;
//循环判断
for (int i = 0; cs !=null && i < cs.length; i++) {
Cookie c = cs[i] ;
if("history".equals(c.getName())){
out.write("你的浏览历史记录如下: <br>") ;
//找到了存放历史记录的Cookie
String value = c.getValue() ;
//将字符串拆分成成数组
String[] ids = value.split("-") ;
//循环数组,拿到每一本书,显示在页面上
for (int j = 0; j < ids.length; j++) {
Book b = BookUtils.getBookById(ids[j]) ;
out.write(b.getBookName() + "<br>") ;
}
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
ShowBookDetailServlet.java
package com.hcx.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hcx.bean.Book;
import com.hcx.utils.BookUtils;
/**
* 此类完成两件事情:
* 1. 显示书的详细信息
* 2. 发送历史浏览记录
* @author Administrator
*
*/
public class ShowBookDetailServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
//1.显示书的详细信息
//拿到页面传递的id
String id = request.getParameter("id") ;
//根据id获取书
Book book = BookUtils.getBookById(id) ;
//显示信息
out.write(book + " <a href = '" + request.getContextPath() +"/servlet/ShowAllBookServlet'>返回主页继续浏览</a><br>") ;
//2.发送历史浏览记录
//功能:获取历史记录字符串
String history = getHistory(request,id) ;
//创建Cookie,发送Cookie
Cookie c = new Cookie("history",history) ;
//设置Cookie存放到客户端的硬盘上
c.setMaxAge(Integer.MAX_VALUE) ;
//设置客户端携带Cookie的路径
c.setPath(request.getContextPath()) ;
//发送Cookie
response.addCookie(c) ;
}
/**
* 浏览器携带的历史记录的Cookie 点击的书的id 最终需要发送的字符串
* 1. 无 1 1
* 2. 1 1 1
* 3. 1 2 2-1
* 4. 1-2 1 1-2
* 5. 1-2 2 2-1
* 6. 1-2 3 3-1-2
* 7. 1-2-3 1 1-2-3
* 8. 1-2-3 2 2-1-3
* 9. 1-2-3 3 3-1-2
* 10. 1-2-3 4 4-1-2
*
*/
//获取要发往客户端的历史记录的字符串
private String getHistory(HttpServletRequest request,String id) {
//设定一个Cookie为空
Cookie history = null ; //因为第一次访问的时候没有携带cookie
//拿到所有的Cookie
Cookie[] cs = request.getCookies() ;
//循环判断给history赋值
for (int i = 0;cs != null && i < cs.length; i++) {
if(cs[i].getName().equals("history")){
history = cs[i] ;
break ;
}
}
//考虑情况1
if(history == null)
return id ;
//拿到客户端浏览器携带的历史记录的字符串
String value = history.getValue() ;
//考虑情况2,3
if(value.length() == 1){
if(value.equals(id))
//说明点击的是浏览过的
return id ;
else
//点击的是新的书
return id + "-" + value ;
}
//先将历史记录字符串拆分成数组,将数组中的元素放入集合中
String[] ids = value.split("-") ;
LinkedList<String> list = new LinkedList<String>(Arrays.asList(ids)) ;
int index = list.indexOf(id) ;
//考虑情况4,5,6
if(value.length() == 3){
if(index == -1){
//说明此id没有点击过
list.addFirst(id) ;
}else{
//说明点击的id以前点击过
list.remove(index) ;
list.addFirst(id) ;
}
}
//考虑情况7,8,,9,10
if(value.length() > 3){
if(index == -1){
//说明点击的id以前没有点击过
list.removeLast() ;
list.addFirst(id) ;
}else{
//说明点击的id是浏览器中已经携带的有的
list.remove(index) ;
list.addFirst(id) ;
}
}
//需要将集合中的数据形成需要的字符串
StringBuffer sb = new StringBuffer(list.get(0)) ;
for (int i = 1; i < list.size(); i++) {
sb.append("-" + list.get(i)) ;
}
return sb.toString();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}