前提:系统做了拦截器,每个用户使用时,必须先登录
配置文件
<filter>
<filter-name>permissionFilter</filter-name>
<filter-class>com.ccf.commons.filter.PermissionFilter</filter-class>
<init-param>
<param-name>ignore_page</param-name>
<param-value>/user/login.do, /user/logout.do</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>permissionFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>permissionFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.ccf.commons.listener.SessionListener</listener-class>
</listener>
step1:登录操作:
1、根据isLogout参数的值来判断登录界面是否需要提醒用户:您的账号在其他IP登录,已被踢下线
2、缓存用户名和对应的sessionID,并在session中添加isLogout属性
/**
* 登录
* @param request
* @param session
* @param sysUser
* @return
* @throws IOException
*/
@RequestMapping("/login")
public ModelAndView login(HttpServletRequest request,HttpServletResponse response, HttpSession session, User sysUser, String isLogout) throws IOException{
ModelAndView modelAndView = new ModelAndView("/login");
if("true".equals(isLogout)){
modelAndView.addObject("user_error", "您的账号在其他IP登录,已被踢下线");
return modelAndView;
}
//异地登陆
Map<String, HttpSession> sessionMap = CacheManager.getSessionMap();
if(false == sessionMap.containsKey(loginId)){
session.setAttribute("isLogout", "false");
sessionMap.put(loginId, session);
CacheManager.setSessionMap(sessionMap);
}else if(session.getId() != sessionMap.get(loginId).getId()){
HttpSession sessionDel = sessionMap.get(loginId);
sessionDel.setAttribute("isLogout", "true");
session.setAttribute("isLogout", "false");
sessionMap.put(loginId, session); //更新loginId
CacheManager.setSessionMap(sessionMap);
}
return new ModelAndView("redirect:/index.jsp");
}
step2:前端
index.js
定时判断session的属性isLogout的值,如果为 'true',说明有其他用户在其他地方登录了,所以调用退出,并带isLogout参数
$(function() {
//异地登录
var logoutInterval = setInterval(function(){
$.ajax({
url : rootPath+"/user/checkSession.do",
type:"post",
success : function(data) {
if(data == "true"){
window.location.href = rootPath + "/user/logout.do?isLogout=true";
}
}
});
},15 *1000);
});
其中,判断方法如下:
/**
* 用户是否已异地登录
* @param userId
* @return
*/
@RequestMapping("/checkSession")
@ResponseBody
public String checkSession(HttpServletRequest request, HttpSession session){
return (String) session.getAttribute("isLogout");
}
step3:退出操作
1、删除整个会话(session)
2、重定向到登录操作
/**
* 退出系统
* @return
*/
@RequestMapping(value = "logout")
public void loginOut(HttpSession session,HttpServletRequest request,HttpServletResponse resp, String isLogout) {
session.invalidate();
String resultUrl=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/user/login.do?isLogout="+isLogout;
try {
resp.sendRedirect(resultUrl);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
step4:过滤器拦截
public class PermissionFilter implements Filter {
private String[] ignorePages;
public void init(FilterConfig config) throws ServletException {
String ignorePage = config.getInitParameter("ignore_page");
if (ignorePage != null)
this.ignorePages = ignorePage.split(",");
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
HttpSession session = request.getSession();
User user = (User)session.getAttribute(Constants.USER_INFO);
String interurl = request.getContextPath() + request.getServletPath();
// 判断用户访问的是否是登录页面
if (isIgnorePage(request)) {
SessionUtil.setUser(user);
chain.doFilter(request, response);
return;
}
// 校验是否验证会话
if (null == user){//判断是否已登录
if (isIgnorePage(request)){
SessionUtil.setUser(user);
chain.doFilter(req, resp);
return;
}
response.sendRedirect(request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/user/login.do");
}else{
if (interurl.equals("/{系统名}/login.jsp")) {
response.sendRedirect(request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/index.jsp");
} else {
SessionUtil.setUser(user);
chain.doFilter(request, response);
}
}
}
private boolean isIgnorePage(HttpServletRequest request) {
if (this.ignorePages == null) {
return false;
}
String servletPath = request.getServletPath();
for (int i = 0; i < this.ignorePages.length; i++) {
if (this.ignorePages[i].endsWith("*")) {
int lastIndex = servletPath.lastIndexOf("/");
String compareUrl = null;
if (lastIndex == 0)
compareUrl = "/*";
else {
compareUrl = servletPath.substring(0, lastIndex) + "/*";
}
if (this.ignorePages[i].endsWith(compareUrl)) {
return true;
}
} else if (this.ignorePages[i].equals(servletPath)) {
return true;
}
}
return false;
}
public void destroy() {
}
}
step5:登录界面
login.jsp
${user_error}:el表达式,它会从page,request,session,application中取值
<html>
<head>
<div style="margin: 20px 0 0 0;padding: 0;text-align: center;">
<span style="font-size: 16px;color: #E70102;">${user_error}</span>
</div>
</body>
</html>
为了避免用户没有调用退出操作(logout),当session结束(session过期、用户直接退出浏览器等),做以下补充
提供一个session的监听器,确保Cache类能正常使用
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
// TODO Auto-generated method stub
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// TODO Auto-generated method stub
HttpSession session = se.getSession();
Map<String, HttpSession> sessionMap = CacheManager.getSessionMap();
Collection<HttpSession> col = sessionMap.values();
while(true == col.contains(session)){
col.remove(session);
}
}