什么是会话?它可以解决什么问题?
会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
一个客户端通过浏览器,新建会话窗口可以建立多个会话。
会话技术解决了http协议无状态。
简单说:使用会话技术,可以保存我们用户在一次会话过程中,所产生数据。request域和ServletContext域都无法满足需求
1.什么是Cookie
Cookie在英语里的解释是小甜点的意思
它是服务器发送到浏览器的少量信息,这些信息由浏览器保存,然后再发送回服务器。cookie 的值可以唯一地标识客户端,因此 cookie 常用于会话管理。
cookie的内容主要包括:名称,值,到期时间,路径和域。路径与域一起构成了cookie的范围。如果未设置到期时间,则表示此cookie的生命周期是在浏览器会话期间,浏览器窗口关闭,并且cookie消失。生命周期为浏览器会话的cookie称为会话cookie。会话cookie通常不存储在硬盘上,而是存储在内存中。当然,这种行为不受监管。如果设置了到期时间,浏览器会将cookie保存到硬盘,关闭它并再次打开浏览器。在超过设定的到期时间之前,这些cookie仍然有效。存储在硬盘上的Cookie可以在不同的浏览器进程之间共享,例如两个IE窗口。不同的浏览器对存储在内存中的cookie有不同的处理方法。会话机制使用维护服务器端状态的解决方案。
cookie本质是一个键值对,一个 cookie 拥有一个名称、一个值和一些可选属性,比如注释、路径和域限定符、最大生存时间和版本号。
下面通过一张图来了解Cookie,如图1-1所示:
图1-1 cookie介绍
浏览器第一次访问服务器后,服务器响应cookie给浏览器,下次浏览器再访问服务器时,只要浏览器端的cookie仍然存在,浏览器就会在访问服务器时将cookie带给服务器。
2.Http协议与Cookie的关系
Cookie是Http协议制定的,并不是Java语言独有的,PHT、.NET中也使用了cookie技术,因此只要是和HTTP协议相关,那么就可以使用cookie技术。
我们知道cookie是服务器创建的一个键值对,并保存在浏览器端。那么服务器是如何将cookie发送给浏览器的呢?
在服务器端先创建cookie,如 Cookie cookie=new Cookie(String name,String value),其中Cookie可以在javaeeAPI中查到的,详情可参考java_ee API。然后再通过response对象将cookie信息作为响应头发送到浏览器端。我们可以通过HttpWatch抓包工具查看响应信息,可以发现cookie是基于一个Set-Cookie响应头工作的,由于Set-Cookie响应头可以有多个,所以我们可以通过response.addHeader(String name,String value)方法发送Set-Cookie响应头,例如,有两个cookie,分别为one=aaa,two=bbb,其中one、two是cookie的名称,aaa、bbb是cookie的值。发送响应头如下所示:
response.addHeader(“Set-Cookie”,”one=aaa”);response.addHeader(“Set-Cookie”,”two=bbb”);
当浏览器再次访问服务器时,会将cookie送还给服务器。那么浏览器是如何将cookie带给服务器的呢?其实通过Cookie请求头传递过去的。请求头Cookie与响应头Set-Cookie有区别,多个cookie对应多个Set-Cookie响应头,但是只对应一个Cookie请求头,格式为:Cookie:one=aaa; two=bbb。即多个cookie之间用分号和空格隔开。
需要注意的是:cookie是不能跨浏览器的。例如,张三首先使用IE浏览器访问服务器,服务器发送了一个cookie,这个cookie只会保存在IE浏览器,如果再使用火狐浏览器访问服务器,服务器会再发送一个cookie个火狐浏览器,在火狐浏览器中不能获取IE浏览器中的cookie,同理IE浏览器也获取不到火狐浏览器中的cookie。
3.Http协议规定
Http协议对Cookie做了一些规定,如下所示:
l 一个Cookie的大小,最大为4KB;
l 一个服务器最多向一个浏览器保存20个Cookie;
l 一个浏览器最多可以保存300个Cookie。
我们知道,浏览器将服务器发送过来的cookie保存在本地磁盘,如果cookie过多,必然会加大浏览器的压力,因此Http协议对Cookie做了以上规定。
但是,目前浏览器之间因为竞争,很多都在一定范围内违反了Http规定,例如,一个浏览器最多保存的Cookie个数超过300个。但是也不会出现浏览器允许一个Cookie的大小超过4GB。
4.Cookie的用途
Cookie是会话跟踪技术,例如,当你访问淘宝网站时,淘宝网站主页上可能会显示你上一次浏览商品的记录。其实这个就是通过Cookie实现的,当然,cookie技术还有其他用途,如下所示:
l 服务器使用Cookie来跟踪客户端状态;
l 保存购物车(购物车中的商品不能保存在request域中,因为购物是用户向服务器发送多个请求);
l 显示用户上一次登录的登录名称。
l 网站可以利用cookies跟踪统计用户访问该网站的习惯,比如什么时间访问,访问了哪些页面,在每个网页的停留时间等。
Cookie的使用
1.在JavaWeb中使用Cookie
在Cookie介绍中,我们了解到Cookie是基于Set-Cookie响应头和Cookie请求头工作的,服务器通过response对象的addHeader()方法将cookie发送给浏览器,然后浏览器通过Cookie请求头将cookie再送回服务器。
Cookie中不能存中文,但可以把中文进行编码存进去,再进行解码取出来。
以上方式操作Cookie比较麻烦,现在我们学习一种简便的方式来操作Cookie,如下所示:
l 服务器发送Cookie
void addCookie(Cookie cookie):使用response对象调用该方法向浏览器端发送参数指定的Cookie;
l 服务器获取浏览器传递过来的Cookie
Cookie[] getCookies():使用request对象调用该方法获取浏览器发送的所有Cookie,该方法的返回值是一个Cookie类型的数组。
2.Cookie练习
通过以上对Cookie的学习,下面为了让大家更加熟练的掌握Cookie技术,我们来学习一个案例,具体如下:
(1)创建一个web应用,Example18,在该应用下的WebRoot根目录下新建一个jsp文件,saveCookie.jsp,主要代码如例1-1所示:
例1-1 savaCookie.jsp
<body>
<h1>保存cookie<h1>
<%
Cookie cookie1=new Cookie("one","aaa");
Cookie cookie2=new Cookie("two","bbb");
response.addCookie(cookie1);
response.addCookie(cookie2);
%>
</body>
例1-1中,新建了两个Cookie,并使用addCookie()方法将两个cookie发送给浏览器。其中response对象是jsp的九大内置对象之一,所以在这里可以直接使用。
(2)再次在Example18应用的WebRoot的根目录下新建一个jsp文件,getCookie.jsp,主要代码如例1-2所示:
例1-2 getCookie.jsp
<body>
<h1>获取cookie<h1>
<%
Cookie[] cookies= request.getCookies();
if(cookies!=null){
for(Cookie c:cookies){
out.print(c.getName()+"="+c.getValue()+"<br>");
}
}
%>
</body>
例1-2中,使用request调用getCookies()方法获得浏览器归还的所有cookie。如果浏览器没有发送过来任何cookie,那么该方法的返回值是null,因此我们操作cookies时要先判断它是否为null,避免出现空指针异常。
(3)将Example18发布到Tomcat服务器,然后启动服务器,在浏览器地址栏上输入:http://localhost:8080/Example18/saveCookie.jsp,并使用HttpWatch工具进行抓包,浏览器显示结果如图1-1所示:
图1-1 发送cookie
由图1-1可知,当在浏览器端访问saveCookie.jsp页面,浏览器一共收到三个cookie,其中一个名字为JSESSIONID的cookie会在后面的session课程中详细讲解。剩余两个cookie是我们在saveCookie.jsp页面中创建,然后向浏览器发送的。
(4)在浏览器端访问getCookie.jsp,访问地址为:http://localhost:8080/Example18/getCookie.jsp,浏览器显示结果如图1-2所示:
图1-2 浏览器显示结果
(5)使用HttpWatch工具抓取的结果,如图1-3所示:
图1-3 HttpWatch抓取结果
Cookie的过期时间设置
1.Cookie生存时间介绍
我们知道Cookie是一个键值对,但是Cookie不仅仅只有name和value属性,它还有以下几种属性:
(1)注释:描述此 cookie 的用途;
(2)路径:指的是浏览器将此 cookie 返回到服务器上的路径,并且该cookie 对于服务器上的所有子路径都是可见的。
(3)域限定符:创建 cookie时设置的域名,域名形式是根据 RFC 2109 设置的;
(4)最大生存时间:表示cookie的存活时间,过了设置的最大生存时间,该cookie就会死亡;
(5)版本号:表示cookie遵守的协议版本,版本 1遵守RFC 2109,版本0遵守根据 Netscape 起草的原始 cookie 规范。
本文档只对Cookie的最大生存时间进行讲解,其他属性后面会一一说明。
Cookie的过期时间即为Cookie的最大生存时间,可以通过以下方法进行设置,如下所示:
l void setMaxAge(int expiry)
该方法的参数的类型是整型,表示过期的时间,单位是秒。例如:cookie.setMaxAge(60)表示当前cookie会被浏览器保存在硬盘上,60秒后会被浏览器删除。
下面分情况说明cookie的setMaxAge()方法对cookie生存时间的设置,如下所示:
Ø setMaxAge()参数大于0:表示将当前cookie保存在硬盘上,保存时间由其参数决定;
Ø setMaxAge()参数小于0:无论该方法的参数是多少,只要小于0,则表示将当前cookie保存在浏览器内存中,浏览器关闭的同时cookie死亡;
Ø setMaxAge()参数等于0:表示浏览器将当前cookie及之前保存的同名cookie立即删除,例如刚开始在浏览器端保存了一个cookie,名称为history,保存时间为2天,现在希望将该history删除,这个时候就可以向浏览器端再次发送一个名字为history的cookie,生存时间设置为0。这个时候浏览器会将名字为history的所有cookie删除。
如果,在服务器端新建一个cookie,并没有给该cookie设置生存时间,那么表示:该cookie会在浏览器关闭的时候被浏览器删除。
2.Cookie设置生存时间练习
通过以上对cookie生存时间的了解,下面通过一个案例来直观的体会cookie的生存时间设置对cookie的影响,具体如下:
(1)创建一个web项目,Example19,在该应用下的WebRoot目录下新建一个jsp文件,名称为cookieSet.jsp,主要代码如例1-1所示:
例1-1 cookieSet.jsp
<body>
<h1>保存cookie</h1>
<%
Cookie cookie1=new Cookie("cookie1","aaa");
response.addCookie(cookie1);
%>
</body>
例1-1中,创建了一个cookie,但是并没有设置cookie的生存时间,通过以上对cookie生存时间的讲解,该cookie会在浏览器关闭的时候被销毁。
(2)将Example19发布到Tomcat服务器中,然后启动服务器,谷歌浏览器查看cookie比较方便,我们在谷歌浏览器端地址栏上访问:http://localhost:8080/Example19/cookieSet.jsp,浏览器显示结果如图1-1所示:
图1-1 浏览器显示结果
(3)查看谷歌浏览器中的cookie,点击图1-1所示的红色标注的图标,在下拉选项中选择【设置】,进入图1-2所示界面:
图1-2 查看cookie
(4)点击图1-2中的【内容设置】选项,进入图1-3所示界面:
图1-3 查看cookie
(5)点击图1-3中的【所有Cookie和网站数据…】按钮,进入图1-4所示界面:
图1-4 查看cookie
(6)点击图1-4所示的【cookie1】按钮,进入图1-5所示界面:
图1-5 cookie信息
由图1-5可知,名字为cookie1的cookie的过期时间为浏览会话结束时,即表示浏览器关闭,cookie被删除。
(7)关闭浏览器,再次打开浏览器,查看cookie1是否还存在,如图1-6所示:
图1-6 cookie信息
由图1-6所示,浏览器中已经不存在名为cookie1的cookie。
(8)对例1-1中的代码进行修改,如例1-2所示:
例1-2 cookieSet.jsp
<body>
<h1>保存cookie</h1>
<%
Cookie cookie1=new Cookie("cookie1","aaa");
cookie1.setMaxAge(60*60)
response.addCookie(cookie1);
%>
</body>
例1-2中,将cookie1的生存时间设置为1小时。
(9)在浏览器端再次访问cookieSet.jsp页面,查看浏览器中cookie1的保存时间,如图1-7所示:
图1-7 cookie信息
由图1-7可知,cookie1的保存时间是10:08:12,过期时间是:11:08:12,其生存时间正好是1个小时。
cookie1在浏览器端的存活时间是1小时,浏览器关闭后再打开,cookie1仍然存在,现在我们通过代码来将cookie1从浏览器端删除。
(10)在Example19应用的WebRoot目录下,新建一个jsp文件,名称为cookieGet.jsp,主要代码如例1-3所示:
例1-3 cookieGet.jsp
<body>
<h1>删除cookie</h1>
<%
Cookie cookie=new Cookie("cookie1","aaa");
cookie.setMaxAge(0);
response.addCookie(cookie);
%>
</body>
例1-3中,再次新建一个名字为cookie1的cookie,并且设置其过期时间为0,表示浏览器立即删除当前及之前保存的名字为cookie1的cookie。
(11)重新启动服务器,在浏览器端地址栏上输入:http://localhost:8080/Example19/cookieGet.jsp,然后查看浏览器端的cookie1是否还存在,如图1-8所示:
图1-8 查看cookie
由图1-8可知,浏览器端的cookie1已经不存在了,它原本的生存时间是1小时,经过cookieGet.jsp页面中代码的设置,没有到过期时间就被浏览器删除了。
对指定路径的cookie进行生存时间做修改,cookie.setMaxAge();方法调用后跟上cookie.setPath()方法。要不然会修改默认的当前cookie。
Cookie的路径和域
1. Cookie路径介绍
我们知道Cookie的属性有很多,其中有一个属性是路径。有些人认为Cookie的路径指的是Cookie在客户端的保存路径,其实并不是。
Cookie的路径是在服务器创建Cookie时设置的,它的作用是决定浏览器访问服务器的某个资源时,需要将浏览器端保存的那些Cookie归还给服务器。如图1-1所示:
图1-1 cookie路径
图1-1中,浏览器端保存的Cookie有三个,分别是Cookie1、Cookie2和Cookie3。它们三个的访问路径分别为:“/Example/cookie“、”/Example/“、”Example1/cookie“。浏览器访问服务器端的路径为:”http://localhost:8080/Example/cookie/a/index.jsp“。也就是说index.jsp页面的访问路径为:”/Example/cookie/a/“,该路径包含了Cookie1和Cookie2的路径,因此在访问index.jsp时,浏览器会将Cookie1和Cookie2发送给服务器。这就是Cookie的路径的作用,其中涉及到访问路径。
如果服务器创建Cookie时没有设置路径,那么该Cookie的路径是当前资源的访问路径。例如:在index.jsp页面中创建了一个Cookie,index.jsp页面的访问路径为“/Example/“,那么该Cookie的路径就是”/Example/“。如果服务器创建Cookie时设置了路径,那么Cookie的路径就是设置的路径,例如:cookie.setPath(“/Example/cookie”),那么该Cookie的路径就是”/Example/cookie“。
2. Cookie路径练习
通过上面对Cookie路径的介绍,我们对它有了一定的了解,现在通过一个案例来验证以上结论。具体步骤如下:
(1)创建一个web应用,Example20,在该应用下的WebRoot目录下新建一个目录cookie,并在该目录下新建一个jsp文件,名称为one.jsp,主要代码如例1-1所示:
例1-1 one.jsp
<body>
<%
Cookie cookie=new Cookie("one","hello");
response.addCookie(cookie);
%>
</body>
例1-1中,服务器创建cookie但是并没有设置其路径,那么该cookie的路径应为one.jsp的访问路径。
(2)将Example20发布到服务器,然后启动服务器,在谷歌浏览器端地址栏上输入:http://localhost:8080/Example20/cookie/one.jsp,然后查看cookie信息,如图1-2所示:
图1-2 cookie信息
由图1-2可知,cookie的路径是:“/Example20/cookie“,该路径正是one.jsp页面的访问路径。
(3)在WebRoot目录下的cookie目录中新建一个jsp文件,名称为two.jsp,主要代码如例1-2所示:
例1-2 two.jsp
<body>
<%
Cookie[] cookies=request.getCookies();
if(cookies!=null){
for(Cookie c:cookies){
out.print(c.getName()+"="+c.getValue()+"<br>");
}
}
%>
</body>
(4)重新启动服务器,在浏览器端地址栏上输入:http://localhost:8080/Example20/cookie/two.jsp,并使用浏览器的开发者工具,查看请求信息中的cookie,如图1-3所示:
图1-3 请求信息
由图1-3可知,在访问two.jsp页面时,浏览器将名称为one和JSESSIONID的cookie归还给服务器。因为two.jsp页面的访问路径也是“/Example20/cookie”。JSESSIONID能够发送过来是因为它的路径是“/Example20/”,也包含在访问路径中,因此被浏览器发送过来。
(5)在浏览器端访问Example20工程的index.jsp页面,访问路径为:http://localhost:8080/Example20,使用开发者工具查看请求信息,观察名称为one的cookie是否在请求信息中,如图1-4所示:
图1-4 请求信息
由图1-4可知,访问index.jsp页面时,浏览器只将名称为JSESSIONID的cookie发送给服务器,而名称为one的cookie并没有发送服务器,原因是index.jsp页面的访问路径是“/Example20/”,而one的访问路径是“/Example20/cookie”,index.jsp页面的访问路径并不包含one的路径。
需要注意的是,大家不要将包含的关系弄混淆了,是访问路径包含cookie的路径。例如,浏览器中保存如下几个cookie,它们的路径分别是:
aCookie.path=/Example20/;bCookie.path=/Example20/jsps/;cCookie.path=/Example20/jsps/cookie
l 访问路径是:http://localhost:8080/Example20/index.jsp
浏览器发送给服务器的cookie有:aCookie;
l 访问路径是:http://localhost:8080/Example20/jsps/a.jsp
浏览器发送给服务器的cookie有:aCookie,bCookie;
l 访问路径是:http://localhost:8080/Example20/jsps/cookie/b.jsp
浏览器发送给服务器的cookie有:aCookie,bCookie,cCookie。
3. Cookie的域
Cookie还有一个属性就是域,Cookie类中有设置和获取cookie域的方法,如下所示:
l Void setDomain(String pattern):设置cookie的域;
l String getDomain():获取cookie的域,返回值的类型是String类型。
其中Domain单词就有域名的意思。一般我们很少使用cookie的域,只有在多个二级域共享Cookie时才用。例如:www.baidu.com、zhidao.baidu.com、news.baidu.com、tieba.baidu.com这些域可以理解是百度的子项目,现在要在这些域中共享cookie,就需要使用cookie的域,使用时需要注意以下两点:
l 设置domain为:setDomain(".baidu.com”);
l 设置path为:setPath(“/”)。
我们如果要自己设置Cookie的域,需要在电脑上配置虚拟主机,下面大家按照以下的步骤操作,如下:
(1) 在C:WINDOWSsystem32driversetchosts文件中添加如下内容:
127.0.0.1 news.qdmmy6.com
127.0.0.1 tieba.qdmmy6.com
这两个域名后面两个单词要一致,如:qdmmy6.com。
(2) 在Tomcat的安装目录下的/conf/server.xml文件中添加如下配置:
<Host name="news.qdmmy6.com" appBase="news"
unpackWARs="true" autoDeploy="true">
<Value className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="tieba.qdmmy6.com" appBase="tieba"
unpackWARs="true" autoDeploy="true">
<Value className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
(3)点击此处下载资源,将它们解压后拷贝到Tomcat的安装目录下。
(4)启动Tomcat服务器,在浏览器端访问:http://news.qdmmy6.com/SaveServlet.使用HttpWatch或者其他开发者工具查看请求响应信息,观察cookie的信息。
(5)在浏览器端访问:http://tieba.qdmmy6.com/GetServle,使用HttpWatch或者其他开发者工具查看请求响应信息,观察cookie的信息。
Servlet中建立cookie
建立cookie
public class CookieDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cookie c = new Cookie("cname", "wfff");
c.setMaxAge(Integer.MAX_VALUE);
c.setPath(request.getContextPath());
c.setHttpOnly(true);//servlet3.0新特性,true表示防止客户端脚本访问浏览器缓存的cookie信息
response.addCookie(c);
response.getWriter().write("write cookie done");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
//读取写的cookie
public class CookieDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cookie cs[] = request.getCookies();
for(int i=0;cs!=null&&i<cs.length;i++){
if("cname".equals(cs[i].getName())){
response.getWriter().write(cs[i].getValue());
return;
}
}
response.getWriter().write("no cookie");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
HttpSession
1.HttpSession概述
javax.servlet.http包下的一个接口。
HttpSession是用来进行会话跟踪的接口,
Servlet的三大域对象
HttpSession对象是Servlet的三大域对象之一,其他两个域对象是request和application。application的类型是ServletContext。这三个域中,request的域范围最小,它的域范围是整个请求链,并且只在请求转发和包含时存在;session域对象的域范围是一次会话,而在一次会话中会产生多次请求,因此session的域范围要比request大;application的域范围是最大的,因为一个web应用只有唯一的一个application对象,只有当web应用被移出服务器或服务器关闭它才死亡,它的域范围是整个应用。
2. HttpSession相关知识
会话
会话是一个用户对服务器的多次连贯性的请求,所谓连贯性请求是指该用户的在多次请求的过程中没有关闭浏览器。而会话范围就是指某个用户从首次访问服务器开始到该用户关闭浏览器为止。
服务器会为每个用户创建一个session对象,当用户关闭浏览器,再次打开浏览器访问服务器时,服务器会为该用户创建一个新的session对象。当然,服务器不会只有一个用户访问,当多个用户访问服务器,服务器会为创建多个session对象,这些session对象都保存在一个Map中,而这个Map被称之为session缓存。当服务器关闭,该缓存就会被清空。
各种浏览器会话
谷歌浏览器关闭,在打开各种页面恢复,cookie中的sessionid没有变所以还是一个会话
edge关闭重新打开session就是使用了新的
如果把cookie删除然后再访问,这个时候sessionid已经变了,就是启用了一个新的session
获取HttpSession对象
在服务器端,例如在Servlet中,我们通过request对象的getSession()方法获取服务器为当前用户创建的session对象,即:HttpSession session=request.getSession()。
而在jsp中,session是jsp的内置对象,不用获取就可以直接使用。
我们知道每一个域对象都会有以下三个方法,HttpSession也不例外:
l void setAttribute(String name,Object value):向域中添加域属性;
l Object getAttribute(String name):从域中获取指定名称的属性值;
l Void removeAttribute(String name):移出域中指定名称的域属性。
session如何判断是同一个会话
session会在浏览器的cookie中保留sessionid,服务端session根据获取到的sessionid判断是不是同一个会话,如果浏览器关闭cookie不存在了就会新建session
(5)选择图1-2中的工具栏选项中的【文件】,在其下拉选项中选择【新建会话】,如图1-3所示:
图1-3新建一个会话
(6)点击图1-3中的“新建会话“,就打开一个新的会话,然后再次访问get.jsp,浏览器显示结果如图1-4所示:
图1-4 浏览器显示结果
图1-4中,输出null,表明没有从session中获取到数据。新建会话,表示重新开启一次会话,那么服务器会重新创建一个session对象,所以在get.jsp页面中通过request.getSession()获取到的session就是新创建的session,该session中并没有存放数据,所以才获取不到。
(7)在IE浏览器中再次访问save.jsp,往session中存放数据,然后再打开谷歌浏览器访问get.jsp,观察是否能从session中获得数据,浏览器显示结果如图1-5所示:
图1-5 谷歌浏览器显示结果
图1-5中,访问get.jsp没有获取到session中的数据,原因是:session是依赖于Cookie,而Cookie是不能跨浏览器的,也就是说使用IE浏览器访问save.jsp,服务器创建一个session对象,由于Cookie不能跨浏览器,所以使用谷歌浏览器访问时,服务器会创建另一个session对象,因此谷歌浏览器访问get.jsp不能获取到上一个session中的数据。
HttpSession案例分析
经过HttpSession第一例的练习,大家对session的用法有了一定的了解,下面我们来学习保存用户登录信息案例,该案例不仅使用了session对象,还使用了Cookie对象。将登录用户的信息保存在session中,将用户名保存在Cookie中实现记住用户名功能。下面我们就来详细介绍该案例:
(1)首先介绍该案例需要的页面和Servlet类,如下所示:
l login.jsp:登录页面;
l succ1.jsp:登录成功后访问的页面,没有登录不能访问;
l succ2.jsp:登录成功后访问的页面,没有登录不能访问;
l LoginServlet :校验用户是否登录成功。
(2)针对以上资源进行分析,具体如下:
l login.jsp:提供登录表单,表单中的字段有用户名和密码,表单提交的请求是LoginServlet;
l LoginServlet:获取请求参数,校验用户是否登录成功:
Ø 登录成功:保存用户信息到session域中,然后重定向到succ1.jsp页面,在succ1.jsp页面中显示当前登录的用户信息;
Ø 登录失败:将错误信息保存在request域中,然后请求转发到login.jsp页面,并在login.jsp页面显示错误信息;
l succ1.jsp:从session域中获取用户信息,如果不存在,保存错误信息到request域中,然后转发到login.jsp页面,在login.jsp页面显示错误信息“您还没有登录!请先登录!“;
l succ2.jsp:从session域中获取用户信息,如果不存在,保存错误信息到request域中,然后转发到login.jsp页面,在login.jsp页面显示错误信息“您还没有登录!请先登录!“。
通过以上分析可知,succ1.jsp和succ2.jsp的功能是一样的,都是成功页面,但是该成功页面在用户没有登录的情况下不能够访问。
下面通过一张图来了解保存用户登录信息案例的工作流程,如图1-1所示:
图1-1 案例序列图
图1-1中,如果用户是登录之后再访问succ1.jsp和succ2.jsp就可以看到用户信息,如果没有登录就访问succ1.jsp和succ2.jsp,那么就转发到login.jsp页面先进行登录。
HttpSession第二例
通过HttpSession案例分析,我们已经对保存用户信息案例的功能需求有了一定的了解,下面我们就来完成该案例,案例详情请参考HttpSession第二例步骤详解,点击此处下载案例源代码,具体操作步骤如下所示:
(1)新建一个web应用,Example22,在WebRoot目录下新建一个目录session,并在该目录下新建一个jsp文件,名称为login.jsp,主要代码如例1-1所示:
例1-1 login .jsp
<body>
<form action="/Example22/LoginServlet" method="post">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="password" name="password"/><br/>
<input type="submit" value="登录"/>
</form>
</body>
例1-1中,form表单的提交方式是post,提交的路径:“/Example22/LoginServlet“,其中”/LoginServlet“是Servlet类的访问路径,后面会说明。
(2)在session目录下再新建一个jsp文件,succ1.jsp。
(3)在session目录再新建一个jsp文件,succ2.jsp。
(4)在src目录下新建一个Servlet类,名称为LoginServlet,其访问路径配置为“/LoginServlet”,主要代码如例1-3所示:
例1-3 LoginServlet.java
public class LoginServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
* 1. 获取表单数据
*/
// 处理中文问题
request.setCharacterEncoding("utf-8");
// 获取
String username = request.getParameter("username");
String password = request.getParameter("password");
/*
* 2. 校验用户名和密码是否正确
*/
if(!"itcast".equalsIgnoreCase(username)) {//登录成功
/*
* 3. 如果成功
* > 保存用户信息到session中
* > 重定向到succ1.jsp
*/
HttpSession session = request.getSession();//获取session
session.setAttribute("username", username);//向session域中保存用户名
response.sendRedirect("/Example22/session/succ1.jsp");
} else {//登录失败
/*
* 4. 如果失败
* > 保存错误信息到request域中
* > 转发到login.jsp
*/
request.setAttribute("msg", "用户名或密码错误!");
RequestDispatcher qr=
request.getRequestDispatcher("/session/login.jsp");//得到转发器
qr.forward(request, response);//转发
}
}
}
例1-3中,首先获得请求参数,因为表单提交的方式是post,所以对于请求参数的乱码问题可以使用request的setCharacterEncoding("utf-8")方法处理乱码。获取的用户名如果是“itcast”就让它登录失败,将错误信息“用户名或密码错误”保存在request域,然后再转发到login.jsp页面。如果不是“itcast”就表示登录成功,将用户名保存在session域中,然后重定向到succ1.jsp页面。
(5)对login.jsp页面做一些补充,具体如例1-4所示:
例1-4 login.jsp
<body>
<%
String message = "";
String msg = (String)request.getAttribute("msg");//获取request域中的名为msg的属性
if(msg != null) {
message = msg;
}
%>
<font color="red"><b><%=message %> </b></font>
... ...此处省略例1-1中的代码
</body>
例1-4中,在login.jsp页面中,从request域中取出错误信息,这个时候我们要考虑到一个问题,如果直接将错误信息输出到浏览器端,会有一个问题,当用户直接访问login.jsp页面时,request域中还没有存放msg属性,因此msg的值为空,所以浏览器端会输出null。因此我们要先判断msg是否为空,如果不为空再将它输出到浏览器端。
(6)succ1.jsp页面信息如例1-5所示:
例1-5 succ1.jsp
<body>
<h1>succ1</h1>
<%
String username = (String)session.getAttribute("username");
if(username == null) {
/*
1. 向request域中保存错误信息,转发到login.jsp
*/
request.setAttribute("msg", "您还没有登录!请求先登录!");
request.getRequestDispatcher("/session/login.jsp").forward(request,
response);
return;
}
%>
欢迎欢迎,热烈欢迎,欢迎<%=username %>领导指导工作!
</body>
例1-5中,首先从session中获取登录的用户名,如果用户名username为空,则表明当前用户没有登录,就直接访问本页面,所以向request域中添加错误信息“您还没有登录!请先登录!”,然后转发到login.jsp页面,如果用户名username不为空就将用户名显示在页面中,如<%username%>。
(7)succ2.jsp和succ1.jsp内容相同,这里就不在叙述了。
(8)将Example22发布到Tomcat服务器,然后启动服务器,在浏览器端访问login.jsp,浏览器显示结果如图1-1所示:
图1-1 登录页面
(9)在图1-1中,输入用户名:itcast,密码123,然后点击“登录”按钮,浏览器显示结果如图1-2所示:
图1-2 登录失败
图1-2中,显示“用户名和登录错误“,说明登录失败,转发到了login.jsp页面。在LoginServlet中,我们设定的逻辑就是如果用户名为itcast,就表示登录失败。
(10)在图1-2中,输入用户名:aaa,密码:123,点击“登录“,浏览器显示结果如图1-3所示:
图1-3 登录成功
由图1-3可知,登录成功后重定向到succ1.jsp,地址栏上的地址改变,并且显示当前用户的名称:aaa。
(11)现在将浏览器窗口关闭,然后重新打开浏览器,在浏览器端访问succ1.jsp,浏览器显示结果如图1-4所示:
图1-4 访问失败
将浏览器关闭,那么之前登录后服务器创建的名为JSESSION的cookie就死亡了,那么对应的session就无法获取,session中保存的用户名也就无法获取。再次打开浏览器,访问succ1.jsp,服务器创建新的session,新的session中并不存在用户名信息,因此转发到login.jsp,然后显示“您还没有登录!请先登录!“。
(12)在图1-4中,输入用户名:aaa,密码:123,然后点击“登录“,这时session中就有了用户信息,succ2.jsp页面与succ1.jsp一样,所以现在访问succ2.jsp可以访问成功,如图1-5所示:
图1-5 访问succ2.jsp
图1-5中,成功的从session中获得用户信息,succ2.jsp访问成功。只要浏览器不关闭,在一定时间内用户的状态都是登录状态,无论访问succ1.jsp还是succ2.jsp都可以。
我们平时上网时,第一次登录某个网站点击了记住用户名,下次再访问该网站时,不用再输入用户名直接输入密码即可。这个是怎么做到的?其实是利用Cookie实现了记住用户名的功能。下面我们就来练习如何使用cookie记住用户名。
(13)用户第一次登录,如果登录成功,将其用户名保存在Cookie中,并且将Cookie的过期时间设置为一天后,然后发送给浏览器。现在我们对LoginServlet进行修改,如下所示:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
... ... 此处省略获取请求参数
if(!"itcast".equalsIgnoreCase(username)) {//登录成功
/*
* 附加项:把用户名保存到cookie中,发送给客户端浏览器
* 当再次打开login.jsp时,login.jsp中会读取request中的cookie,把它显示到用户名文本框中
*/
Cookie cookie = new Cookie("uname", username);//创建Cookie
cookie.setMaxAge(60*60*24);//设置cookie命长为1天
response.addCookie(cookie);//保存cookie
... ... 此处省略登录成功处理代码
} else {//登录失败
... ... 此处省略例1-3中登录失败处理代码
}
}
(14)再修改login.jsp页面,如例1-6所示:
例1-6 login.jsp
<body>
<%
/*
读取名为uname的Cookie!
如果为空显示:""
如果不为空显示:Cookie的值
*/
String uname = "";
Cookie[] cs = request.getCookies();//获取请求中所有的cookie
if(cs != null) {// 如果存在cookie
for(Cookie c : cs) {//循环遍历所有的cookie
if("uname".equals(c.getName())) {//查找名为uname的cookie
uname = c.getValue();//获取这个cookie的值,给uname这个变量
}
}
}
%>
... ... 此处省略1-4中代码
<form action="/Example22/LoginServlet" method="post">
用户名:<input type="text" name="username" value=”<%=uname%>”/><br/>
密 码:<input type="password" name="password"/><br/>
<input type="submit" value="登录"/>
</form>
</body>
例1-6中,首先获得所有Cookie,再遍历所有Cookie,然后查找名字为uname的cookie,如果找到,将该Cookie的值赋值给uname变量,然后将uname变量的值赋给名字为username的表单项的value属性。
(15)重新启动服务器,在浏览器端访问login.jsp,输入用户名:zhangsan,密码:123,然后点击“登录“按钮,如图1-6所示:
图1-6 登录
(16)登录成功后,将浏览器关闭,再打开浏览器,再次访问login.jsp,如图1-7所示:
图1-7 记住用户名
如图1-7所示,用户名zhagnsan回显在登录页面中,这就是记住用户名的实现原理。当时间超过一天,名字为uname的Cookie就会被浏览器杀死,这个时候在访问登录页面,就不会回显用户名。
HttpSession原理
通过HttpSession案例一和HttpSession案例二的学习,大家对HttpSession的用途有了一定的了解。今天我们来深入了解HttpSession的原理。学习HttpSession的原理对大家运用HttpSession有很大帮助。
1.HttpSession原理分析
首先,我们知道session对象是由服务器创建,并保存在服务器端。那么服务器在什么情况下创建session对象?浏览器在访问服务器时,服务器又是通过什么来找到对应的session对象呢?带着这些问题,我们来深入了解HttpSession。
1.1服务器如何识别session对象
session是依赖于Cookie的。浏览器访问服务器后,在浏览器端查看cookie时可以发现一个名为JSESSIONID的cookie。如图1-1所示:
图1-1 cookie信息
从图1-1可以看出,这个名字为JSESSIONID的cookie的值是A147B274C704729BA01624490C898757,并且过期时间为浏览会话结束时,即表示当浏览器关闭,该cookie就死亡。其实这个cookie的值就是当前会话session的id值。
服务器每次创建的session对象,都具有一个id属性,也是唯一标识的属性。服务器创建session后,将它的id值保存在cookie中,然后发送给浏览器。浏览器在一次会话中无论访问服务器的那个资源都会带着这个cookie,服务器会根据cookie的值找到对应的session,然后从session中取出数据。下面通过一张图形象理解这个过程们,如图1-2所示:
图1-2 浏览器与服务器之间传递session过程
调用request.getSession()方法是从名为JSESSIONID的cookie中获取session的id值,然后拿到这个id值去服务器的session缓存中查找对应session并返回。
session怎样保证一个浏览器有一个专属的session.
通过将session的id值存储到cookie中,每一次请求时,都将会id 值传递到服务器端,服务器端通过request.gtSession()时会判断是否存在这样id值的session对象,如果存在,会直接获取,如果不存在,会重新创建。
1.2服务器在什么情况下创建session对象
调用request.getSession()方法可以获得session对象,但并不是代表调用该方法服务器就会创建一个HttpSession对象,只有在一次会话中,第一次调用该方法时服务器才会创建一个session对象。
request.getSession()方法会查找请求信息中是否存在一个名为JSESSIONID的cookie,这个cookie是否存在会导致出现以下三种情况:
l Cookie不存在:
Cookie不存在,说明服务器还没有为本次会话创建session对象,这时服务器会创建一个session对象,并把这个session对象保存在session缓存中,然后将session的id值保存在一个cookie中,再把这个cookie发送给浏览器。
l Cookie存在,session的id值有对应的session对象:
拿到该cookie的值,即session的id值,然后根据id值去session缓存中查找到了对应的session对象,这时服务器不会重新创建session,而是将找到的session返回。
l Cookie存在,session的id值没有对应的session对象:
根据session的id值在session缓存中没有找到对应的session对象,这时服务器创建新的session,并将新session的id值保存在一个cookie中,然后响应给浏览器。
以上就是服务器创建session的对象的三种情况。另外,request对象还有其他两个方法可以获取session对象,分别是:
l request.getSession(false):这个方法的作用是:从cookie中取出session的id值,但是该id值没有对应的session,服务器不再创建新的session对象,返回null;
l request.getSession(true):该方法的作用和request.getSession()方法的作用一样。
HttpSession对象有最大不活动时间,默认的最大不活动时间是30分钟,也就是说,如果session对象长时间不被使用,30分钟后这个session对象就会失效。
2.验证HttpSession对象创建时机
(1)创建一个web应用,Example23,在该应用下新建一个Servlet类,SessionServlet,该Servlet类的访问路径为:“/SessionServlet“,主要代码如例1-1所示:
例1-1 SessionServlet.java
public class SessionServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("请查看是否有jsessionid这个cookie");
}
}
例1-1中,因为要向浏览器端响应中文,因此要设置响应信息编码以防乱码。
(2)将Example23发布到Tomcat服务器中,然后启动服务器,在浏览器地址栏上输入:http://localhost:8080/Example23/SessionServlet,浏览器显示结果如图1-3所示:
图1-3 浏览器显示结果
(3)查看浏览器中保存的cookie信息,如图1-4所示:
图1-4 cookie信息
由图1-4可知,该浏览器中并没有一个叫JSESSIONID的cookie,也就是说浏览器访问服务器端的SessionServlet,服务器并没有创建session对象。因为在SessionServlet中并没有调用request.getSession()方法。
(4)现在在浏览器端访问Example23应用的index.jsp页面,然后查看浏览器中的cookie信息,如图1-5所示:
图1-5 cookie信息
由图1-5可知,访问index.jsp页面后,浏览器中存在一个名为JSESSIONID的cookie,说明服务器创建了一个session对象。我们并没有在index.jsp页面调用request.getSession()方法,服务器为什么就创建session对象了?因为session是jsp页面的内置对象,服务器将jsp翻译成Java文件后,在该Java文件中存在一句代码,调用了getSession()方法。
(5)将浏览器中的cookie删除,然后修改SessionServlet,如下所示:
public class SessionServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.getSession();
response.getWriter().write("请查看是否有jsessionid这个cookie");
}
}
(6)重新启动服务器,在浏览器端访问SessionServlet ,然后查看浏览器的cookie信息,如图1-6所示:
图1-6 cookie信息
当在SessionServlet中添加request.getSession()代码,服务器就创建了session对象。
配置session最大不活动时间
1.HttpSession的相关方法介绍
HttpSession对象是域对象,我们知道只要是域对象都会有三个方法:getAttribute()、setAttribute(String name,Object value)和removeAttribute(String name)。除了这三个方法,HttpSession接口还有其他方法,下面我们进行一一介绍。
1.1 获取session id方法
HttpSession接口中定义的获取session id的方法是:
l String getId():返回分配给此会话的唯一标识符的字符串,标识符是由servlet容器即Tomcat服务器分配的,并且与实现相关。
下面我们来看请求信息中Cookie请求头的值,如图1-1所示:
图1-1 Cookie信息
由图1-1可知,JSESSION的值为3F95219AC8A0ADE5DB2D79C9A8850BA9,这个值就是session的id值,它是一个32位的十六进制的字符串。我们知道这个值是由服务器创建,并且每一次会话中session的id值都是唯一的。其实我们自己也可以生成这样的字符串,步骤如下所示:
(1)在一个web应用Example24中,新建一个Class类,UUIDTest,主要代码如例1-1所示:
例1-1 UUIDTest.java
public class UUIDTest {
@Test
public void fun1() {
UUID uuid = UUID.randomUUID();
String string = uuid.toString();
System.out.println(string);
string = string.replace("-", "");
System.out.println(string);
string = string.toUpperCase();
System.out.println(string);
}
}
在例1-1中,UUID是java.util包下的一个类,通过调用它的一个静态的randomUUID()方法可以获得一个随机生成的UUID,然后将这个UUID转换成String类型,再进行一系列操作将它转换成与JSESSIONID类似的字符串。
(2)测试fun1()方法,运行结果如图1-2所示:
图1-2 控制台运行结果
图1-2中,第一行打印的是UUID转换后的字符串,该字符串中包含有“-”,使用String类的replace(char oldChar,char newChar)方法将“-”替换掉,再将返回的值转换成大写的字母,就得到了与JSESSIONID类似的32位十六进制字符串。
(3)我们可以将这个测试方法写成一个帮助类,以后需要UUID时可以直接调用该方法获得一个32位的十六进制的字符串。下面我们新建一个类,CommonUtils,在该类中新建一个静态的方法名字为uuid(),主要代码如例1-2所示:
例1-2 CommonUtils.java
public class CommonUtils {
public static String uuid(){
return UUID.randomUUID().toString().replace("-", "").toUpperCase();
}
}
(4)有了这个帮助类,我们就可以在例1-1中的UUIDTest类中再定义一个测试方法fun2(),在该方法中调用CommonUtils类的uuid()方法获取一个uuid,例如:
@Test
public void fun2(){
System.out.println(CommonUtils.uuid());
}
(5)测试fun2()方法,控制台打印结果如图1-3所示:
图1-3 控制台打印结果
每一次执行fun2()方法,控制台打印的结果都不相同,因为UUID类每次调用randomUUID()方法都会获得一个唯一的UUID。
1.2 获取session的最大不活动时间
HttpSession接口中定义的获取session最大不活动时间的方法是:
l int getMaxInactiveInterval():
session默认的最大不活动时间是30分钟,表示:超过30分钟不使用session,服务器就会让这个session失效。可以使用setMaxInactiveInterval(int interval)方法设置session的最大不活动时间,该方法的参数的单位是秒,如果参数interval为负数则表示该session永远不会超时。
1.3使session失效的方法
l 服务器停止
HttpSession接口中定义了一个方法,该方法可以让当前session失效:
l void invalidate():
该方法可以使session失效,所谓的失效是指session还存在,但是已经不能再使用了。当session失效后,客户端再次请求,服务器会创建一个新的session对象,并在响应中将新session的id值通过cookie传递给客户端。
注销操作就是用这个方法完成的。
1.4判断当前session是否是新的
HttpSession接口还提供了一个方法用来判断session是否是新的:
l boolean isNew():
当客户端第一请求服务器时,服务器为本次会话创建一个session对象,这时服务器还没有将session的id值响应给客户端,那么这个session的状态就是新的,调用isNew()方法,返回值是true。我们知道调用request.getSession()方法服务器可能创建session,也可能返回一个session,那么调用以下方法:request.getSession().isNew()就可以判断当前session是服务器新创建的还是返回的。
2.配置session最大不活动时间
1、java程序中HttpSession session=request.getSession(), session.setMaxInactiveInterval(30 * 60); 单位是秒,如果设置的值为零或负数,则表示会话将永远不会超时。
2、在web.xml中的session-config配置
session-timeout元素用来指定默认的会话超时时间间隔,以分钟为单位。该元素值必须为整数。如果 session-timeout元素的值为零或负数,则表示会话将永远不会超时。如,设置session失效时间为30分钟:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
3、直接在应用服务器中设置
如果是tomcat,可以在tomcat目录下conf/web.xml中找到<session-config>元素,tomcat默认设置是30分钟。
<session-config>
<session-timeout>30</session-timeout>
</session-config>
Session钝化和激活
钝化:
服务器内存不够了,把最近不活动的session序列化到磁盘,在序列化之前你会收到监听事件,所以放在session中的对象要序列化
激活:
如果这个钝化的用户某个时候又访问了,服务器在内存没找到session,就去磁盘找,再反序列化到内存,这个时候你又会收到监听事件
Tomcat提供了两种Session钝化管理器:
org.apache.catalina.session.StandardManger
org.apache.catalina.session.Persistentmanager
StandardManager钝化机制是:
l 当Tomcat服务器被关闭或重启时,tomcat服务器会将当前内存中的Session对象钝化到服务器文件系统中;
l 另一种情况是Web应用程序被重新加载时,内存中的Session对象也会被钝化到服务器的文件系统中。
PersistentManager钝化机制
提供了比StandardManager更为灵活的Session钝化算法。首先在钝化的时刻选择上进行了扩张。第一种情况如上面1,第二种如上2,第三种情况,可以配置主流内存的Session对象数目,将不常使用的Session对象保存到文件系统或数据库,当用时再重新加载。
Tomcat两个钝化驱动类
默认情况下,Tomcat提供两个钝化驱动类,org.apache.Catalina.FileStore和org.apache.Catalina.JDBCStore。
前者将Session对象钝化到文件系统;后者用来将Session对象钝化到数据库(也可以钝化到指定文件)。
默认情况下钝化后的文件被保存路径:
Tomcat安装路径/work/Catalina/hostname/applicationname/SESSION.ser
补充
整个过程由服务器自动完成
你放入session的一切变量都必须是可序列化的,否则失败
URL重写
1.什么是URL重写
session是依赖于cookie或URL重写的,当浏览器端没有禁用Cookie,那么session就依赖cookie,即服务器会将session的id值存放在一个名为JSESSIONID的cookie中,浏览器再次访问服务器时,会将这个cookie带给服务器,这样在服务器端就可以根据获得session的id值找到对应的session,进而从session中获取数据。但是如果浏览器端禁用了cookie,就会出现如图1-1所示的情况:
图1-1 浏览器禁用cookie
由图1-1可知,如果浏览器端禁用了cookie,那么浏览器每次访问服务器时,服务器端只要调用了request.getSession()方法,服务器就会创建一个新的session对象。那么我们就不能再将数据保存在session中,因为新的session创建后,之前的session就无法获取了。
为了解决浏览器禁用cookie后所带来的问题,我们采用URL重写。所谓的URL重写就是将应用中的所有超链接、表单提交路径后面都添加一个特殊的请求参数,参数名为jsessionid,参数值为session的id值。当浏览器访问服务器时,在服务器端调用了request.getSession()方法,这个方法会在没有找到名为JSESSIONID的cookie的情况下,去请求参数中查找名为jsessionid的参数,并获取该参数的值,进而找到对应的session。
另外,需要注意的是,如果使用URL重写,那么应用中的所有超链接和表单提交路径都要进行URL重写,如果有一个超链接或表单路径没有进行URL重写,那么服务器就会认为没有为当前会话创建session,从而又为当前会话创建一个新的session,那么之前的session就无法获取了。
2.实现URL重写
使用以下两个操作就可以完成url重写:
response. encodeRedirectURL(java.lang.String url)
用于对sendRedirect方法后的url地址进行重写。
response. encodeURL(java.lang.String url)
用于对表单action和超链接的url地址进行重写
注意:以上操作,如果检测到浏览器禁用了cookie,会在路径上添加jsessionid值。
否则不会添加。
通过对URL重写的了解,下面我们通过一个案例来了解如何实现URL重写,具体如下:
(1)创建一个web应用,名称为Example25,对该应用下的index.jsp文件进行编辑,如例1-1所示:
例1-1 index.jsp
<body>
<h1>index.jsp页面</h1>
<a href="/Example25/url/one.jsp;jsessionid=<%=session.getId()%>">点击这里</a>
<%=session.getId() %>
</body>
例1-1中,在超链接中使用了URL重写,注意这里,如果URL后面跟的参数是jsessionid那么连接符就不再使用“?”而是使用“;”连接。
(2)在该应用下的WebRoot目录下新建一个目录url,并在该目录下新建一个jsp文件,one.jsp,主要代码如例1-2所示:
例1-2 one.jsp
<body>
<h1>one.jsp页面</h1>
<a href="/Example25/url/two.jsp;jsessionid=<%=session.getId()%>">点击这里
</a>
<%=session.getId() %>
</body>
在one.jsp中有一个超链接,该超链接也使用了URL重写。
(3)在url目录下新建一个jsp文件,two.jsp,主要代码如例1-3所示:
例1-3 two.jsp
<body>
<h1>two.jsp页面</h1>
<%=session.getId() %>
</body>
(4)将Example25发布到Tomcat服务器中,然后启动服务器,在浏览器端访问:http://localhost:8080/Example25/index.jsp,浏览器显示结果如图1-2所示:
图1-2 浏览器显示结果
(5)点击图1-2中的超链接“点击这里”,进入如图1-3所示界面:
图1-3 浏览器显示结果
(6)点击图1-3中的超链接“点击这里”,进入图1-4所示界面:
图1-4 浏览器显示结果
由图1-4、图1-3、图1-2可知,index.jsp、one.jsp以及two.jsp,这三个页面中的session是同一个session,也就是说使用URL重写与浏览器没有禁用cookie有一样的效果。
以上是我们手动在URL后面添加jsessionid,如果浏览器没有禁用cookie,那么在URL后面添加jsessionid参数就显得多余了。现在我们使用比较智能的URL重写:如果浏览器没有禁用cookie,那么就不进行URL重写,如果浏览器禁用了cookie就进行URL重写。
response.encodeURL(String url)方法可以实现智能的URL重写,该方法的参数是要进行URL重写的路径。
例如,将index.jsp页面中的手动URL重写换成智能的URL重写:
<body>
<h1>index.jsp页面</h1>
<%String url=response.encodeURL("/Example25/url/one.jsp"); %>
<a href="<%=url%>">点击这里</a>
<%=session.getId() %>
</body>
将浏览器设置为接受cookie,然后在浏览器端访问index.jsp页面,浏览器显示结果如图1-5所示:
图1-5 浏览器显示结果
设置浏览器禁用cookie,再次访问index.jsp页面,浏览器显示结果如图1-6所示:
图1-6 浏览器显示结果
由图1-5和图1-6可知,使用response.encodeURL(String url)方法可以实现智能的URL重写。
其他总结
http无状态
Http协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;
cookie和session都是为了弥补Http的无状态特性
cookie的用途
l 服务器使用Cookie来跟踪客户端状态;
l 保存购物车(购物车中的商品不能保存在request域中,因为购物是用户向服务器发送多个请求);
l 显示用户上一次登录的登录名称。
l 网站可以利用cookies跟踪统计用户访问该网站的习惯,比如什么时间访问,访问了哪些页面,在每个网页的停留时间等。
cookie的参数
key:设置的cookie的key。
value:key对应的value。
max_age:改cookie的过期时间,如果不设置,则浏览器关闭后就会自动过期。
expires:过期时间,应该是一个datetime类型。
domain:该cookie在哪个域名中有效。一般设置子域名,比如cms.example.com。
path:该cookie在哪个路径下有效。
cookie的生命周期
Cookie在生成时就会被指定一个Expire值,这就是Cookie的生存周期,在这个周期内Cookie有效,超出周期Cookie就会被清除。有些页面将Cookie的生存周期设置为“0”或负值,这样在关闭浏览器时,就马上清除Cookie,不会记录用户信息,更加安全。
session的生命周期
1:创建时机
1:这个浏览器在servlet中第一次使用session的时候会创建;
2:这个浏览器第一次访问jsp的时候,服务器也会为这个浏览器创建一个session对象;
2:销毁时机
1:程序员调用invalidate方法;(立刻销毁)
2:设置的存活时间到了;(tomcat默认是30分钟)
3:服务器非正常关闭;(突然断电)
注意事项:
1:正常关闭服务器,session不会销毁,而是直接序列化到硬盘上,下一次服务器启动的时候,会重新创建出来;
2:如果浏览器单方面关闭会话,服务器上对应的session不会死亡 ,但是会导致服务器给浏览器创建的JSESSIONID的cookie死亡,当cookie死亡后,会导致浏览器无法找到上一个session对象,会造成服务器中session死亡的假象;
服务器判断请求是属于同一个会话
答:用Session id区分,Session id相同的即认为是同一个会话,在Tomcat中Session id用JSESSIONID表示;
cookie和session对比
cookie和session一般都是为了存储用户相关的数据
cookie存于客户端,session存于服务器端。
cookie数据大小一般不超过4kB
Cookie是由Http协议制定的,在请求信息和响应信息中分别对应了Cookie请求头和Set-Cookie响应头,并且Cookie是由服务器创建,保存在客户端。而HttpSession对象也是由服务器创建,但是与Cookie不同的是,它保存在服务器端。
session底层是依赖Cookie的,如果浏览器禁用Cookie则session会依赖URL重写。
cookie和session的结合使用
在如今的市场或者企业里,一般有两种存储方式:
1、存储在服务端:通过cookie存储一个session_id,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个session_id,下次再次请求的时候,会把该session_id携带上来,服务器根据session_id在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。
2、将session数据加密,然后存储在cookie中。这种专业术语叫做client side session。flask采用的就是这种方式,但是也可以替换成其他形式。