会话
用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
保存会话数据的两种技术
- Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
- Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时可以把各自的数据放在各自的session中,当用户再去访问服务器中的其他web资源时,其他web资源再从用户各自的session中取出数据为用户服务。
Cookie
Cookie是客户端技术,服务器把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。cookie原理:
浏览器第一次访问服务器时,没带有cookie,访问完Servlet1之后带有cookie信息回送给浏览器,存在缓存区。当浏览器第二次访问服务器时就已经带着缓存中的Cookie了,Servlet2此时就知道用户原本购买的信息了。
Cookie API
我们先看一下官方文档的对于Cookie的介绍。
javax.servlet.http.Cookie创建一个Cookie,response接口也定义了一个addCookie方法,它用于在其响应头中增加一个相应的SetCookie头字段。同样,request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。Cookie类方法:
- public Cookie(String name, String value) //构造方法
- setValue getValue
- setMaxAge getMaxAge //设置Cookie有效期,不调这个方法 Cookie有效期是浏览器进程周期(用户打开浏览器到用户关闭浏览器)
- setPath getPath //Cookie的有效目录 默认的有效路径是哪个Servlet发出去的就是哪个servlet下的目录
- setDomain getDomain // 设置域 如 .sina.com.cn
- getName
Cookie的应用:获取最近访问时间,与清除Cookie
- 创建模拟网站首页的Servlet,
package com.xuda27.cookie;
import java.io.IOException;
import java.io.PrintWriter;
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 CookieTest1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//服务器向浏览器发送数据 编码以utf-8格式
response.setCharacterEncoding("utf-8");
//通知浏览器以utf-8打开数据
response.setContentType("text/html charset=utf-8");
PrintWriter out = response.getWriter();
out.print("<a href='/JavaWeb_CookieSession/servlet/CookieTest2'>清除Cookie</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());
}
}
//给用户回送最新的访问时间
//创建名为 lastAccessTime,值为系统当前时间的Cookie
Cookie cookie = new Cookie("lastAccessTime", System.currentTimeMillis()+"");
cookie.setMaxAge(30*24*3600);//cookies有效期 30天
cookie.setPath("/JavaWeb_CookieSession");//设置cookie的有效路径:当前工程
response.addCookie(cookie);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}
后台处理servlet:
package com.xuda27.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
* @author eden
*
*/
public class CookieTest2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//Cookie与前面的要长得一样
Cookie cookie = new Cookie("lastAccessTime",System.currentTimeMillis()+"");
cookie.setMaxAge(0);//清除
cookie.setPath("/JavaWeb_CookieSession");//路径要设置一样
response.addCookie(cookie);//浏览器增加空的cookie
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
测试结果:
我们打开firebug可以看到Cookie信息。
当我第一次访问CookieTest1(代表网站首页)时,没有带有Cookie信息所以就没有显示上一次访问的时间,然后Servlet才创建Cookie信息,然后在当我刷新页面时,Servlet就会发现有Cookie信息,这时就把上一次访问的时间给显示出来。当点击清除Cookie时,跳转到cookieTest2(代表后台处理),此时Servlet创建一个空的Cookie将原来Cookie信息覆盖,所以当我再一次访问CookieTest1时,上一次访问时间就没有了。
Cookie的一些细节
- 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置(VALUE)。
- 一个Web站点可以给一个web浏览器发送多个Cookie,一个Web浏览器可以存储多个web站点提供的Cookie。
- 浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
- 如果创建了一个cookie,并将它发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要是要maxAge,并给出一个以秒为单位的时间。将最大时间设为0则是命令浏览器删除该cookie。
- 注意,删除Cookie时,path必须一致,否则不会删除
Session
Session是服务器端技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,用户可以在访问服务器的web资源时,可以把各自的数据放在各自的session中,所以session跟ServletContext和Request一样也是域对象。当用户再去访问服务器中的其它web资源时,其它web资源就可以从用户各自的session中取出数据为用户服务。
Session的生命周期
Session域的作用范围是:默认情况下是在一个会话期间,当然这个范围我们是可以设置的,设置之后可以在多个会话之间。那么Session的生命周期是:
1. Session什么时候创建:
Servlet调用HttpServletRequest.getSession(true)这样的语句时才会被创建。
2. Session什么时候销毁:
Session在下列情况下被删除:
- 程序调用HttpSession.invalidate()
- 距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
- 服务器进程被停止
再次注意关闭浏览器只会使存储在客户端浏览器内存中的session的cookie失效,不会使服务器端的session对象失效。
Session实现原理
服务器创建session出来后,会把session的id号,以cookie的形式回写给浏览器,这样,只要浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现浏览器带session id过来了,就会使用内存中与之对应的session为之服务。
图解:
浏览器访问Servlet1时,通过调用request.getSession()方法判断服务器中是否含有该session,如果没有则创建,如果有直接调用。因为第一次调用则创建session,并获取session的id,将这个id以Cookie形式会写给浏览器。当浏览器带着Cookie访问servlet2时,调用request.getsession 服务器发现服务器端的session id与cookie的值是否相同,相同直接为它服务。
内部原理,用代码实现 类似这样:
//获取session的Id
String sessionId = session.getId();
//将session的Id存储到名字为JSESSIONID的cookie中
Cookie cookie = new Cookie("JSESSIONID", sessionId);
//设置cookie的有效路径
cookie.setPath(request.getContextPath());
response.addCookie(cookie);
Session的相关API
- getAttribute(String name)/getAttributeNames()/setAttribute(String
name)/removeAttribute(String name) 这些方法都是和Session域中的值有关的方法,和ServletContext,Request域的是一样 - getCreationTime():获取Session的创建时间
- getId():获取session的id
- getServletContext():获取ServletContext对象,即jsp中的application
- invalidate():删除session,然后取消对任何绑定到它的对象的绑定。
- setMaxInactiveInterval(int interval):这个方法设置session的最大有效时间,以秒为单位。负数时间指示session永远不会超时。
修改session默认生命周期:
HttpSession session = request.getSession();
String sessionId = session.getId();
Cookie cookie = new Cookie("JSESSIONID", sessionId);
cookie.setPath("/JavaWeb_CookieSession");//设置session的有效路径,覆盖默认的session的路径
cookie.setMaxAge(30*60);//设置时长为30分钟
response.addCookie(cookie);
session.setAttribute("name", "你好!世界!");
取出session中的值:
resp.addHeader("content-type", "text/html;charset=utf-8");
resp.setCharacterEncoding("utf-8");
PrintWriter out = resp.getWriter();
String name = (String) req.getSession().getAttribute("name");
out.print(name);
如果浏览器禁用Cookie中就无法使用上面的代码来取得存在Cookie中的session id,无法与服务器中的session id匹配。
所以在浏览器禁用Cookie时,怎么来解决session的数据共享问题呢?
- response.encodeRedirectURL(java.lang.String url)
用于对sendRedirect方法后的url地址进行重写。 - response.encodeURL(java.lang.String url)用于对表单action和超链接的url地址进行重写
response.addHeader("content-type", "text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
//创建session
request.getSession();
//会在原有的url后面加上 JSESSIONID 地址重写
String url1 = response.encodeURL("/JavaWeb_CookieSession/servlet/SessionTest1");
String url2 = response.encodeURL("/JavaWeb_CookieSession/servlet/SessionTest2");
out.print("<a href='"+url1+"'>说</a><br>");
out.print("<a href='"+url2+"'>看</a>");
在禁用Cookie之后,这两个方法会给地址重写。
它会在原有的地址后面加上 session id号。而如果不禁用Cookie则超链接的地址则不会重写。
Session和Cookie的主要区别
- cookie是把用户的数据写给用户的浏览器。
- session把用户的数据写到用户独占的session中。
- session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
三个域对象的总结
- 产生数据之后,显示完了就没用了,就用request。
- 产生数据之后,除了显示等一会还有用,就用session。
- 产生数据之后,除了显示等一会还要给别人用,就用servletContext。