功能描述:

当用户退出(主动)或者关闭浏览器(session超时)的时候,利用本次登录Ip更新上次登录IP。有人可能要问,你在用户登录的时候记录不就行了。可是我有两个字段,一个为本次登录IP,另外一个为上次登录IP。当用户退出的时候,本次登录IP也就成了上次登录IP。

首先解决的问题是:在Listener里面访问Service。

因为是基于注解开发,将Listener扫描和将Service成员变量注解@Autowired是不能解决问题的。运行起来会报空指针。

public class UserLeaveListener implements HttpSessionListener {

    private UserService userService;

    @Override
public void sessionCreated(HttpSessionEvent arg0) {
// 记录访问日志:IP } @Override
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("---SessionListener---");
//调用 session.invalidate(); 后,在这个方法里仍然可以获取到属性值 ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(
arg0.getSession().getServletContext());
userService = applicationContext.getBean(UserService.class);
HttpSession session = arg0.getSession();
User user = (User) session.getAttribute("user");
System.out.println("user:" + user);
//如果user不为空,代表超时退出。否则是主动退出
if(user != null){
System.out.println("用户超时退出:" + user.getUserName());
userService.updatePreIp(user.getUserId(), user.getUserCurIP());
}else{
System.out.println("用户已经退出");
}
} }

核心代码便是

ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(
arg0.getSession().getServletContext());
userService = applicationContext.getBean(UserService.class);

第二个问题:在我的登出Controller方法中,我调用

session.invalidate();

后的确能够进入listener,也成功执行了service方法,但是却爆了错。这个错不影响什么,但是看起来难受

严重: Servlet.service() for servlet [springDispatcherServlet] in context with path [/target] threw exception [org.apache.shiro.session.InvalidSessionException: java.lang.IllegalStateException: getAttribute: Session already invalidated] with root cause
java.lang.IllegalStateException: getAttribute: Session already invalidated
at org.apache.catalina.session.StandardSession.getAttribute(StandardSession.java:1190)
at org.apache.catalina.session.StandardSessionFacade.getAttribute(StandardSessionFacade.java:103)
at org.apache.shiro.web.session.HttpServletSession.getAttribute(HttpServletSession.java:146)
at org.apache.shiro.session.ProxiedSession.getAttribute(ProxiedSession.java:121)
at org.apache.shiro.subject.support.DelegatingSubject.getRunAsPrincipalsStack(DelegatingSubject.java:469)
at org.apache.shiro.subject.support.DelegatingSubject.getPrincipals(DelegatingSubject.java:153)
at org.apache.shiro.subject.support.DelegatingSubject.getPrincipal(DelegatingSubject.java:149)
at org.apache.shiro.web.servlet.ShiroHttpServletRequest.getSubjectPrincipal(ShiroHttpServletRequest.java:96)
at org.apache.shiro.web.servlet.ShiroHttpServletRequest.getUserPrincipal(ShiroHttpServletRequest.java:112)
at org.springframework.web.servlet.FrameworkServlet.getUsernameForRequest(FrameworkServlet.java:1091)
at org.springframework.web.servlet.FrameworkServlet.publishRequestHandledEvent(FrameworkServlet.java:1077)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

看这句:

[org.apache.shiro.session.InvalidSessionException: java.lang.IllegalStateException: getAttribute: Session already invalidated]

可以知道这个shiro啊,他想找这个session玩,但是session已经不在了。经过查阅我猜整合了shiro之后,就得考虑shiro的感受了。那么shiro有没有退出的方法呢?

SecurityUtils.getSubject().logout();

原来有啊,我就在controller方法中把它也加上了。

运行成功之后,又报错了。

java.lang.IllegalStateException: invalidate: Session already invalidated

我很怀疑用了shiro之后,shiro就霸占了session。所以我就把session.invalidate去掉了

果然运行之后啥错误都没有了。

客户端地址:0:0:0:0:0:0:0:1
user:User [userId=14962441362734L7V7MF, userName=博美, ...]
用户主动退出:博美
---SessionListener---
user:User [userId=14962441362734L7V7MF, userName=博美, ...]
用户超时退出:博美
---SessionListener---
user:null
用户已经退出

这里说一下,虽然我们调用了让session失效的方法,但是等到session超时时间一到,会再次进入sessionListener中

