* 两个会话的技术
* 会话概念:打开浏览器,可以访问WEB资源,多次访问WEB资源,关闭浏览器,整个过程一次会话。* 购买商品
用户点击超链接通过一个servlet购买了一个商品,程序应该保存用户购买的商品,
以便于用户点结帐servlet时,结帐servlet可以得到用户商品为用户结帐。
* 把商品存入到ServletContext获取request域中呢?
* cookie和seesion的原理
看图02
保存会话数据的两种技术:
Cookie
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] ; } } |
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] ; String str = c.getName() + ": " + c.getValue()[涛4] + "<br/>"; response.getWriter().print(str); } } |
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。
如果你想在BServlet中设置的Cookie,在客户端访问AServlet时也包含在请求头中,那么就需要设置BServlet中的Cookie的path:
c2.setPath(“/day07_03/”):硬编码;
c2.setPath(request.getContextpath() + “/”):活编码。
这样就可以设置Cookie的路径,保存在访问AServlet时,也会包含BServlet中添加的Cookie。
8 Cookie的域
Cookie的domain属性可以让网站中二级域共享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请求中包含)。很明显,现在不是路径的问题了,而是主机的问题,即域名的问题。处理这一问题其实很简单,只需要下面两步:
设置Cookie的path为“/”:c.setPath(“/”);
设置Cookie的domain为“.baidu.com”:c.setDomain(“.baidu.com”)。
当domain为“.baidu.com”时,无论前缀是什么,都会共享Cookie的。但是现在我们需要设置两个虚拟主机:www.baidu.com和news.baidu.com。
第一步:设置windows的DNS路径解析
找到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类用于创建一个Cookie,response接口也中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。 同样,request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。Cookie类的方法: