Browse Source

定时删除过期的登录会话

huangxiao 1 week ago
parent
commit
424b461f43

+ 28 - 37
src/main/java/net/mingsoft/MSApplication.java

@@ -7,10 +7,10 @@
  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  * the Software, and to permit persons to whom the Software is furnished to do so,
  * the Software, and to permit persons to whom the Software is furnished to do so,
  * subject to the following conditions:
  * subject to the following conditions:
-
+ * <p>
  * The above copyright notice and this permission notice shall be included in all
  * The above copyright notice and this permission notice shall be included in all
  * copies or substantial portions of the Software.
  * copies or substantial portions of the Software.
-
+ * <p>
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
@@ -21,52 +21,43 @@
 
 
 package net.mingsoft;
 package net.mingsoft;
 
 
-import net.mingsoft.people.action.web.PeopleAction;
 import org.mybatis.spring.annotation.MapperScan;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.Banner;
 import org.springframework.boot.Banner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.web.servlet.ServletComponentScan;
 import org.springframework.boot.web.servlet.ServletComponentScan;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.FilterType;
 import org.springframework.core.env.Environment;
 import org.springframework.core.env.Environment;
 
 
-import java.util.logging.Logger;
-
 @SpringBootApplication(scanBasePackages = {"net.mingsoft"})
 @SpringBootApplication(scanBasePackages = {"net.mingsoft"})
-@MapperScan(basePackages={"**.dao","com.baomidou.**.mapper"})
+@MapperScan(basePackages = {"**.dao", "com.baomidou.**.mapper"})
 @ServletComponentScan(basePackages = {"net.mingsoft"})
 @ServletComponentScan(basePackages = {"net.mingsoft"})
-@ComponentScan(excludeFilters = @ComponentScan.Filter(
-		type = FilterType.ASSIGNABLE_TYPE,
-		classes = {PeopleAction.class}))
 public class MSApplication {
 public class MSApplication {
-	public static void main(String[] args) {
-		SpringApplication springApplication = new SpringApplication(MSApplication.class);
-		springApplication.setBannerMode(Banner.Mode.OFF);
-		ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);
-		Environment env = configurableApplicationContext.getEnvironment();
-		String port = env.getProperty("server.port", "8080");
-		String managerPath = env.getProperty("ms.manager.path", "");
-		String profiles = String.join(", ", env.getActiveProfiles());
-
-		System.out.printf(
-				"\n" +
-						"\033[1;36m" + // 青色加粗
-						"╔══════════════════════════════════════════════════════════╗\n" +
-						"║ \033[1;33m🚀 MCms Application Started Successfully! \033[1;36m               ║\n" +
-						"╠══════════════════════════════════════════════════════════╣\n" +
-						"║ \033[0;32m➜ Manager URL: \033[0;33mhttp://localhost:%s\033[1;36m%s\033[1;36m/login.do         ║\n" +
-						"║ \033[0;32m➜ Front URL: \033[0;33mhttp://localhost:%s/\033[1;36m                      ║\n" +
-						"║ \033[0;32m➜ Activate Profiles: \033[0;35m%s\033[1;36m                                 ║\n" +
-						"╚══════════════════════════════════════════════════════════╝" +
-						"\033[0m", // 重置颜色
-				port,
-				managerPath,
-				port,
-				profiles
-		);
-	}
+    public static void main(String[] args) {
+        SpringApplication springApplication = new SpringApplication(MSApplication.class);
+        springApplication.setBannerMode(Banner.Mode.OFF);
+        ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);
+        Environment env = configurableApplicationContext.getEnvironment();
+        String port = env.getProperty("server.port", "8080");
+        String managerPath = env.getProperty("ms.manager.path", "");
+        String profiles = String.join(", ", env.getActiveProfiles());
+        System.out.printf(
+                "\n" +
+                        "\033[1;36m" + // 青色加粗
+                        "╔══════════════════════════════════════════════════════════╗\n" +
+                        "║ \033[1;33m🚀 MCms Application Started Successfully! \033[1;36m               ║\n" +
+                        "╠══════════════════════════════════════════════════════════╣\n" +
+                        "║ \033[0;32m➜ Manager URL: \033[0;33mhttp://localhost:%s\033[1;36m%s\033[1;36m/login.do         ║\n" +
+                        "║ \033[0;32m➜ Front URL: \033[0;33mhttp://localhost:%s/\033[1;36m                      ║\n" +
+                        "║ \033[0;32m➜ Activate Profiles: \033[0;35m%s\033[1;36m                                 ║\n" +
+                        "╚══════════════════════════════════════════════════════════╝" +
+                        "\033[0m", // 重置颜色
+                port,
+                managerPath,
+                port,
+                profiles
+        );
+    }
 }
 }
 
 
 
 