Spring + Shiro 项目 + HttpSessionListener 【调用springService问题】&【Session失效问题】的更多相关文章

  1. spring boot项目启动报(No session repository could be auto-configured, check your configuration (session store type is 'null'))

    找到项目的application配置文件,增加 spring.session.store-type=none,重新启动问题解决 注:因为项目未使用redis管理session,可以如上设置,如果想使用 ...

  2. 解决ajax 遇到session失效后自动跳转的问题

    在项目中,经常会遇到session失效后,点击任何链接无反应的情况!这样给客户的体验就不是很好,以为是系统出了故障!所以在项目中我们会处理session失效后的跳转问题(一般给用户提示,并跳转后登录页 ...

  3. Spring Cloud项目中通过Feign进行内部服务调用发生401\407错误无返回信息的问题

    问题描述 最近在使用Spring Cloud改造现有服务的工作中,在内部服务的调用方式上选择了Feign组件,由于服务与服务之间有权限控制,发现通过Feign来进行调用时如果发生了401.407错误时 ...

  4. 控制反转和spring在项目中可以带来的好处

    Spring实例化Bean的三种方式分别是: 1,xml配置使用bean的类构造器 <bean id="personService" class="cn.servi ...

  5. Spring顶级项目以及Spring cloud组件

    作为java的屌丝,基本上跟上spring屌丝的步伐,也就跟上了主流技术. spring 顶级项目: Spring IO platform:用于系统部署,是可集成的,构建现代化应用的版本平台,具体来说 ...

  6. Java Spring MVC项目搭建(二)——项目配置

    1.站点配置文件web.xml 每一个Spring MVC 项目都必须有一个站点配置文件web.xml,他的主要功能吗....有一位大哥已经整理的很好,我借来了,大家看看: 引用博客地址: http: ...

  7. Spring Boot实战笔记(二)-- Spring常用配置(Scope、Spring EL和资源调用)

    一.Bean的Scope Scope描述的是Spring容器如何新建Bean实例的.Spring的Scope有以下几种,通过@Scope注解来实现. (1)Singleton:一个Spring容器中只 ...

  8. Shiro+Redis实现tomcat集群session共享

      一.背景 当我们使用了nginx做项目集群以后,就会出现一个很严重的问题亟待解决,那就是:tomcat集群之间如何实现session共享的问题,如果这个问题不解决,就会出现登陆过后再次请求资源依旧 ...

  9. spring shiro 集成

    1.向spring项目中添加shiro相关的依赖 <dependency> <groupId>commons-logging</groupId> <artif ...

随机推荐

  1. taro之React Native 端开发研究

    初步结论:如果想把 React Native 集成到现有的原生项目中,不能使用taro的React Native 端开发功能(目前来说不能实现,以后再观察).   RN开发有2种模式: 1.一是原生A ...

  2. Android中Json数据读取与创建的方法

    转自:http://www.jb51.net/article/70875.htm 首先介绍下JSON的定义,JSON是JavaScript Object Notation的缩写. 一种轻量级的数据交换 ...

  3. sho

    手工编程:hello world 全部用命令行工具和Notepad编辑器,用手工创建并编译一个C的命令行程序:hello world. public class Hello{         publ ...

  4. java 值传递 数组传递

    在java中,不允许程序员选择值传递还是地址传递各个参数,基本类型总是按值传递.对于对象来说,是将对象的引用也就是副本传递给了方法,在方法中只有对对象进行修改才能影响该对象的值,操作对象的引用时是无法 ...

  5. Socket、Session、Option和Pipe

    消息队列NetMQ 原理分析4-Socket.Session.Option和Pipe   消息队列NetMQ 原理分析4-Socket.Session.Option和Pipe 前言 介绍 目的 Soc ...

  6. chrome启用flash不询问

    69版本之后 打开 chrome://flags/#enable-ephemeral-flash-permission 把它从Default改为Disabled 重新打开Chrome,进入 chrom ...

  7. ubuntu16.04下载安装navicate

    1.下载试用版本地址: https://www.navicat.com.cn/download/navicat-premium 2.解压缩 tar -zxvf  /home/rain/download ...

  8. Kali2.0的简单使用--开启root用户登录

    1. 安装完kali之后 2. 修改/etc/ssh/sshd_conf的文件 将: #PasswordAuthentication no 修改为: PasswordAuthentication ye ...

  9. Linux 重启网络提示找不到eth0(no device found for “System eth0”)

    一.背景 使用VMWare创建了一个虚拟机(VM1),然后通过拷贝的方式创建了另一台虚拟机(VM2).在第二台虚拟机上设置网卡为固定IP,使用service network restart重启网络的时 ...

  10. App WebView实例化

    a,高级设置里的环境变量 jdk的配置 b,下载Google的sdk,里面直接包含eclipse 1,新建一个项目 2,起个名字 3,设么走不做,next 4,只操作选择显示的三种方式 5,next什 ...