Cookie意为“甜饼”,是由W3C组织提出,最先由Netscape社区发展的一种机制。 目前Cookie已经成为标准,全部的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。html
因为HTTP是一种无状态的协议,服务器单从网络链接上无从知道客户身份。 怎么办呢?就给客户端们颁发一个通行证吧,每人一个,不管谁访问都必须携带本身通行证。 这样服务器就能从通行证上确认客户身份了。这就是Cookie的工做原理。git
Cookie其实是一小段的文本信息。 客户端请求服务器,若是服务器须要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。 客户端浏览器会把Cookie保存起来。 当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。 服务器检查该Cookie,以此来辨认用户状态。 服务器还能够根据须要修改Cookie的内容。github
Cookie技术是客户端的解决方案,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端, 而后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。web
具体过程以下:数据库
Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。 一旦数据交换完毕,客户端与服务器端的链接就会关闭,再次交换数据须要创建新的链接。 这就意味着服务器没法从链接上跟踪会话。 举个例子,用户A购买了一件商品放入购物车内, 当再次购买商品时服务器已经没法判断该购买行为是属于用户A的会话仍是用户B的会话了。 要跟踪该会话,必须引入一种机制。跨域
Cookie就是这样的一种机制。它能够弥补HTTP协议无状态的不足。 在Session出现以前,基本上全部的网站都采用Cookie来跟踪会话。浏览器
两个Http头部和Cookie有关 : Set-Cookie和Cookie缓存
当服务器返回给客户端一个Http响应信息时,其中若是包含Set-Cookie这个头部,说明:安全
一个cookie的设置以及发送过程分为如下四步:bash
在客户端的第二次请求中包含Cookie头部,提供给了服务器端能够用来惟一标识客户端身份的信息。 这时,服务器端也就能够判断客户端是否启用了cookie。 尽管,用户可能在和应用程序交互的过程当中忽然禁用cookie的使用, 可是,这个状况基本是不太可能发生的,因此能够不加以考虑,这在实践中也被证实是对的。
不少网站都会使用Cookie。例如,Google会向客户端颁发Cookie,Baidu也会向客户端颁发Cookie。 那浏览器访问Google会不会也携带上Baidu颁发的Cookie呢?或者Google能不能修改Baidu颁发的Cookie呢?
答案是否认的。Cookie具备不可跨域名性。 根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。 Google也只能操做Google的Cookie,而不能操做Baidu的Cookie。
Cookie在客户端是由浏览器来管理的。 浏览器可以保证Google只会操做Google的Cookie而不会操做Baidu的Cookie,从而保证用户的隐私安全。 浏览器判断一个网站是否能操做另外一个网站Cookie的依据是域名。 Google与Baidu的域名不同,所以Google不能操做Baidu的Cookie。
虽然网站images.google.com与网站www.google.com同属于Google, 可是域名不同,两者一样不能互相操做彼此的Cookie。
用户登陆网站www.google.com以后会发现访问images.google.com时登陆信息仍然有效,而普通的Cookie是作不到的。 这是由于Google作了特殊处理。
cookie的API
new Cookie(String key,String value);
String getName();//获取cookie的key(名称)
String getValue();//获取cookie的值
void setMaxAge(int);//设置cookie在浏览器存活时间,单位:秒
//若是设置成0:表示删除高cookie(前提:路径必须一致)
void setPath(String path);//设置cookie的路径
//当咱们访问的路径中包含次cookie的path,才会携带cookie
//默认访问路径:访问Servlet的路径,从"/项目名称"开始,到最后一个"/"结束。好比:/demo/a/b,默认路径为/demo/a
//手动设置路径:以"/项目名称"开始,以"/"结尾复制代码
写回浏览器
response.addCookie(Cookie);复制代码
获取cookie
Cookie[] request.getCookies();复制代码
/**
* 根据 cookie名称获取Cookie 的工具类
*/
public class CookieUtils {
public static Cookie getCookieByName(String name,Cookie[] cookies){
if(cookies != null){
for(Cookie cookie : cookies){
if(name.equals(cookie.getName())){
return cookie;
}
}
}
return null;
}
}
public class RecordServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置编码
response.setContentType("text/html;charset=utf-8");
PrintWriter w = response.getWriter();
//2.获取指定名称的Cookie
Cookie cookie = CookieUtils.getCookieByName("record",request.getCookies());
//3.判断cookie是否为空;
// 若为null,则说明是第一次访问;
// 若不为 null,则根据cookie显示上一次的访问时间
if(cookie == null){
w.write("这是您第一次访问");
}else{
long lastTime= Long.parseLong(cookie.getValue());
w.write("您上次访问的时间:"+ new Date(lastTime).toLocaleString());
}
//4.记录当前访问时间,而且该信息存入cookie中
Cookie c = new Cookie("record",System.currentTimeMillis()+"");
//设置cookie的有效期是 1 小时
c.setMaxAge(60*60);
response.addCookie(c);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}复制代码
/**
* 记录商品浏览记录,只展现3个商品
*/
public class CategoryServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取当前访问商品的id
String id = request.getParameter("id");
Cookie c = CookieUtils.getCookieByName("ids",request.getCookies());
//判断该 cookie 是否为空
String ids="";
if(c == null){
//若为空,说明以前没有访问记录
//将当前商品的id放入ids中
ids = id;
}else{
//若不为空,获取值。也就是以前浏览的商品编号,使用 "-"进行链接
ids = c.getValue();
//将 ids 经过"-"进行分割,而后存入list中,方便后续的操做
String[] categoryIds = ids.split("-");
LinkedList<String> categories = new LinkedList<>();
if(categories != null){
for(String categoryId : categoryIds){
categories.add(categoryId);
}
}
//判断以前记录中有无该商品
if(categories.contains(id)){
//如有,删除原来的id,将当前的id放入前面
categories.remove(id);
}else{
// 若没有
// 继续判断长度是否>=3
// 若>=3,移除最后一个,将当前的id放入最前面
// 若<3,直接将当前的id放入最前面.
if(categories.size() >= 3){
categories.removeLast();
}
}
//无论如何,id都是最新浏览的,直接加入到前面
categories.addFirst(id);
ids="";
for(String categoryId : categories){
ids += (categoryId + "-");
}
ids = ids.substring(0,ids.length()-1);
}
//建立cookie
c=new Cookie("ids",ids);
//设置访问路径
c.setPath(request.getContextPath()+"/");
//设置存活时间
c.setMaxAge(60);
//写回浏览器
response.addCookie(c);
//跳转到指定的商品页面上
response.sendRedirect(request.getContextPath()+"/category_info"+id+".htm");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}复制代码
<ul style="list-style: none;">
<%
//获取指定名称的cookie ids
Cookie c= CookieUtils.getCookieByName("ids", request.getCookies());
//判断ids是否为空
if(c==null){
%>
<h2>暂无浏览记录</h2>
<%
}else{//ids=3-2-1
String[] arr=c.getValue().split("-");
for(String id:arr){
%>
<li style="width: 150px;height: 216;float: left;margin: 0 8px 0 0;padding: 0 18px 15px;text-align: center;"><img src="category/0<%=(Integer.parseInt(id)-1) %>.jpg" width="130px" height="130px" /></li>
<%
}
}
%>
</ul>复制代码
/**
* 清空浏览记录
*/
public class ClearServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie c = new Cookie("ids","");
//cookie的路径与 CategoryServlet中的cookie中的路径要相同
c.setPath(request.getContextPath()+"/");
//直接将cookie设置成无效
c.setMaxAge(0);
response.addCookie(c);
//重定向
response.sendRedirect(request.getContextPath()+"/category_list.jsp");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}复制代码
Session是一种记录客户状态的机制,不一样于Cookie的是Cookie保存在客户端浏览器中,而Session保存在服务器上。 客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。 客户端浏览器再次访问时只须要从该Session中查找该客户的状态就能够了。
若是说Cookie机制是经过检查客户身上的"通行证"来肯定客户身份的话, 那么Session机制就是经过检查服务器上的"客户明细表"来确认客户身份。 Session至关于程序在服务器上创建的一份客户档案, 客户来访的时候只须要查询客户档案表就能够了。
一方面,咱们能够把客户端浏览器与服务器之间一系列交互的动做称为一个 Session。 从这个语义出发,咱们会提到Session持续的时间,会提到在Session过程当中进行了什么操做等等。
另外一方面,Session指的是服务器端为客户端所开辟的存储空间,该空间保存的信息就是用于保持状态。 从这个语义出发,咱们则会提到往Session中存放什么内容,如何根据键值从Session中获取匹配的内容等。
Session保存在服务器端。为了得到更高的存取速度,服务器通常把Session放在内存中。 每一个用户都会有一个独立的Session。 若是Session内容过于复杂,当大量客户访问服务器时可能会致使内存溢出。 所以,Session里的信息应该尽可能精简。
Session在用户第一次访问服务器的时候自动建立。 须要注意只有访问JSP、Servlet等程序时才会建立Session, 只访问HTML、IMAGE等静态资源并不会建立Session。 若是还没有生成Session,也可使用request.getSession(true)强制生成Session。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。 用户每访问服务器一次,不管是否读写Session,服务器都认为该用户的Session"活跃(active)"了一次。
因为会有愈来愈多的用户访问服务器,所以Session也会愈来愈多。 为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。 这个时间就是Session的超时时间。若是超过了超时时间没访问过服务器,Session就自动失效了。
Session的超时时间为maxInactiveInterval属性, 能够经过对应的getMaxInactiveInterval()获取,经过setMaxInactiveInterval(longinterval)修改。
Session的超时时间也能够在web.xml中修改。 另外,经过调用Session的invalidate()方法可使Session失效。
获取Session
HttpSession getSession(); //request.getSession()复制代码
域对象
xxxAttribute //存放私有数据复制代码
域对象生命周期
默认超时时间:30 min
手动设置超时:setMaxInactiveInterval(int) (单位:秒)
Session接口中的invalidate()方法
public void invalidate()复制代码
public class CartServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
//1.获取商品名称
String name = request.getParameter("name");
//2.获取购物车,实际上就是存入session的map
HashMap<String,Integer> map = (HashMap<String, Integer>) request.getSession().getAttribute("cart");
Integer num = null;
//3.判断购物车是否为空
if(map==null){
//3.1 购物车为空,说明是第一次将商品放入购物车
//先建立购物车,
map = new HashMap<>();
request.getSession().setAttribute("cart",map);
num = 1;
}else{
//3.2 购物车不为空,判断该商品以前是否已经加入购物车
num = map.get(name);
if(num == null){
//num==null,说明该商品以前未加入购物车
num = 1;
}else{
num ++ ;
}
}
map.put(name,num);
//4.提示信息
out.print("<center>已经将<b>"+name+"</b>添加到购物车中<hr></center>");
out.print("<center><a href='"+request.getContextPath()+"/category_list.jsp'>继续购物</a></center><br/>");
out.print("<center><a href='"+request.getContextPath()+"/cart.jsp'>查看购物车</a><center>");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}复制代码
<body>
<div class="container">
<a href="${pageContext.request.contextPath}/category_list.jsp">继续购物</a>
<a href="${pageContext.request.contextPath}/clearCart">清空购物车</a>
<div class="row">
<div style="margin:0 auto; margin-top:10px;width:950px;">
<strong style="font-size:16px;margin:5px 0;">订单详情</strong>
<table class="table table-bordered">
<tbody>
<tr class="warning" align="center">
<th>商品</th>
<th>数量</th>
</tr>
<%
HashMap<String,Integer> map = (HashMap<String,Integer>)request.getSession().getAttribute("cart");
if(map==null){
out.print("<tr><th colspan='2'>亲,购物车空空,先去逛逛~~</th></tr>");
}else{
for(String name : map.keySet()){
out.print("<tr class='active'>");
out.print("<td width='30%'>");
out.print(name);
out.print("</td>");
out.print("<td width='20%'>");
out.print(map.get(name));
out.print("</td>");
out.print("</tr>");
}
}
%>
</tbody>
</table>
</div>
</div>
</div>
</body>复制代码
public class ClearCartServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getSession().invalidate();
response.sendRedirect(request.getContextPath()+"/cart.jsp");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}复制代码
向客户端发送Cookie :
Cookie c =new Cookie("name","value"); //建立Cookie
c.setMaxAge(60*60*24); //设置最大时效,此处设置的最大时效为一天
response.addCookie(c); //把Cookie放入到HTTP响应中复制代码
从客户端读取Cookie :
String name ="name";
Cookie[]cookies =request.getCookies();
if(cookies !=null){
for(int i= 0;i<cookies.length;i++){
Cookie cookie =cookies[i];
if(name.equals(cookis.getName()))
//something is here.
//you can get the value
cookie.getValue();
}
}复制代码
优势: 数据能够持久保存,不须要服务器资源,简单,基于文本的Key-Value
缺点: 大小受到限制,用户能够禁用Cookie功能,因为保存在本地,有必定的安全风险。
在URL中添加用户会话的信息做为请求的参数, 或者将惟一的会话ID添加到URL结尾以标识一个会话。
优势: 在Cookie被禁用的时候依然可使用
缺点: 必须对网站的URL进行编码,全部页面必须动态生成,不能用预先记录下来的URL进行访问。
<input type="hidden" name ="session" value="..."/>复制代码
优势: Cookie被禁时可使用
缺点: 全部页面必须是表单提交以后的结果。
当一个用户第一次访问某个网站时会自动建立 HttpSession,每一个用户能够访问他本身的HttpSession。
能够经过HttpServletRequest对象的getSession方法得到HttpSession。 经过HttpSession的setAttribute方法能够将一个值放在HttpSession中, 经过调用 HttpSession对象的getAttribute方法,同时传入属性名就能够获取保存在HttpSession中的对象。
与上面三种方式不一样的是,HttpSession放在服务器的内存中,所以不要将过大的对象放在里面。 即便目前的Servlet容器能够在内存将满时将 HttpSession 中的对象移到其余存储设备中,可是这样势必影响性能。 添加到 HttpSession 中的值能够是任意Java对象,这个对象最好实现了 Serializable接口, 这样Servlet容器在必要的时候能够将其序列化到文件中,不然在序列化时就会出现异常。
总结: