保存会话数据的两种技术之Cookie

时间:2024-05-22 10:28:00

* 两个会话的技术

* 会话概念:打开浏览器,可以访问WEB资源,多次访问WEB资源,关闭浏览器,整个过程一次会话。
* 购买商品
用户点击超链接通过一个servlet购买了一个商品,程序应该保存用户购买的商品,
以便于用户点结帐servlet时,结帐servlet可以得到用户商品为用户结帐。
* 把商品存入到ServletContext获取request域中呢?
* cookie和seesion的原理

看图02

保存会话数据的两种技术:

Cookie

Cookie客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
Session
Session服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。

Cookie的响应头set-cookie:product=1,浏览器的内存会保存cookie的内容,再发送请求时,会带着头cookie:product=1去访问。之后累加。

Session在服务器端开辟一块空间,分配一个唯一的标识,每次请求响应都带着唯一的标识,最终结算通过标识找到空间。

* cookie
* 显示上次的访问时间(案例)
* 第一次访问,输出欢迎,在服务器端,记录当前的时间,把当前的时间通过cookie回写到浏览器。
* 第二次访问,会带着上次的时间,获取时间,可以把时间显示到页面上,记录当前的时间,再把回写浏览器。
输出上次的访问时间。

Cookie翻译成中文是小甜点,小饼干的意思。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie就是一个键和一个值构成的,随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。

2 Cookie规范

你大可以放心,Cookie不会占满你的硬盘。因为一个Cookie最多只有4KB,一个服务器最多只能发送到客户端20个Cookie,并且浏览器最多可以保存300个Cookie。当然,在浏览器大战的今天,一些浏览器为了打败对手,可能对Cookie规范“扩展”了一些,例如每个Cookie的大小为8KB,最多可保存500个Cookie等!但也不会出现把你硬盘占满的可能!

不同的浏览器之间不能共享Cookie!!!

3 Cookie的作用

Cookie的作用可大了,但无论怎么夸大Cookie的作用都离不开“跟踪客户端状态”这句话。我们知道Cookie是服务器保存在客户端的信息,然后客户端会在下次请求时把Cookie在还给服务器,这样服务器就可以通过信息来识别客户端了。

就好比你去医院看病,第一次去需要买卡片,然后你去任何科室都需要你出示卡片。只要你出示卡片,医生就会知道你去过哪些科室,看了哪些病!卡片上只有一个ID,它就是Cooke,而你本人就是客户端,而医生就是服务器了。 

4 Cookie的属性

Cookie最重要的4个属性:

  名字(name);

  值(value);

  路径(path);

  域(domain)。

* Cookie的API
* cookie的构造方式 Cookie(String name, String value) 
* String getName()  获取cookie的名称
* String getValue() 获取cookie的值

* void setMaxAge(int expiry)   :设置有效时间
* 失效cookie setMaxAge(0); 前提条件:设置有效路径(和之前设置过相同)

* void setPath(String uri)   :设置有效路径
* 默认的有效路径()
* 配置 /last 默认路径 /day11
* 配置 /servlet/last 默认路径 /day11/servlet

* void setDomain(String pattern)   :设置有效域名
* www.sina.com.cn
* sports.sina.com.cn
* xxx.sina.com.cn
* 设置有效域名 setDomain(".sian.com.cn");

* 会话级别的cookie:默认保存到浏览器的内存中。
* 持久的cookie:把cookie保存到磁盘上。通过setMaxAge(int a)进行设置。

* 显示用户上次访问过的商品信息(需求)
 *  1.获取请求参数
 *  2.获取cookie数组,通过指定的名称(自己指定)查找cookie
 *  3.如果cookie==null,第一次访问
 *  * 如果是第一次访问,创建cookie,回写浏览器
 *  4.如果cookie!=null,不是第一次访问
 *  * 如果不是第一次访问,说明我的cookie中已经存在id
 *  * 判断,当前的id是否已经存在cookie的中value
 *  * 如果存在,不用操作
 *  * 如果不存在,在后面追加(product=1,2)
 *  5.重定向到商品页面
