Java用户关闭页面,清除用户Session【服务端】

该博客介绍了如何通过JavaScript发送心跳包和Java后端定时任务来检测用户页面活跃状态。当用户关闭页面超过指定时间(如120秒),服务端会清除对应的Session。主要涉及Ajax、Session管理、定时任务和Session监听器的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述:当用户关闭页面之后 达到指定得秒数,移除用户Session
思路:用户进入页面后一个ajax每间隔多少秒请求服务端发送心跳包保存当前得时间戳,一旦用户关闭了页面,这个时间戳就不再改变,而服务端得定时器每间隔多久执行检查Session一旦发现这个session得时间戳超过了指定时间秒没有更新,则表示用户已经关闭了页面,则清除用户Session

页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
测试页面
<script>
    setInterval(userActive, 20000); //如果用户打开了这个页面,每隔20秒页面发送一次心跳包存入当前时间戳,
    function userActive(){
        console.log("发送心跳包!");
        var xmlReq;
        if (window.XMLHttpRequest) {//如果windows支持XML请求对象
            xmlReq = new XMLHttpRequest();
        } else {
            xmlReq = new ActiveObject('Microsoft.XMLHTTP');
        }
        xmlReq.onreadystatechange = function () {
            if (xmlReq.readyState == 4 && xmlReq.status == 200) {
               console.log(xmlReq.responseText);
            }
        }
        xmlReq.open("GET", "checkUserActive", true);
        xmlReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");//设置请求头信息
        xmlReq.send("d="+new Date());
    }
</script>
</body>
</html>

Controller

/**
 * 接收请求得控制类
 */
@Controller
@RequestMapping("/test")
public class UserValidityDetection {


    //当用户进入某个页面时 存入用户得某些Session 值
    @RequestMapping("/")
    public String pageSkip(HttpServletRequest request){
        request.getSession().setAttribute("UserKey","this is test key");
        //当用户进入页面时,需要保存一次当前活跃时间,避免用户进入后马上退出页面,无法监听用户是否在页面得活跃状态
        checkUser(request);
        //跳转页面时存入测试 session
        return "test";
    }

    /**
     * 查看用户session是否存在
     * @param request
     * @return
     */
    @RequestMapping("/getUserKey")
    @ResponseBody
    public String getUserKey(HttpServletRequest request){
        String UserKey = (String) request.getSession().getAttribute("UserKey");
        //跳转页面时存入测试 session
        return "{\"UserKey\":"+UserKey+"}";
    }

    /**
     * 页面js每间隔多少秒请求一次,存入当前时间戳,标识用户打开浏览器中打开了当前页面
     * @param request
     */
    @RequestMapping("/checkUserActive")
    @ResponseBody
    public String checkUser( HttpServletRequest request){
        //存入当前Session用户得活跃时间
        request.getSession().setAttribute("userActiveTime",System.currentTimeMillis());
        return "{\"code\":200,\"message\":\"The page remains active and successful!\"}";
    }


}

服务端定时检查器

/**
 * @author YuLF
 * @version 1.0
 * @date 2020/10/15 17:46
 * 定时检查Session状态类
 */
@Component
@EnableScheduling
public class UserValidityDetectionChecker {
    /**
     * 用户离开页面多少秒 销毁用户Session,
     * 因为定时检查是定时执行,存在一定得时间差,不过定时任务得执行间隔只要不是太长,那这个时间差就不会太大
     * 比如说:当用户离开页面后,并不是只要达到了120秒就去移除Session,而是需要等待这个定时器再次执行
     * 当用户离开页面120秒后销毁用户Session得某个Key
     */
    private static final Integer USER_LEAVE_TIME = 120;
    /**
     * 定时检查任务执行得间隔时间 每1分钟执行一次定时任务检查
     * 1.拿到所有用户Session进行遍历
     * 2.判断每一个用户得session,userActiveTime(用户活跃时间戳),关闭当前页面是否超过了指定得秒数
     * 3.关闭页面超过多少秒则移除用户session某个值
     */
    @Scheduled(cron = "0 1/1 * * * ?")
    public void checkUserPage(){
        String needRemoveSession = "UserKey";//需要移除得Session
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + ":执行定时任务检查所有Session状态!");
        Map<String,Object> sessionMap = SessionManager.getSessionMap();
        Iterator<Map.Entry<String, Object>> iterator = sessionMap.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<String, Object> next = iterator.next();
            HttpSession session = SessionManager.getSession(next.getKey());
            //拿到用户在页面得最后一次活跃时间戳
            String userActiveTime = session.getAttribute("userActiveTime")+"";
            if(session.getAttribute(needRemoveSession) != null){
                //用户关闭页面后大于指定得秒数,则移除session UserKey这个值
                if(getDateDifference(userActiveTime) > USER_LEAVE_TIME){
                    //移除session中得某个session值  也可以直接移除用户Session
                    session.removeAttribute(needRemoveSession);
                    System.out.println(session.getId()+"离开页面:"+USER_LEAVE_TIME + "s,移除"+session.getId()+"得UserKey值");
                }
            }
        }
    }
    /**
     * 通过传入得毫秒时间戳,获取距离当前系统时间得秒数,来判断是否超过指定得秒数
     * @param userActiveDateMs
     * @return
     */
    public static long getDateDifference(String userActiveDateMs){
        return (System.currentTimeMillis() - (Long.parseLong(userActiveDateMs)))/1000;
    }
}

Session管理器

/**
 * @author YuLF
 * @version 1.0
 * @date 2020/10/15 17:52
 * Session管理器,保存用户Session
 */
public class SessionManager {

    private static Map<String,Object> map = new HashMap();

    public static Map<String,Object> getSessionMap() {
        return map;
    }

    public static synchronized void AddSession(HttpSession session) {
        if (session != null) {
            map.put(session.getId(), session);
        }
    }

    public static synchronized void DelSession(HttpSession session) {
        if (session != null) {
            map.remove(session.getId());
        }
    }

    public static synchronized HttpSession getSession(String session_id) {
        if (session_id == null)
            return null;
        return (HttpSession) map.get(session_id);
    }
}

Session监听器

/**
 * @author YuLF
 * @version 1.0
 * @date 2020/10/15 17:51
 * Session监听器
 */
public class SessionListener implements HttpSessionListener {
    /**
     * 当有新用户创建时,把他得Session添加到Session管理器
     * @param httpSessionEvent  /
     */
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        SessionManager.AddSession(httpSessionEvent.getSession());
    }

    /**
     * 当有Session销毁时,从Session管理器移除
     * @param httpSessionEvent  /
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession session = httpSessionEvent.getSession();
        SessionManager.DelSession(session);
    }
}

Web.xml

<!--会话管理-->
    <listener>
        <listener-class>com.fly.web.sessionlistener.SessionListener</listener-class>
    </listener>
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值