会话跟踪技术----cookie和session
Cookie
什么叫Cookie
Cookie 是网站用来在客户端保存识别用户的一种小文件
一般用Cookie可以保存用户登录信息、购物数据信息等一系列微小信息。
其实Cookie就是一个键和一个值构成的,随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie、再发送给服务器。
注意,不同浏览器之间是不共享Cookie的。
Cookie与HTTP头
Cookie是通过HTTP请求和响应头在客户端和服务器端传递的:
Cookie:请求头,客户端发送给服务器端;
格式:Cookie: a=A; b=B; c=C。即多个Cookie用分号离开;
Set-Cookie:响应头,服务器端发送给客户端;
一个Cookie对象一个Set-Cookie:
Set-Cookie: a=A
Set-Cookie: b=B
Set-Cookie: c=C
Cookie的覆盖
如果服务器端发送重复的Cookie那么会覆盖原有的Cookie,
如客户端的第一个请求服务器端发送的Cookie是:Set-Cookie: a=A;第二请求服务器端发送的是:Set-Cookie: a=AA,那么客户端只留下一个Cookie,即:a=AA。
Cookie示例(Servlet)
服务端ServletA将一个键值对 以Cookie的形式响应给客户端,客户端存储在本地,然后再访问ServletB,ServletB得到请求中的所有Cookie ,并在控制台打印出来。
我们这个案例是,客户端访问AServlet,AServlet在响应中添加Cookie,浏览器会自动保存Cookie。然后客户端访问BServlet,这时浏览器会自动在请求中带上Cookie,BServlet获取请求中的Cookie打印出来。
注:
使用repsonse.addCookie()方法向浏览器保存Cookie
使用request.getCookies()方法获取浏览器归还的Cookie
代码实现:
AServlet.java
/**
* 给客户端发送Cookie
* @author Administrator
*
*/
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String id = UUID.randomUUID().toString();//生成一个随机字符串
Cookie cookie = new Cookie("id", id);//创建Cookie对象,指定名字和值
response.addCookie(cookie);//在响应中添加Cookie对象
response.getWriter().print("已经给你发送了ID");
}
}
BServlet.java
/**
* 获取客户端请求中的Cookie
* @author Administrator
*
*/
public class BServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
Cookie[] cs = request.getCookies();//获取请求中的Cookie
if(cs != null) {//如果请求中存在Cookie
for(Cookie c : cs) {//遍历所有Cookie
if(c.getName().equals("id")) {//获取Cookie名字,如果Cookie名字是id
response.getWriter().print("您的ID是:" + c.getValue());//打印Cookie值
}
}
}
}
}
Cookie的生命
**setMaxAge(int)**来设置Cookie的有效时间, 以秒为单位
**cookie.setMaxAge(60)**表示这个Cookie会被浏览器保存到硬盘上60秒。
cookie.setMaxAge(-1):cookie的maxAge属性的默认值就是-1,表示只在浏览器内存中存活。一旦关闭浏览器窗口,那么cookie就会消失。
cookie.setMaxAge(0):cookie生命等于0是一个特殊的值,它表示cookie被作废!也就是说,如果原来浏览器已经保存了这个Cookie,那么可以通过Cookie的setMaxAge(0)来删除这个Cookie。无论是在浏览器内存中,还是在客户端硬盘上都会删除这个Cookie。
创建Cookie,名为lasttime,值为当前时间,添加到response中;
在AServlet中获取请求中名为lasttime的Cookie;
如果不存在输出“您是第一次访问本站”,如果存在输出“您上一次访问本站的时间是xxx”;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//创建Cookie对象,名为lasttime,值为当前时间
Cookie cookie = new Cookie("lasttime", new Date().toString());
//设置Cookie在客户端的有效时间为1小时
cookie.setMaxAge(60 * 60);
//添加Cookie到response中
response.addCookie(cookie);
//获取请求中的Cookie
Cookie[] cs = request.getCookies();
String s = "您是首次访问本站!";
if(cs != null) {//如果请求中存在Cookie
for(Cookie c : cs) {//循环遍历请求中的Cookie
//如果Cookie名为lasttime
if(c.getName().equals("lasttime")) {
s = "您上次的访问时间是:" + c.getValue();
}
}
}
//打印s到客户端
response.getWriter().print(s);
}
Cookie中保存中文
Cookie的name和value都不能使用中文,如果希望在Cookie中使用中文,那么需要先对中文进行URL编码,然后把编码后的字符串放到Cookie中。
向客户端响应中添加Cookie
//使用URL编码
String name = URLEncoder.encode("姓名", "UTF-8");
String value = URLEncoder.encode("张三", "UTF-8");
//编码后的字符串保存到Cookie中
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) {
//把Cookie的name和value使用URL解码后再打印
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);
}
HttpSession
什么是HttpSesssion
javax.servlet.http.HttpSession是由JavaWeb提供的,用来会话跟踪的类。session是服务器端对象,保存在服务器端!!!
HttpSession接口表示一个会话,我们可以把一个会话内需要共享的数据保存到HttSession对象中!
获取HttpSession对象
HttpSession request.getSesssion():如果当前会话已经有了session对象那么直接返回,如果当前会话还不存在会话,那么创建session并返回;
HttpSession request.getSession(boolean):当参数为true时,与requeset.getSession()相同。如果参数为false,那么如果当前会话中存在session则返回,不存在返回null;
HttpSession是域对象
我们已经学习过HttpServletRequest、ServletContext,它们都是域对象,现在我们又学习了一个HttpSession,
它也是域对象。它们是Servlet的三大域对象。
HttpServletRequest:一个请求创建一个request对象,所以在同一个请求中可以共享request,
例如一个请求从AServlet转发到BServlet,那么AServlet和BServlet可以共享request域中的数据;
ServletContext:一个应用只创建一个ServletContext对象,
所以在ServletContext中的数据可以在整个应用*享,只要不启动服务器,
那么ServletContext中的数据就可以共享
HttpSession:一个会话创建一个HttpSession对象,
同一会话中的多个请求中可以共享session中的数据;
HttpSession和HttpServletRequest、ServletContext 一样 有着如下域方法
void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,
例如:session.setAttribute(“xxx”,“XXX”),在session中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。
请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;
Object getAttribute(String name):用来获取session中的数据,当前在获取之前需要先去存储才行,
例如:String value = (String) session.getAttribute(“xxx”);,获取名为xxx的域属性;
void removeAttribute(String name):用来移除HttpSession中的域属性,
如果参数name指定的域属性不存在,那么本方法什么都不做;
Enumeration getAttributeNames():获取所有域属性的名称;
登录案例
需要的页面:
login.html:登录页面,提供登录表单;
Index1Serlvet:回写当前用户名称,如果没有登录,显示您还没登录;
index2Serlve回写当前用户名称,如果没有登录,显示您还没登录
LoginServlet:在login.html页面提交表单时,请求本Servlet。在本Servlet中获取用户名、密码进行校验,如果用户名、密码错误,显示“用户名或密码错误”,如果正确保存用户名session中,然后重定向到index1Servlet;
当用户没有登录时访问index1Servlet或index1Servlet,显示“您还没有登录”。如果用户在login.html登录成功后到达index1Servlet页面会显示当前用户名,而且不用再次登录去访问index2Servlet也会显示用户名。因为多次请求在一个会话范围,index1Servlet和index2Servlet都会到session中获取用户名,session对象在一个会话中是相同的,所以都可以获取到用户名!
public class LoginServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获取表单参数username
String username = request.getParameter("username");
//如果用户为root表示登录失败
if(username.equalsIgnoreCase("scott")) {
response.getWriter().print("用户名或密码错误!");
} else {
//获取session对象
HttpSession session = request.getSession();
//在session中保存用户名
session.setAttribute("username", username);
//重定向指定的页面。
response.sendRedirect("/index1Servlet");
}
}
}
HTTP协议是无状态协议。JavaWeb服务器是无法记录客户端浏览器的身份的。若需要实现回话跟踪,也需要使用一个标识。
当客户端浏览器首次访问服务器端的时候,并且当服务器首次使用session 此时要创建session,session是保存在服务器端(这个Session中可以保存一些数据)。然后,响应客户端浏览器的时候,会将这个Session的ID以Cookie的形式返回给客户端浏览器,这个SessionID在客户端就以Cookie的形式保存了。
当客户端再次访问服务器时,在请求中会带上sessionId,而服务器会通过sessionId找到对应的session,而无需再创建新的session。这样,服务器就辨识出了哪个客户端回话了。
session与浏览器
session保存在服务器,而sessionId通过Cookie发送给客户端,但这个Cookie的生命为-1,即只在浏览器内存中存在,也就是说如果用户关闭了浏览器,那么这个Cookie就丢失了。
当用户再次打开浏览器访问服务器时,就不会有sessionId发送给服务器,那么服务器会认为你没有session,所以服务器会创建一个session,并在响应中把sessionId中到Cookie中发送给客户端。
session其他常用API
String getId():获取sessionId;
int getMaxInactiveInterval():获取session可以的最大不活动时间(秒),默认为30分钟。当session在30分钟内没有使用,那么Tomcat会在session池中移除这个session;
**void setMaxInactiveInterval(int interval):**设置session允许的最大不活动时间(秒),如果设置为1秒,那么只要session在1秒内不被使用,那么session就会被移除;
**long getCreationTime():**返回session的创建时间,返回值为当前时间的毫秒值;
long getLastAccessedTime():返回session的最后活动时间,返回值为当前时间的毫秒值;
**void invalidate():让session失效!**调用这个方法会被session失效,当session失效后,客户端再次请求,服务器会给客户端创建一个新的session,并在响应中给客户端新session的sessionId;
**boolean isNew():**查看session是否为新。当客户端第一次请求时,服务器为客户端创建session,但这时服务器还没有响应客户端,也就是还没有把sessionId响应给客户端时,这时session的状态为新。
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
//使用request对象的getSession()获取session,如果session不存在则创建一个
HttpSession session = request.getSession();
//获取session的Id
String sessionId = session.getId();
//判断session是不是新创建的
if (session.isNew()) {
response.getWriter().print("session创建成功,session的id是:"+sessionId);
}else {
response.getWriter().print("服务器已经存在该session了,session的id是:"+sessionId);
}
}