springboot项目监听器不起作用

1.使用springboot项目,现在有个需求是在添加或者修改某个菜单后,菜单会影响角色,角色影响用户。所有受影响的用户在要退出重新登录。

自己实现的思路是这样的:写一个监听器,在收到某个特定的请求后,监听当前所有的用户,如果是受影响的用户,就销毁session,让重新登录。

有了思路后,刚开始上网搜的是怎么在spring boot中添加监听:网上大部分的思路都一样:使用@ServletComponentScan和一个实现了HttpSessionListener的方法就可以了。(参考:https://www.cnblogs.com/liuyong1993/p/10012808.html)。但是自己按照这个配置了后,一直不起作用。启动时候能debug到这个自定义的监听里面,但是登录后缺不能实现

sessionCreated()
package com.listener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * session监听器
 * @author Administrator
 */
@WebListener
public class SessionListener implements HttpSessionListener{

    private int onlineCount = 0;//记录session的数量

    /**
     * session创建后执行
     */
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        onlineCount++;
        System.out.println("【HttpSessionListener监听器】 sessionCreated, onlineCount:" + onlineCount);
        se.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
    }

    /**
     * session失效后执行
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        if (onlineCount > 0) {
            onlineCount--;
        }
        System.out.println("【HttpSessionListener监听器】 sessionDestroyed, onlineCount:" + onlineCount);
        se.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
    }

}
复制代码

  

还问了群里的大神帮忙看了下,也没问题。刚开始怀疑是 不是登录时候监听的HttpSession,因为实现的是HttpSessionListener,是需要有个发起的动作的.但是自己登录时候也有httpSession。然后在自己的测试类里面进行测试,发现sesionId是存在的:

package com.sq.transportmanage.gateway.api.auth;

import com.alibaba.fastjson.JSONObject;
import com.sq.transportmanage.gateway.api.web.interceptor.AjaxResponse;
import com.sq.transportmanage.gateway.api.web.interceptor.LoginoutListener;
import com.sq.transportmanage.gateway.service.common.shiro.session.RedisSessionDAO;
import com.sq.transportmanage.gateway.service.common.web.RestErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * @Author fanht
 * @Description
 * @Date 2020/3/5 下午6:46
 * @Version 1.0
 */
@RestController
@RequestMapping("/loginoutController")
public class LoginoutController extends RedisSessionDAO{

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @RequestMapping("/userLoginOut")
    @ResponseBody
    public AjaxResponse userLoginOut(String userIds, HttpSession httpSession,
                                     HttpServletRequest request){

        logger.info("httpSessionId" + httpSession.getId() + ",是否是session会话:" +
        request.getSession(false));
        HttpSession session = request.getSession();
        String loginName = (String) session.getAttribute("loginName");
        logger.info("loginName:" + loginName);
        logger.info("调用退出接口并清除shiro缓存" + userIds);
        logger.info("获取监听存取的信息" + JSONObject.toJSONString(LoginoutListener.sessionCount));
        try {
            String userId[] = StringUtils.tokenizeToStringArray(userIds,",");
            for(int i = 0;i<userId.length;i++){
                clearRelativeSession(null,null,Integer.valueOf(userId[i]));
            }
            return AjaxResponse.success(null);
        } catch (NumberFormatException e) {
            e.printStackTrace();
            logger.error("shiro退出异常" + e);
            return AjaxResponse.fail(RestErrorCode.UNKNOWN_ERROR);
        }
    }

    @Override
    public void clearRelativeSession(Integer permissionId, Integer roleId, Integer userId) {
        super.clearRelativeSession(null, null, userId);
    }
}

  是能够打印sessionId的,也就是说session是存在不为空的。

然后想到我们项目里面用的是shiro,会不会是shiro重写了session机制? 想到这个疑问,又上网搜索,最后通过这个发现是可以的(参考:https://blog.csdn.net/qq_34021712/article/details/80418112

附上自己的配置:

自定义shiroSessionListener:

package com.sq.transportmanage.gateway.api.web.interceptor;

import com.google.common.collect.Maps;
import com.sq.transportmanage.gateway.service.common.shiro.session.RedisSessionDAO;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author fanht
 * @Description 监听当前有哪些用户,当收到特定通知后通知退出登录
 * @Date 2020/3/5 下午1:48
 * @Version 1.0
 */
//@WebListener
public class LoginoutListener   extends RedisSessionDAO implements SessionListener {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    public  static final Map<Long,String> mapUser = Maps.newHashMap();
    public final static AtomicInteger sessionCount = new AtomicInteger(0);

    @Override
    public void onStart(Session session) {
        //会话创建,在线人数加一
        logger.info("======" + sessionCount);
        sessionCount.incrementAndGet();
    }

    @Override
    public void onStop(Session session) {
        //会话退出,在线人数减一
        sessionCount.decrementAndGet();
    }

    @Override
    public void onExpiration(Session session) {
        //会话过期,在线人数减一
        sessionCount.decrementAndGet();

    }

    /**
     * 获取在线人数使用
     * @return
     */
    public AtomicInteger getSessionCount() {
        return sessionCount;
    }

    /*@Override
    public void sessionCreated(HttpSessionEvent se) {
        onlineCount++;
        logger.info("创建start====== ===" + se.getSession().getId());
        mapUser.put(se.getSession().getCreationTime(),se.getSession().getId());
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        logger.info("销毁session=============");
    }*/
}

  

ShiroConfiguration里面添加配置的监听:
 @Bean("sessionManager")
    public DefaultWebSessionManager sessionManager(RedisSessionDAO sessionDAO, SimpleCookie sessionIdCookie) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //session存活时间60分钟
        sessionManager.setGlobalSessionTimeout(3600000);
        sessionManager.setDeleteInvalidSessions(true);
        //自定义监听 fht 不能使用@WebListern的 HttpSessionListerner 因为shiro重写了session 2020-03-05
        Collection<SessionListener> sessionListeners = new ArrayList<>();
        sessionListeners.add(sessionListener());
        sessionManager.setSessionListeners(sessionListeners);
        //sessionManager.setSessionValidationSchedulerEnabled(true);
        //sessionManager.setSessionValidationScheduler(sessionValidationScheduler);
        sessionManager.setSessionDAO(sessionDAO);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(sessionIdCookie);
        return sessionManager;
    }

  

/**
     * 自定义shiro监听
     * @return
     */
    @Bean("sessionListener")
    public LoginoutListener sessionListener(){
        LoginoutListener loginoutListener = new LoginoutListener();

        return loginoutListener;
    }

  

然后重新启动,测试 ,发现可以进入到shiro自定义的监听里面了。。。。

原文地址:https://www.cnblogs.com/thinkingandworkinghard/p/12423913.html

时间: 2024-11-24 22:34:28

springboot项目监听器不起作用的相关文章

SpringBoot源码分析之---SpringBoot项目启动类SpringApplication浅析

源码版本说明 本文源码采用版本为SpringBoot 2.1.0BUILD,对应的SpringFramework 5.1.0.RC1 注意:本文只是从整体上梳理流程,不做具体深入分析 SpringBoot入口类 @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args

springboot项目中,@transactional 无效

问题: springboot项目,依然是使用jpa.Hibernate来操作mysql,涉及到数据库的操作,就少不了事务.写了一个接口,用来测试@Transaction注解的作用,发现没有效果 分析: 在项目启动时候,看到Hibernate: create table hibernate_sequence (next_val bigint) engine=MyISAM,说明是MyISAM引擎,由此我们也就很容易想到MyISAM与InnoDB之间的区别 解决: 发现Hibernate默认创建的表是

完成一个springboot项目的完整总结-------二

我们接着上篇继续写,继续进行springboot项目 一. swagger2 接口描述,测试每个接口是否有效 1. 添加依赖 pom.xml 在编辑pom.xml之前,要先关闭spring-boot项目 eclipse 编辑pom.xml.当编辑完毕保存pom.xml后eclipse会帮我们自动下载依赖.eclipse这个自动化操作可能会出现一些问题. mvn install <dependency> <groupId>io.springfox</groupId> &l

idea内springboot项目设置热部署

一.需求分析: 编写idea中编写项目时,经常性改某几行代码就需要重新启动项目,比较浪费时间,借助idea的热部署可以实现代码的热部署 二.实现经过 这边可以借助spring-boot-devtools模块进行配置,devtools会检测代码,并进行重新发布.devtools的实现原理是通过使用两个 ClassLoader,一个用来加载一些第三方的代码(如引入的一些jar包).另一个ClassCLoud会加载一些会更改的代码,可以称 为restart ClassLoader.在有代码进行更改的时

「SpringBoot」如何优雅地管理SpringBoot项目

本文主要讲述一下如何优雅地管理SpringBoot项目. 背景 课堂上,当小明形如流水地回答完沐芳老师提出来的问题时,却被至今没有对象的胖虎无情嘲讽了? 沐芳老师:小明,你平时是如何启动.停止你的SpringBoot项目的? 小明(自信满满):启动时使用java -jar xxxx.jar命令启动,停止服务时,使用ps -ef找到服务的pid,然后再kill掉停止. 胖虎:就这? 这让小明很有挫败感,原计划按时放学回去陪隔壁小花打王者荣耀的小明,毅然决然留在教室潜心研究一番到底什么是Spring

关于springboot项目中自动注入,但是用的时候值为空的BUG

最近想做一些web项目来填充下业余时间,首先想到了使用springboot框架,毕竟方便 快捷 首先:去这里 http://start.spring.io/ 直接构建了一个springboot初始化的项目框架 然后:在页面上选择相应的依赖包,然后点击构建按钮,然后下载并且导入IDE中,目前喜欢使用IDEA 于是一个简答的springboot项目就搭建好了 废话说完,然后想体验下spring中redis的使用: 那就直接新建了一个类,然后 @Autowired 自动注入 RedisTemplate

java项目中META-INF的作用中MANIFEST.MF的作用(转载)

发布Java应用程序时你会感到困难?好在Java提供了一系列打包和发布工具,可以显著的简化发布过程 该文章提供了打包Java code的几种方法,我们将会探讨Java manifest 文件,给出用于管理JAR文件所依赖文件.估计跨平台发布所需的CLasspath的合适方法.我也会解释如何使用manifest包版本特性来确认包的兼容性... 什么是JAR文件? 在开发过程中,我们可以直接使用Java class文件来运行程序,但这并不是一个好方式,好在Java 提供了 JAR(Java Arch

springboot项目怎么部署到外部tomcat

spring-boot项目中,默认提供内嵌的tomcat,所以打包直接生成jar包,用Java -jar命令就可以启动. 但是也有一定的需求,会使用外部tomcat来部署项目.下面来看: 1.新建项目boot-tomcat-test 2.pom依赖:(添加spring-boot-starter-tomcat依赖,打包方式为war) <?xml version="1.0" encoding="UTF-8"?> <project xmlns="

web项目连接池的作用

连接池的作用:连接池是将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对数据库进行访问.这样省略了创建连接和销毁连接的过程.这样性能上得到了提高. 基本原理是这样的: (1)建立数据库连接池对象(服务器启动).(2)按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数).(3)对于一个数据库访问请求,直接从连接池中得到一个连接.如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接.(4)存取数据库.(5)关闭数据库,释