+ 45 - 6
src/main/java/net/mingsoft/config/DbSessionDAO.java

@@ -2,11 +2,14 @@ package net.mingsoft.config;
 
 
 import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.ReflectUtil;
 import cn.hutool.core.util.ReflectUtil;
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Resource;
 import net.mingsoft.base.biz.IBaseBiz;
 import net.mingsoft.base.biz.IBaseBiz;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.session.mgt.SimpleSession;
 import org.apache.shiro.session.mgt.SimpleSession;
 import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
 import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
+import org.springframework.stereotype.Component;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Collection;
@@ -14,6 +17,7 @@ import java.util.Date;
 import java.util.Map;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
 
 
 /**
 /**
@@ -22,19 +26,28 @@ import java.util.stream.Stream;
  * @author hx
  * @author hx
  * @date 2025-10-31
  * @date 2025-10-31
  */
  */
+@Component
 public class DbSessionDAO extends MemorySessionDAO {
 public class DbSessionDAO extends MemorySessionDAO {
     /**
     /**
      * 随便一个能操作数据库的dao
      * 随便一个能操作数据库的dao
      */
      */
+    @Resource(name = "peopleBiz")
     private IBaseBiz<?> dao;
     private IBaseBiz<?> dao;
 
 
-    public DbSessionDAO(IBaseBiz<?> dao) {
+    public DbSessionDAO() {
         super();
         super();
-        this.dao = dao;
-        ConcurrentMap<Serializable, Session> sessions = new ConcurrentHashMap<>() {
+        runThread();
+        ReflectUtil.setFieldValue(this, "sessions", createMap());
+    }
+
+    /**
+     * 重写Map相关方法,使其可以对接数据库操作
+     */
+    private ConcurrentMap<Serializable, Session> createMap() {
+        return new ConcurrentHashMap<>() {
 
 
             @Override
             @Override
-            public Session putIfAbsent(Serializable key, Session value) {
+            public Session putIfAbsent(@Nonnull Serializable key, Session value) {
                 saveOrUpdate(key.toString(), (SimpleSession) value);
                 saveOrUpdate(key.toString(), (SimpleSession) value);
                 return super.putIfAbsent(key, value);
                 return super.putIfAbsent(key, value);
             }
             }
@@ -54,7 +67,7 @@ public class DbSessionDAO extends MemorySessionDAO {
             }
             }
 
 
             @Override
             @Override
-            public Session remove(Object key) {
+            public Session remove(@Nonnull Object key) {
                 delete(key.toString());
                 delete(key.toString());
                 return super.remove(key);
                 return super.remove(key);
             }
             }
@@ -64,7 +77,25 @@ public class DbSessionDAO extends MemorySessionDAO {
                 return all().map(row -> (Session) row).toList();
                 return all().map(row -> (Session) row).toList();
             }
             }
         };
         };
-        ReflectUtil.setFieldValue(this, "sessions", sessions);
+    }
+
+    /**
+     * 定时执行
+     * <p>
+     * 不知道为什么{@code @EnableScheduling}和{@code @Scheduled(cron = "0/5 * * * * ?")}不能生效
+     * <p>
+     * 能只用这种猥琐的方式
+     */
+    private void runThread() {
+        new Thread(() -> {
+            while (true) {
+                try {
+                    delete();
+                    TimeUnit.MINUTES.sleep(5);
+                } catch (Exception ignored) {
+                }
+            }
+        }).start();
     }
     }
 
 
     /**
     /**
@@ -107,6 +138,14 @@ public class DbSessionDAO extends MemorySessionDAO {
         dao.update("delete from login_session where id=?", key);
         dao.update("delete from login_session where id=?", key);
     }
     }
 
 
+    /**
+     * 每5分钟定时删除失效登录
+     */
+
+    public void delete() {
+        dao.update("delete from login_session where time<=now()");
+    }
+
     private static byte[] serialize(SimpleSession value) {
     private static byte[] serialize(SimpleSession value) {
         return ObjUtil.serialize(value);
         return ObjUtil.serialize(value);
     }
     }

+ 4 - 4
src/main/java/net/mingsoft/config/ShiroConfig.java

@@ -183,10 +183,10 @@ public class ShiroConfig {
         return modularRealmAuthenticator;
         return modularRealmAuthenticator;
     }
     }
 
 
-    @Bean
-    public AbstractSessionDAO getMemorySessionDAO(IPeopleBiz peopleBiz) {
-        return new DbSessionDAO(peopleBiz);
-    }
+    // @Bean
+    // public AbstractSessionDAO getMemorySessionDAO(IPeopleBiz peopleBiz) {
+    //     return new DbSessionDAO(peopleBiz);
+    // }
 
 
     @Bean
     @Bean
     public SimpleCookie getSimpleCookie() {
     public SimpleCookie getSimpleCookie() {

+ 34 - 1
zh.puml

@@ -153,9 +153,42 @@ participant 后台 as sys
 ui -> sys: wx.login 登录,带上code
 ui -> sys: wx.login 登录,带上code
 sys --> ui: 返回用户在微信的唯一标识openid\n如果已经注册过用,就返回用户信息和登录标识cookie\n如果没注册过,不会有登录标识cookie
 sys --> ui: 返回用户在微信的唯一标识openid\n如果已经注册过用,就返回用户信息和登录标识cookie\n如果没注册过,不会有登录标识cookie
 
 
-ui -> sys: 注册:\nwx.authorize(授权)\nwx.getUserProfile(得到用户信息)\ngetPhoneNumber(获得手机号)\n短信验证\n带上openid
+ui -> sys: 游客注册:\n如果没有用户信息,就是”游客“,就调用xx接口保存昵称和头像\n真实注册:\n调用”注册“接口保存用户的全部信息
 sys --> ui: 注册的结果
 sys --> ui: 注册的结果
 
 
 ui -> sys: 业务操作,带上登录标识cookie
 ui -> sys: 业务操作,带上登录标识cookie
 @enduml
 @enduml
 
 
+@startuml
+participant 用户 as user
+participant 亚洲展会小程序 as yz
+participant 票务系统 as pw
+participant 硬件闸机 as zj
+participant 支付宝 as zfb
+
+== 二维码 ==
+user -> yz: 登录、注册之后,生成入场二维码
+user -> zj: 出示入场二维码
+zj -> zj: 识别二维码
+zj -> pw: 携带二维码数据访问接口
+pw -> yz: 携带二维码数据访问接口
+yz -> yz: 执行判断逻辑\n判断该二维码是否可以入场
+yz --> pw: 返回是否可放行的结果
+pw --> zj: 返回是否可放行的结果
+zj --> zj: 根据结果判断是否开闸
+
+== 人脸识别 ==
+user -> yz: 注册时要录入人脸图片
+yz -> pw: 用户增、删、改时\n都要及时同步用户身份证号码
+pw -> zfb: 用身份证号码拿到人脸图片
+user -> zj: 在闸机前扫描人脸
+zj -> zj: 拍照人脸图片
+zj -> pw: 携带人脸图片访问接口
+pw -> pw: 识别人脸图片\n根据人脸图片查出对应的用户
+pw -> yz: 携带用户信息访问接口
+yz -> yz: 执行判断逻辑\n判断该用户是否可以入场
+yz --> pw: 返回是否可放行的结果
+pw --> zj: 返回是否可放行的结果
+zj --> zj: 根据结果判断是否开闸
+@enduml
+