什么是会话,在日常生活中我们从接电话到挂断电话的过程,就是一次会话的过程。在Web应用中,也会产生类似打电话的过程,它指的是客户端(浏览器)和web服务器之间连续发生的一系列请求和响应的过程。
为了保存会话过程中产生的数据,Servlet技术中,提供了两个用于保存会话数据的对象,Cookie和Session。
什么是Cookie呢,当用户通过浏览器访问服务器时,服务器就会给用户浏览器返回一些信息,这些信息就会保存在Cookie中,这样当用户再次访问服务器时,就会在请求头中将Cookie发送给服务器,方便服务器对浏览器做出正确的响应。
服务器在给客户端发送Cookie时,会在Http响应头字段中中添加Set-Cookie响应头字段:Set-Cookie:user=test;Path=/;其中,user是Cookie的名称,test是它的值,Paht表示Cookie的属性,Cookie都是以键值对的方式存放的,其属性可以有多个,以;隔开。一旦用户浏览器接收了服务器发送的Cookie信息,那么它会保存在浏览器的缓存区中,后续的访问服务器中的,都会带上Cookie访问。
Constructor Summary | |
---|---|
Cookie(String name,String value) Constructs a cookie with a specified name and value. |
一旦创建了,name是不能更改的,而value是可以修改的
Cookie操作的主要方法
Method Summary | |
---|---|
Object | clone() Overrides the standard java.lang.Object.clone method to return a copy of this cookie.覆写Object类的clone方法,拷贝一份新的Cookie对象 |
String | getComment() Returns the comment describing the purpose of this cookie, or null if the cookie has no comment.返回该Cookie的描述 |
String | getDomain() Returns the domain name set for this cookie. 返回Cookie的有效域 |
int | getMaxAge() Returns the maximum age of the cookie, specified in seconds, By default, -1 indicating the cookie will persist until browser shutdown.返回Cookie的生存期,如果为-1,表示浏览器关闭,则立即清除 |
String | getName() Returns the name of the cookie. 返回Cookie的名称 |
String | getPath() Returns the path on the server to which the browser returns this cookie. 返回cookie的有效目录路径 |
boolean | getSecure() Returns true if the browser is sending cookies only over a secure protocol, orfalse if the browser can send cookies using any protocol.如果该Cookie采用的是安全协议,则返回true,否则返回false |
String | getValue() Returns the value of the cookie. 返回Cookie的值 |
int | getVersion() Returns the version of the protocol this cookie complies with. 返回Cookie采用的协议版本 |
void | setComment(String purpose) Specifies a comment that describes a cookie's purpose. 设置该Cookie的描述 |
void | setDomain(String pattern) Specifies the domain within which this cookie should be presented. 设置Cookie的有效域 |
void | setMaxAge(int expiry) Sets the maximum age of the cookie in seconds. 设置最大生存期,单位秒 |
void | setPath(String uri) Specifies a path for the cookie to which the client should return the cookie. 设置有效路径 |
void | setSecure(boolean flag) Indicates to the browser whether the cookie should only be sent using a secure protocol, such as HTTPS or SSL. 设置cookie的传输协议 |
void | setValue(String newValue) Assigns a new value to a cookie after the cookie is created. 设置cookie的值 |
void | setVersion(int v) Sets the version of the cookie protocol this cookie complies with. 设置Cookie的协议版本 |
1、setMaxAge(int expiry)和getMaxAge()方法
设置和返回Cookie在浏览器中保存的有效秒数,为正整数,则从当前时间算起,没有超过该秒数之前,Cookie会一直保留在浏览器本地缓存中,为负数,则会在浏览器关闭的时候清除该Cookie,如果设置为0,则通知浏览器立刻删除Cookie,默认情况,Max-Age属性值为-1。
2、setPath(String uri)和getPath()方法
上面两个方法是针对Cookie的Path属性的。如果创建Cookie对象时没有设置path属性,表示该Cookie对当前访问路径下的所有目录和子目录都有效,如果想让某个Cookie项对站点的所有目录下的访问路径都有效,则设置为 “/”。
3、setDomain(String pattern)和getDomain()方法
上面两个方法是针对Cookie的Domain属性的,指定浏览器访问的域。当设置Domain属性时,其值必须以"."开头,如Domain=.winlu.cn 。默认情况下,demoain属性的值为当前的主机名,浏览器在访问当前主机下的资源时,都会将Cookie信息返回给服务器。Domain属性是不区分大小写的。
Cookie案例:显示用户上一次访问的时间
package cookie;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
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 CookieDemo01 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//将最后访问时间存放在Cookie中
Date lastAccessTime = null;
//遍历Cookies
Cookie[] cookies = request.getCookies();
if(cookies != null){
for (Cookie cookie : cookies) {
String cookieName = cookie.getName();
if("lastAccessTime".equals(cookieName)){
try {
lastAccessTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(cookie.getValue());
} catch (ParseException e) {
e.printStackTrace();
}
break;
}
}
}
if(lastAccessTime != null){
System.out.println("上一次访问服务器的时间:"+lastAccessTime);
}else{
System.out.println("第一次访问服务器");
}
Cookie cookie = new Cookie("lastAccessTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
response.addCookie(cookie);
}
}
Cookie技术可以将用户的信息保存在各自的浏览器中,并且可以在多次请求下实现数据共享,但是如果传递过多,会增加服务器端处理的难度,这是就可以使用session来实现将会话数据保存到服务器的端。
什么是session呢?当浏览器访问web服务器时,servlet容器会创建一个Session对象和ID属性,当客户端后续访问服务器时,只需要将标识号传递给服务器,服务器就可以判断出请求是哪个客户端发送的,从而选择对应的session对象为其服务。由于客户端需要接收、记录和回送Session对象的ID,因此,通常情况下,session是借助Cookie技术来实现的ID属性的传递的。
session主要的操作方法
Method Summary | |
---|---|
Object | getAttribute(String name) Returns the object bound with the specified name in this session, or null if no object is bound under the name.返回根据名称绑定在httpSession中的Object对象 |
Enumeration | getAttributeNames() Returns an Enumeration of String objects containing the names of all the objects bound to this session.返回httpSession中所有绑定对象的名称集合 |
long | getCreationTime() Returns the time when this session was created, measured in milliseconds since midnight January 1, 1970 GMT. 返回Httpsession的创建时间,从1971年1月1日算起的毫秒数 |
String | getId() Returns a string containing the unique identifier assigned to this session. 返回与当前httpSession对象关联的会话标识 |
long | getLastAccessedTime() Returns the last time the client sent a request associated with this session, as the number of milliseconds since midnight January 1, 1970 GMT, and marked by the time the container received the request. 返回客户端最后一次发送与session相关的请求时间 |
int | getMaxInactiveInterval() Returns the maximum time interval, in seconds, that the servlet container will keep this session open between client accesses. 返回会话的最大持续时间 |
ServletContext | getServletContext() Returns the ServletContext to which this session belongs. 返回该session所属的web应用对象,即代表当前web应用的ServletContext对象 |
HttpSessionContext | getSessionContext() Deprecated. As of Version 2.1, this method is deprecated and has no replacement. It will be removed in a future version of the Java Servlet API. (过时了) |
Object | getValue(String name) Deprecated. As of Version 2.2, this method is replaced by getAttribute(java.lang.String) .(过时了) |
String[] | getValueNames() Deprecated. As of Version 2.2, this method is replaced by getAttributeNames() |
void | invalidate() Invalidates this session then unbinds any objects bound to it. 强制使session对象失效 |
boolean | isNew() Returns true if the client does not yet know about the session or if the client chooses not to join the session.判断当前的session对象是不是新创建的 |
void | putValue(String name,Object value) Deprecated. As of Version 2.2, this method is replaced by setAttribute(java.lang.String, java.lang.Object) |
void | removeAttribute(String name) Removes the object bound with the specified name from this session. 用于从当前的httpSession对象删除指定名称的属性 |
void | removeValue(String name) Deprecated. As of Version 2.2, this method is replaced by removeAttribute(java.lang.String) |
void | setAttribute(String name,Object value) Binds an object to this session, using the name specified. 指定名称绑定对象到httpSession中 |
void | setMaxInactiveInterval(int interval) Specifies the time, in seconds, between client requests before the servlet container will invalidate this session. 设置Session的最大生存期 |
Session是与每个请求消息紧密相关的,因此HttpServletRequest定义了用于获取Session对象的getSessoin方法,有两种重载方式:
public HttpSession getSession(boolean create);//true ,则在相关的httpsession对象不存在的时候返回新的Session对象,否则不创建,返回null
public HttpSession getSession();//相当于第一个方法的create为true情况
session超时管理
当客户端第一次访问某个能开启会话功能的资源时,web服务器就会创建一个与该客户端对应的HttpSession对象。在HTTP中,web服务器是无法判断当前客户端浏览器是否还会继续访问,因此也无法检测客户端浏览器是否已经关闭,所以客户端已经离开或者关闭了浏览器,web服务器依然保存着与之对应的HttpSession对象,随着时间的推移,这些不再使用的HttpSession对象将会在web服务器中越积越多,从 而耗尽服务器的内存。
为解决上述问题,web服务器采用了Session超时限制的办法来判断客户端是否还继续访问。在一定时间内,如果某个客户端一直没有请求访问,那么web服务器就会认为客户端请求已经结束,并且销毁服务器内存中的session对象所占用的空间。如果浏览器在此访问,web服务器就会重新创建一个httpSession对象,并为其分配一个新的ID属性。在会话过程中,会话有效时间可以在web.xml文件中配置
<session-config>
<session-timeout>30</session-timeout>
</session-config>
如果将时间设置为0,则表示永远不超时,那么就需要用户通过invalidate()使会话失效或直接删除对应的session对象,从而释放内存。
Session案例:实现用户登陆
IndexServlet
package session;
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;
public class IndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//判断用户是否已经登陆过了,没有则跳转到登陆页面
//从session中获取用户信息
User user = (User) request.getSession().getAttribute("user");
if(user == null){//没有登陆过
//重定向到登陆页面
response.sendRedirect(request.getContextPath()+"/index.jsp");
}else{ //登陆过了
//获取当前的SessionID
String sessionId = request.getSession().getId();
//创建一个Cookie
Cookie cookie = new Cookie("JSESSINOID", sessionId);
cookie.setPath("/");
cookie.setMaxAge(60*30);
response.addCookie(cookie);
response.sendRedirect(request.getContextPath()+"/index.jsp");
}
}
}
LoginServelt
package session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
//这里默认 用户名是 吴渣渣 密码 123
if("吴渣渣".equals(username) && "123".equals(password)){ //登陆成功
User user = new User();
user.setUsername(username);
user.setPassord(password);
request.getSession().setAttribute("user", user);
response.sendRedirect(request.getContextPath()+"/IndexServlet");
}else{ //登陆失败
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
}
LogoutServlet
package session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//将session中的user对象移除
request.getSession().removeAttribute("user");
response.sendRedirect(request.getContextPath()+"/IndexServlet");
}
}
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>首页</h1>
<c:if test="${user.username != null}">
欢迎你,${user.username} <a href="<%=request.getContextPath() %>/LogoutServlet">退出登陆</a>
</c:if>
<c:if test="${user.username == null}">
未登录,<a href="<%=request.getContextPath() %>/LoginServlet">点击登陆</a>
</c:if>
</body>
</html>
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/Blog_demo01/LoginServlet" method="post" >
<span style="color: red">${error }</span><br/>
用户名:<input type="text" name="username" /><br/>
密码: <input type="text" name="password" /><br/>
<input type="submit" value="登陆" />
</form>
</body>
</html>