5 保存Cookie到客户端

保存Cookie到客户端,这是响应工作的一部分,所以这个方法是response对象的。并且Cookie是HTTP协议中的内容,所以保存Cookie是HttpServletResponse类的方法。

void addCookie(Cookie c):添加Cookie对象到当前response对象中,这个方法可以被调用多次,从而完成添加多个Cookie对象到response中。

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request,

            HttpServletResponse response)

            throws ServletException, IOException {

        Cookie c = new Cookie("id""itcast")[涛1] ;

        response.addCookie(c)[涛2] ;

    }

}


创建名为id,值为itcast的Cookie对象。

把Cookie对象添加到response对象中去。

保存会话数据的两种技术之Cookie

6 Cookie的生命

Cookie会在客户端存活多久呢?这就是Cookie的生命了。默认情况下,Cookie只在浏览器的内存中存活,也就是说,当你关闭浏览器后,Cookie就会消失!

可以使用Cookie#setMaxAge(int expiry)来设置Cookie的存活时间。参数expiry表示Cookie存活的秒数。

  cookie.setMaxAge(60*60):表示cookie对象可存活1小时。就算关闭浏览器,就算重启客户端电脑,cookie也会存活1小时。因为当maxAge大于0时,浏览器不仅会把cookie保存在浏览器内存中,还会把cookie保存到硬盘上。

  cookie.setMaxAge(-1):cookie的maxAge属性的默认值就是-1(其实只要是负数都是一个意思),表示只在浏览器内存中存活。一旦关闭浏览器窗口,那么cookie就会消失。

  cookie.setMaxAge(0):cookie被作废!表示cookie即不在内存中存活,也不在硬盘上存活,这样的cookie设置只有一个目的,那就是覆盖客户端原来的这个cookie,使其作废。

7 服务器端读取Cookie

我们现在已经可以保存Cookie到客户端了,但还没有学习让服务器如何读取Cookie。

如果浏览器保存了Cookie,那么会在下一次请求时把Cookie放到请求头中发送给服务器,这时服务器需要在请求中读取Cookie。既然是在请求中读取,那么当然是使用request对象来读取了。

HttpServletRequest:Cookie[] getCookies()

注意,它返回的是Cookie数组,而不是一个Cookie对象。如果请求中没有Cookie,那么该方法返回null。

        Cookie[] cs = request.getCookies()[涛1] ;

        if (cs != null[涛2] ) {

            for (Cookie c : cs) [涛3] {

                String str = c.getName() + ": " + c.getValue()[涛4]  + "<br/>";

                response.getWriter().print(str);

            }

        }


获取当前请求中所有Cookie对象

如果返回的数组不是null

循环遍历所有Cookie对象

获取当前Cookie对象的名字与值

7 Cookie的路径

Cookie路径会影响请求中是否包含Cookie,次要。

Cookie还有一个path属性,可以通过Cookie#setPath(String)方法来设置。你可以使用HttpWatch查看响应中的Set-Cookie中是否存在路径。

也就是说,就算你不设置Cookie的path,Cookie也是有路径的。这个路径就是请求的路径。例如在请求http://localhost/day07_03/AServlet时,服务器响应了一个Cookie,那么这个Cookie的默认路径就是/day07_03/。

例如请求的路径是http://localhost/day07_03/servlet/BServlet时,服务器响应了一个Cookie,那么这个Cookie的默认路径就是/day07_03/servlet/。

到现在我们还没说过Cookie的path有什么用,现在我们来聊聊path的作用。首先声明一点,path不是指Cookie在客户端存放的路径!!!不同的浏览器存放Cookie的路径是不同的!!!你不能通过Cookie的path来指定Cookie文件的存放路径!!!

那么Cookie的path是干什么的呢?假设你的浏览器当前已经有了两个Cookie:

  c1:name=id; value=itcast;path=/day07_03/;

  c2:name=name;value=qdmmy6; path=/day07_03/servlet/。

当访问http://localhost/day07_03/*时,请求头中会包含c1,而不会包含c2。

当访问http://localhost/day07_03/servlet/*时,请求头中会包含c1和c2。

