Springboot项目监听器失效问题解决

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

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

有了思路后,刚开始上网搜的是怎么在spring boot中添加监听:网上大部分的思路都一样:使用@ServletComponentScan和一个实现了HttpSessionListener的方法就可以了。但是自己按照这个配置了后,一直不起作用。启动时候能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机制? 想到这个疑问,又上网搜索,最后通过这个发现是可以的

附上自己的配置:

自定义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自定义的监听里面了。。。。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Boot的listener(监听器)简单使用实例详解

    监听器(Listener)的注册方法和 Servlet 一样,有两种方式:代码注册或者注解注册 1.代码注册方式 通过代码方式注入过滤器 @Bean public ServletListenerRegistrationBean servletListenerRegistrationBean(){ ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean

  • spring boot设置过滤器、监听器及拦截器的方法

    前言 其实这篇文章算不上是springboot的东西,我们在spring普通项目中也是可以直接使用的 设置过滤器: 以前在普通项目中我们要在web.xml中进行filter的配置,但是只从servlet 3.0后,我们就可以在直接在项目中进行filter的设置,因为她提供了一个注解@WebFilter(在javax.servlet.annotation包下),使用这个注解我们就可以进行filter的设置了,同时也解决了我们使用springboot项目没有web.xml的尴尬,使用方法如下所示 @

  • SpringBoot定义过滤器、监听器、拦截器的方法

    一.自定义过滤器 创建一个过滤器,实现javax.servlet.Filter接口,并重写其中的init.doFilter.destory方法. package com.example.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.Se

  • Spring boot通过HttpSessionListener监听器统计在线人数的实现代码

    首先说下,这个统计在线人数有个缺陷,一个人在线可以同时拥有多个session,导致统计有一定的不准确行. 接下来,开始代码的编写, 第一步:实现HttpSessionListener中的方法,加上注解@WebListener @WebListener public class SessionListener implements HttpSessionListener{ public void sessionCreated(HttpSessionEvent arg0) { // TODO Aut

  • springboot 用监听器统计在线人数案例分析

    本文在springboot 的项目,用HttpSessionListener 监听器(监听器的其中一种) 统计在线人数,实质是统计session 的数量. 思路很简单,但是有个细节没处理好,让我调试了大半天,才把bug搞好. 先写个HttpSessionListener 监听器.count  是session的数量(人数),session 创建的时候,会触发监听器的sessionCreated 方法,session销毁的时候,会触发监听器的sessionDestroyed 方法. 在监听器中计算

  • SpringBoot实现拦截器、过滤器、监听器过程解析

    这篇文章主要介绍了SpringBoot实现拦截器.过滤器.监听器过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 过滤器 过滤器简介 过滤器的英文名称为 Filter, 是 Servlet 技术中最实用的技术.如同它的名字一样,过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求,通常用作 Session 校验,判断用户权限,如果不符合设定条件,则会被拦截到特殊的地址或者基于特殊的响应. 过滤器的使用 首

  • Springboot项目监听器失效问题解决

    1.使用springboot项目,现在有个需求是在添加或者修改某个菜单后,菜单会影响角色,角色影响用户.所有受影响的用户在要退出重新登录. 自己实现的思路是这样的:写一个监听器,在收到某个特定的请求后,监听当前所有的用户,如果是受影响的用户,就销毁session,让重新登录. 有了思路后,刚开始上网搜的是怎么在spring boot中添加监听:网上大部分的思路都一样:使用@ServletComponentScan和一个实现了HttpSessionListener的方法就可以了.但是自己按照这个配

  • SpringBoot项目多数据源及mybatis 驼峰失效的问题解决方法

    目录 1 配置多数据源时,application.yml 的有关mybatis的配置是失效的,因为他不知道配置哪一个数据源 2 application.yml 配置文件 3 解决方法一 4 完整代码 4解决方法二 1 配置多数据源时,application.yml 的有关mybatis的配置是失效的,因为他不知道配置哪一个数据源 2 application.yml 配置文件 server: # 服务器的HTTP端口 port: 8097 spring: # 配置数据源 datasource: m

  • SpringBoot项目没有把依赖的jar包一起打包的问题解决

    这篇文章主要介绍了SpringBoot项目没有把依赖的jar包一起打包的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一般未一起打包是因为pom不是继承自spring-boot-starter-parent导致的需要在pom.xml文件写入以下配置 <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId>

  • Springboot Retry组件@Recover失效问题解决方法

    目录 背景 问题复现 问题解决 背景 在使用springboot的retry模块时,你是否出现过@Recover注解失效的问题呢?下面我会对该问题进行复现,并且简要的说下解决方法. 问题复现 首先我们引入maven <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> &

  • 解决weblogic部署springboot项目步骤及可能会出现的问题

    项目为springboot的需要适配weblogic 第一步 修改启动类, 很多搜到的都是这样 修改启动类StartEPassApplication 第二步 完全排除掉tomcat 详情请看下面的地址 完全排除springboot的tomcat还需加上weblogic.xml <?xml version="1.0" encoding="UTF-8"?> <wls:weblogic-web-app xmlns:wls="http://xml

  • SpringBoot项目中分页插件PageHelper无效的问题及解决方法

    在Springboot项目中使用分页插件的时候 发现PageHelper插件失效了 我导入的是: 后来才发 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency> 现 PageHelper若要在Springbo

  • IDEA解决springboot热部署失效问题(推荐)

    一.什么是热部署? 热部署,就是在应用正在运行的时候升级软件,却不需要重新启动应用. 二.什么是SpringBoot热部署? SpringBoot热部署就是在项目正在运行的时候修改代码, 却不需要重新启动项目. 有了SpringBoot热部署后大大提高了开发效率,因为频繁的重启项目,势必会浪费很多时间, 有了热部署后,妈妈再也不用担心我修改代码重启项目了~~~ 下面看下IDEA解决springboot热部署失效问题,IDEA实现springboot热部署详情如下: 在pom.xml文件中添加依赖

  • SpringBoot项目如何把接口参数中的空白值替换为null值(推荐)

    问题发生 我们公司代码生成的时候,查询列表统一都是使用了setEntity() ,查询写法如下: public List<BasReservoirArea> selectList(BasReservoirArea basReservoirArea) { QueryWrapper<BasReservoirArea> where = new QueryWrapper<>(); where.setEntity(basReservoirArea); return baseMap

  • SpringBoot项目 文件上传临时目标被删除异常的处理方案

    1.业务背景 我们使用了SpringCloud 进行项目开发,其中一个主要服务(涉及到图片上传)的SpringBoot微服务在测试环境之中.因为此项目已经上线,很长一段时未针对此项目间做相关布更改和打包发. 由于最近此项目业务甲方需要新增部分功能.但是测试在上传课程时候,需要上传课程封面,发现上传课程封面的图片上传接口报错500啦. 本人在后端日志目录之中也无法查找到报错信息.仅仅只有前后端分离的前端调用接口的时候返回一个如下错误提示 Could not parse multipart serv

随机推荐