监听器的功能 防止重复登录:当一个用户登录系统之后,另外一个用户使用相同账户登陆时,对前一个用户进行踢除操作,保证在同一时间只有一个账户在登录系统。
案例说明:
- 通过过滤器实现登录控制,未登录用户不能访问系统首页
- 用户登录,将登录名存储到session里
- 登录监听器session属性中登录值属性变化
- 若登录用户用户名已登录系统,清除前次登录信息
步骤:
- 实现登录功能
- 登录权限过滤验证
- 用户信息存储实现
- 监听功能实现
创建index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String flag=request.getParameter("flag");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<script type="text/javascript">
var flag='<%=flag %>';
if("1"==flag){
alert("你尚未登陆,或者账号在异地登陆,请重新登陆!");
}
</script>
<body>
<form action="login.jsp" method="post" class="smart-green">
<h1>系统登录</h1>
<label>
<span>用户名:</span>
<input id="username" type="text" name="username"/>
</label>
<label>
<span>密码:</span>
<input id="password" type="password" name="password"/>
</label>
<span> </span>
<label>
<input type="submit" class="button" value="登录"/>
</label>
</form>
</body>
</html>
一、实现登录功能
- 获取用户名和密码
- 将登录用户名存储至session对象
- 页面跳转到(登录后)main.jsp
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//获取登录用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
//将登录用户名存储至session对象
session.setAttribute("LoginUser", username);
//页面跳转到main.jsp
response.sendRedirect(request.getContextPath()+"/main.jsp");
%>
对于main.jsp即登录后的页面,大家可以根据自己的喜好设置,需在前面加上
<%
String user=(String)session.getAttribute("LoginUser");
%>
二、登录权限过滤验证
- Filter接口
- 从session对象中获取登录用户名
- 判断是否登录,即用户名是否已经存在:不存在则重定向至登录页面,已登录则转入相应请求
SessionFilter.java
/**
* 用户登录权限过滤器
*/
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SessionFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//将request和response转为专门的http请求对象
HttpServletRequest hrequest=(HttpServletRequest)request;
HttpServletResponse hresponse=(HttpServletResponse)response;
//从session对象中获取登录用户名
String LoginUser = (String)hrequest.getSession().getAttribute("LoginUser");
//判断是否登录,即用户名是否存在
if(LoginUser==null) {
//不存在则重定向至登录页面
hresponse.sendRedirect(hrequest.getContextPath()+"/index.jsp?flag=1");
return;
}else {
chain.doFilter(request, response);//已登录,转到相应的请求
return;
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
三、用户信息存储实现
- 通过登录名获取对应登录用户的sessionId
- 通过sessionId获取对应的session对象
- 存储登录名与相应的登录sessionId至缓存对象
- 存储 sessionId与对应的session对象至缓存对象
LoginCache.java
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
/**
* 用户信息存储实现
* @author 16286
*
*/
public class LoginCache {
private static LoginCache instance = new LoginCache();
//单例模型
private LoginCache() {
}
public static LoginCache getInstance() {
return instance;
}
private Map<String,String>LoginUserSession=new HashMap<String,String>();
//key值:登录用户登录名,value值:登录用户sessionId
private Map<String,HttpSession>LoginSession=new HashMap<String,HttpSession>();
//key值:登录用户sessionId,value值:登录用户session对象
/**
* 通过登录名获取对应登录用户的sessionId
*/
public String getSessionIdByUsername(String username) {
return LoginUserSession.get(username);
}
/**
* 通过sessionId获取对应的session对象
*/
public HttpSession getSessionBySessionId(String sessionId) {
return LoginSession.get(sessionId);
}
/**
* 存储登录名与相应的登录sessionId至缓存对象
*/
public void setSessionIdByUsername(String username,String sessionId) {
LoginUserSession.put(username, sessionId);
}
/**
* 存储sessionId与对应的session对象至缓存对象
*/
public void setSessionBySessionId(String sessionId,HttpSession session) {
LoginSession.put(sessionId, session);
}
}
四、监听功能实现
LoginSessionListener.java
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import com.lzy.session.LoginCache;
public class LoginSessionListener implements HttpSessionAttributeListener {
private static final String LOGIN_USER = "LoginUser";
@Override
public void attributeAdded(HttpSessionBindingEvent hsbe) {
// 监听到session属性值发生添加操作,获取对应操作的属性名
String attname = hsbe.getName();
if (LOGIN_USER.equals(attname)) {
// 获取添加的属性值,即用户登录名
String attrVal = (String) hsbe.getValue();
// 获取该次操作的session对象
HttpSession session = hsbe.getSession();
// 该次操作的session对象ID
String sessionId = session.getId();
// 从缓存对象里面,获得该用户登录名对应的sessionID值
String sessionId2 = LoginCache.getInstance().getSessionIdByUsername(attrVal);
if (null == sessionId2) {// 未获得结果,不需要清理前次登录用户会话信息
} else {
HttpSession session2 = LoginCache.getInstance().getSessionBySessionId(sessionId2);// 获取前次该用户登录对应的session对象
session2.invalidate();// 清理前次登录用户会话存储信息,使得前次登录失效
}
// 完成该次登录用户登录名、sessionID,session对象的缓存对象存储
LoginCache.getInstance().setSessionIdByUsername(attrVal, sessionId);
LoginCache.getInstance().setSessionBySessionId(sessionId, session);
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void attributeReplaced(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
}
}
配置xml
<!--注册监听器-->
<listener>
<listener-class>com.lzy.session.LoginSessionListener</listener-class>
</listener>
<!--注册过滤器-->
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.lzy.session.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/main.jsp</url-pattern>
</filter-mapping>
最后运行结果(用两个浏览器进行测试)
运行程序
在360浏览器里打开本地服务器
跳转到登录后的界面main.jsp
接着在火狐浏览器打开
输入相同的账号密码,登录成功后,回到360浏览器,点击刷新,就会出现