也就是说,在访问子路径时,会包含其父路径的Cookie,而在访问父路径时,不包含子路径的Cookie。

保存会话数据的两种技术之Cookie

如果你想在BServlet中设置的Cookie,在客户端访问AServlet时也包含在请求头中,那么就需要设置BServlet中的Cookie的path:

  c2.setPath(“/day07_03/”):硬编码

  c2.setPath(request.getContextpath() + “/”):活编码。

   这样就可以设置Cookie的路径,保存在访问AServlet时,也会包含BServlet中添加的Cookie。

8 Cookie的域

Cookiedomain属性可以让网站中二级域共享Cookie,次要!

百度你是了解的对吧!

http://www.baidu.com

http://zhidao.baidu.com

http://news.baidu.com

http://tieba.baidu.com

现在我希望在这些主机之间共享Cookie(例如在www.baidu.com中响应的cookie,可以在news.baidu.com请求中包含)。很明显,现在不是路径的问题了,而是主机的问题,即域名的问题。处理这一问题其实很简单,只需要下面两步:

  设置Cookiepath为“/”:c.setPath(“/”);

设置Cookiedomain为“.baidu.com”:c.setDomain(“.baidu.com”)。 

domain为“.baidu.com”时,无论前缀是什么,都会共享Cookie的。但是现在我们需要设置两个虚拟主机:www.baidu.com和news.baidu.com。 

第一步:设置windowsDNS路径解析

找到C:\WINDOWS\system32\drivers\etc\hosts文件,添加如下内容

127.0.0.1       localhost

127.0.0.1       www.baidu.com

127.0.0.1       news.baidu.com

第二步:设置Tomcat虚拟主机

找到server.xml文件,添加<Host>元素,内容如下:

      <Host name="www.baidu.com"  appBase="F:\webapps\www"

            unpackWARs="true" autoDeploy="true"

            xmlValidation="false" xmlNamespaceAware="false"/>

      <Host name="news.baidu.com"  appBase="F:\webapps\news"

            unpackWARs="true" autoDeploy="true"

            xmlValidation="false" xmlNamespaceAware="false"/>

第三步:创建A项目,创建AServlet,设置Cookie。

        Cookie c = new Cookie("id""baidu");

        c.setPath("/");

        c.setDomain(".baidu.com");

        c.setMaxAge(60*60);

        response.addCookie(c);

        response.getWriter().print("OK");

把A项目的WebRoot目录复制到F:\webapps\www目录下,并把WebRoot目录的名字修改为ROOT。

第四步:创建B项目,创建BServlet,获取Cookie,并打印出来。

        Cookie[] cs = request.getCookies();

        if(cs != null) {

            for(Cookie c : cs) {

                String s = c.getName() + ": " + c.getValue() + "<br/>";

                response.getWriter().print(s);

            }

        }

把B项目的WebRoot目录复制到F:\webapps\news目录下,并把WebRoot目录的名字修改为ROOT。

第五步:访问www.baidu.com\AServlet,然后再访问news.baidu.com\BServlet。

9 Cookie中保存中文

  Cookie中保存中文,次要。

Cookie中是不可以设置中文的,但可以使用URLEncoder.encode()方法编码后在存放到Cookie中。在获取Cookie时,需要先使用URLDecoder.decode()方法解码,再使用。

向客户端响应中添加Cookie

        String name = URLEncoder.encode("姓名""UTF-8");

        String value = URLEncoder.encode("张三""UTF-8");

        Cookie c = new Cookie(name, value);

        c.setMaxAge(3600);

        response.addCookie(c);

从客户端请求中获取Cookie

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

        Cookie[] cs = request.getCookies();

        if(cs != null) {

            for(Cookie c : cs) {

                String name = URLDecoder.decode(c.getName(), "UTF-8");

                String value = URLDecoder.decode(c.getValue(), "UTF-8");

                String s = name + ": " + value + "<br/>";

                response.getWriter().print(s);

            }

        }

10 Cookie练习

使用Cookie来验证用户是否已经登录。

  index.jsp:登录页面,提供登录表单提交到LoginServlet;

  LoginServlet:验证登录,获取用户名,保存到Cookie中,转发到AServlet;

  AServlet:受保护Servlet,查看Cookie是否存在;

  BServlet:受保护Servlet,查看Cookie是否存在。

 index.jsp

    <h1>XXX系统</h1>

    <hr/>

    <h3>请求输入你的姓名</h3>

    <form action="/login/LoginServlet" method="get">

    姓名:<input type="text" name="username" /><br/>

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

    </form>

LoginServlet.java

        String username = request.getParameter("username");

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

        PrintWriter out = response.getWriter();

        if(username == null || "".equals(username)) {

            out.print("你瞎了!让你输入用户名,你没看见么?<br/>");

            out.print("点击<a href='/login/index.jsp'>这里</a>返回登录页面!");

            return;

        }

        CookieUtils.saveCookie(response, new Cookie("username", username));

        response.sendRedirect("/login/AServlet");

 AServlet.java

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

        PrintWriter out = response.getWriter();

        out.print("<h1>AServlet</h1>");

        out.print("<hr/>");

        String name = CookieUtils.getCookie(request, "username");

        if(name == null) {

            out.print("您还没有登录,点击<a href='/login/index.jsp'>这里</a>返回登录页面!");

            return;

        }

        out.print("您好:" + name + ", 欢迎登录本系统<br/>");

        out.print("<a href='/login/AServlet'>AServlet</a><br/>");

        out.print("<a href='/login/BServlet'>BServlet</a><br/>");

 BServlet.java

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

        PrintWriter out = response.getWriter();

        out.print("<h1>BServlet</h1>");

        out.print("<hr/>");

        String name = CookieUtils.getCookie(request, "username");

        if(name == null) {

            out.print("您还没有登录,点击<a href='/login/index.jsp'>这里</a>返回登录页面!");

            return;

        }

        out.print("您好:" + name + ", 欢迎登录本系统<br/>");

        out.print("<a href='/login/AServlet'>AServlet</a><br/>");

        out.print("<a href='/login/BServlet'>BServlet</a><br/>");

 CookieUtils

publicclass CookieUtils {

    publicstatic String getCookie(HttpServletRequest request, String name) {

        Cookie[] cs = request.getCookies();

        if(cs == null) {

            returnnull;

        }

        for(Cookie c : cs) {

            try {

                String n = URLDecoder.decode(c.getName(), "utf-8");

                if(n.equals(name)) {

                    return URLDecoder.decode(c.getValue(), "utf-8");

                }

            } catch (UnsupportedEncodingException e) {

                thrownew RuntimeException(e);

            }

        }

        return"";

    }  

    publicstaticvoid saveCookie(HttpServletResponse response, Cookie c) {

        try {

            String name = URLEncoder.encode(c.getName(), "utf-8");

            String value = URLEncoder.encode(c.getValue(), "utf-8");

            Cookie cookie = new Cookie(name, value);

            cookie.setPath(c.getPath());

            response.addCookie(cookie);

        } catch (UnsupportedEncodingException e) {

            thrownew RuntimeException(e);

        }

    }

}

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

public Cookie(String name,Stringvalue)
setValuegetValue方法
setMaxAgegetMaxAge方法
setPathgetPath方法
setDomaingetDomain方法
getName方法
Cookie细节
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie
浏览器一般只允许存放300Cookie每个站点最多存放20Cookie每个Cookie的大小限制为4KB
如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。
删除持久cookie,可以将cookie最大时效设为0注意,删除cookie时,path必须一致,否则不会删除
Cookie应用
显示用户上次浏览过的商品
编写商品信息列表,给每个商品起唯一的id值,通过id传值。
判断是否是第一次访问
如果是第一次访问,创建cookie,记录商品id,回写到浏览器
如果不是第一次访问,获取cookie中的商品信息,但是需要判断cookie中是否已经包含该商品,如果包含就不用处理,如果不包含,可以取出商品的id,累加操作。(可以编写一个判断是否包含的方法
重定向到商品列表页面,把商品循环到列表页面
清除浏览记录