一 关于session
1 session机制
在web程序中使用session来记录客户端状态,是服务器端使用的一种记录客户端状态的机制。
session技术则是服务端的解决方案,通过服务器保持状态的。
session通常被翻译成会话,通常大家把客户端(浏览器)与服务器之间的一系列交互动作称为一个session。基于此,会提到session持续的时间以及session过程中进行了什么操作等。
另外session也指服务端为客户端开辟的存储空间,在其中保存的信息就是用于保存状态。基于此,会提到向session中存放了什么内容以及会根据键值从session中匹配的内容等。
通常来讲,要使用session必须要先创建session,具体来说是在服务器端运行的过程中创建的,在Java web中通过调用HttpServletRequest的getSession()方法(使用true作为参数)创建的。创建session的同时,服务器会为该session生成一个唯一的session id,这个session id 在随后的请求中会被用来重新获取已经创建的session。
当然,在创建session后,就能往session中添加内容了,但这些内容只会保存在服务器中,发送到客户端的只有session id。当客户端再次发送请求的时候,会将这个session id带上(通过session id 辨别是哪个客户端),服务器接受到请求之后就会根据session id 找到对应的session,从而再次使用。这样的交互过程使得用户的状态能够保持。
2 什么是session
1)session是不同于cookie的一种记录客户状态的机制,保存在服务端(cookie客户端)。
2)客户端浏览器在访问服务端的时候,服务器把客户端信息以某种形式记录在服务器上,这就是session。
3 实现用户登陆
在Java中session对应的类为Javax.servlet.HttpSession类。每个访问者对应一个session对象,所有该客户的状态信息都保存在这个session对象中。session对象是在客户端第一次请求服务器的时候创建的。session是一种key-value的属性对,通过getAttribute(StringKey)和setAttribute(String key,Object value)方法读写客户状态信息。
在servlet(action、controller等)可以通过request.getSession()方法获取该客户的session:
HttpSession session = request.getSession(); // 获取Session对象
session.setAttribute("loginTime", new Date()); // 设置Session中的属性
System.out.println("登录时间为:" +(Date)session.getAttribute("loginTime")); // 获取Session属性
request还可通过getSession(boolean create)来获取session,区别在于如该客户的session不存在,request.getSession()方法会返回null,而getSession(true)会创建session再将session返回。
在servlet中必须使用request来编程式获取HttpSession对象,而Jsp中内置了Session隐藏对象,可以直接使用。当声明了<%@page session="false">,则session隐藏对象不可以使用。
Person.java
package test.session.bean;
import java.io.Serializable;
import java.util.Date;
public class Person implements Serializable{
private String username;
private String password;
private int age;
private Date birthday;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String username, String password, int age) {
super();
this.username = username;
this.password = password;
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Person(String username, String password, int age, Date birthday) {
super();
this.username = username;
this.password = password;
this.age = age;
this.birthday = birthday;
}
}
index.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%!
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式化器
%>
<%
response.setCharacterEncoding("UTF-8"); // 设置request编码
Person[] persons =
{
// 基础数据,保存三个人的信息
new Person("zhangsan","zhangsan", 34, dateFormat.parse
("1982-01-01")),
new Person("lisi","lisi", 23, dateFormat.parse
("1984-02-21")),
new Person("wangmazi", "wangmazi",23, dateFormat.parse
("1994-09-12"))
};
String message = ""; // 要显示的消息
if(request.getMethod().equals("POST"))
{
// 如果是POST登录
for(Person person :persons)
{
// 遍历基础数据,验证账号、密码
// 如果用户名正确且密码正确
if(person.getUsername().equalsIgnoreCase(request.getParameter("username"))&&person.getPassword().equals(request.getParameter("password")))
{
// 登录成功,设置将用户的信息以及登录时间保存到Session
session.setAttribute("person", person); // 保存登录的Person
session.setAttribute("loginTime", new Date()); // 保存登录的时间
response.sendRedirect(request.getContextPath() + "/welcome.jsp");
return;
}
}
message = "用户名密码不匹配,登录失败。"; // 登录失败
}
%>
welcome.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%!
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式化器
%>
<%
Person person =(Person)session.getAttribute("person"); // 获取登录的person
Date loginTime =(Date)session.getAttribute("loginTime"); // 获取登录时间
%>
您的姓名: | <%= person.getUsername()%> |
登录时间: | <%= loginTime%> |
您的年龄: | <%= person.getAge()%> |
您的生日: | <%=dateFormat.format(person.getBirthday()) %> |
ps: 当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。
虽然session的使用比cookie方便,但过多的session存储在服务器的内存中,会对服务器造成压力。
3 session的生命周期
session保存在服务器端,为求响应速度,一般被存放在内存中。每个访问的用户都有一个独立的session,为避免内存溢出,session内容应该精简。
session在用户第一次访问服务器时创建,只有访问jsp、servlet等程序时才会创建session,如果只访问html、image等静态资源并不会创建session。如果尚未生成session,也可以使用request.getSession(true)强制生成session。
session生成后,如若用户继续访问,服务器就会更新session的最后访问时间,并维护该session。用户每访问一次服务端(无论读写),服务端都认为该用户的session活跃(active)了一次。
4 session有效期
因用户访问服务器越来越多造成session越来越多,未防止内存溢出,服务器会把长时间没有活跃的session从内存中删除,这个时间点就是session的超时时间。如超过了超时时间没有访问服务器,那么session自动失效。
session的超时时间为maxInactiveInterval属性,可通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(long interval)修改。
5 session的常用方法
session中包括了很多方法,常用如下:
1)void setAttribute(String attribute,Object value):设置session属性。value参数可以为任何Java Object。一般为Java bean。value信息一般不宜过大。
2)String getAttribute(String attribute):返回session属性
3)Enumeration getAttributeNames(): 返回session中存在的session属性名称
4) void removeAttribute(String attribute):移除session属性
5) String getId():返回session id,该id由服务器自动创建,不会重复
6)long getCreationTime():返回session的创建日期,返回类型为long,常被转换成Date类型。
7)long getLastAccessedTime():返回session的最后活跃时间,返回类型为long
8) int getMaxInactiveInterval():返回session的超时时间,单位为秒。超过该时间没有访问,服务器认为session失效
9)void setMaxInactiveInterval(int second):设置session的超时时间,单位为秒
10)void putValue(String attribute,Object value):不推荐,已经被setAttribute(String attribute, Object Value)替代
11)Object getValue(String attribute):不被推荐的方法。已经被getAttribute(String attr)替代
12)boolean isNew():返回该Session是否是>新创建的
13)void invalidate():使该Session失效
6 session与浏览器
session需要客户端浏览器的支持,毕竟session需要使用cookie作为标志。鉴于http协议无状态,session不能根据http连接判断是否为同一客户,服务器需向浏览器发送一个名为JSESSIONID的Cookie,其值为该session的id。session根据该cookie来识别是否为同一用户。
该cookie为服务器自动生成,它的maxAge属性一般为-1,表示只在当前浏览器中有效,且各浏览器窗口间不共享,关闭浏览器就会失效。
即在同一计算机的两个浏览器窗口访问服务时,会生成两个不同的session,但由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的cookie,因此会共享一个session。
PS:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择“在新窗口中打开”时,子窗口便可以访问父窗口的Session。
如果客户端浏览器将Cookie功能禁用,或者不支持Cookie怎么办?例如,绝大多数的手机浏览器都不支持Cookie。Java Web提供了另一种解决方案:URL地址重写。
7 URL地址重写
URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(Stringurl)实现URL地址重写,例如:
该方法会自动判断客户端是否支持Cookie。如果客户端支持Cookie,会将URL原封不动地输出来。如果客户端不支持Cookie,则会将用户Session的id重写到URL中。重写后的输出可能是这样的:
即在文件名的后面,在URL参数的前面添加了字符串“;jsessionid=XXX”。其中XXX为Session的id。分析一下可以知道,增添的jsessionid字符串既不会影响请求的文件名,也不会影响提交的地址栏参数。用户单击这个链接的时候会把Session的id通过URL提交到服务器上,服务器通过解析URL地址获得Session的id。
二 Java 设置session超时(失效)的时间
tomcat中session的默认超时时间是30分钟,可以通过三种方法设置失效时间。
1 在web容器中设置(如tomcat)
在tomcat-7.0\conf\web.xml中设置:
可以根据需要修改,负数或者0表示不限制session失效时间,一般取值在1-1440(一分钟到一天)。这个session的设置时间是根据服务器来计算,不是根据客户端计算。调试的时候应该修改服务端时间测试,而不是客户端。
2 在项目的web.xml中设置
这里是1440分钟失效
3 通过Java代码设置
session.setMaxInactiveInterval(30*60);//以秒为单位,即在没有活动30分钟后,session将失效
4 优先级
三种方式中:1<2<3
三 怎么动态监控session
写一个监听器,实现HttpSessionListener, HttpSessionAttributeListener两个接口,然后放在web.xml
四 session过期演示
1 演示案例
1.1 配置session过期时间 4分钟
1.2 实体类UserInfo.java
package test.session.bean;
public class UserInfo {
private int id;
private String username;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public UserInfo() {
super();
}
public UserInfo(int id, String username) {
super();
this.id = id;
this.username = username;
}
}
1.3 请求类 UserServlet
package test.session.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import test.session.bean.UserInfo;
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public UserServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setUsername("风间净琉璃");
request.getSession().setAttribute("userInfo", userInfo);
request.getSession().setAttribute("loginMessage", "用户登陆成功");
request.getRequestDispatcher("showUserInfo.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
1.4 session监听器 SessionListener
package test.session.listener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class SessionListener implements HttpSessionListener,HttpSessionAttributeListener{
private long attributeAddTime;
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println("添加属性:"+event.getName());
attributeAddTime = System.currentTimeMillis();
}
@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("移除属性"+event.getName());
long attributeRemoveTime = System.currentTimeMillis();
long attributeSaveTime=(attributeRemoveTime-attributeAddTime)/1000;
System.out.println("数据保存时间"+attributeSaveTime+"秒");
}
@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println("更改属性:"+event.getName());
}
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("session 创建 ");
System.out.println("session id: "+session.getId());
System.out.println("session 创建时间: "+session.getCreationTime());
System.out.println("session 最后活跃时间:"+session.getLastAccessedTime());
System.out.println("session 最大过期时间 :"+session.getMaxInactiveInterval());
System.out.println("session 中的所有属性值"+session.getAttributeNames());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("session 销毁:"+session.getId()+"||"+session.getCreationTime()+"||"+session.getLastAccessedTime()+"||"+session.getMaxInactiveInterval()+" "+session.getAttributeNames());
}
}
1.4 展示用户页面 showUserInfo.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" isELIgnored="false" pageEncoding="UTF-8"%>
1.5 演示