diff --git a/basic-app/pom.xml b/basic-app/pom.xml index 402484da..0c155bfb 100644 --- a/basic-app/pom.xml +++ b/basic-app/pom.xml @@ -12,6 +12,12 @@ basic-app + + org.springframework.boot + spring-boot + provided + + ink.wgink basic-interface diff --git a/basic-app/src/main/java/ink/wgink/app/AppTokenManager.java b/basic-app/src/main/java/ink/wgink/app/AppTokenManager.java index 8040eded..5906fff5 100644 --- a/basic-app/src/main/java/ink/wgink/app/AppTokenManager.java +++ b/basic-app/src/main/java/ink/wgink/app/AppTokenManager.java @@ -1,23 +1,20 @@ package ink.wgink.app; import com.alibaba.fastjson.JSONObject; -import ink.wgink.pojo.app.AppToken; -import ink.wgink.pojo.app.AppTokenUser; import ink.wgink.exceptions.TokenException; import ink.wgink.interfaces.consts.ISystemConstant; import ink.wgink.interfaces.manager.IAppManager; +import ink.wgink.interfaces.manager.IAppTokenService; +import ink.wgink.pojo.app.AppToken; +import ink.wgink.pojo.app.AppTokenUser; import ink.wgink.util.AesUtil; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; /** * When you feel like quitting. Think about why you started @@ -33,7 +30,8 @@ public class AppTokenManager implements IAppManager { private static final Logger LOG = LoggerFactory.getLogger(AppTokenManager.class); private static AppTokenManager appTokenManager = AppTokenManagerBuilder.appTokenManager; - private static final Map tokens = new ConcurrentHashMap(); + + private IAppTokenService appTokenService; private AppTokenManager() { } @@ -50,11 +48,7 @@ public class AppTokenManager implements IAppManager { */ @Override public AppToken getToken(String token) { - AppToken appToken = tokens.get(token); - if (appToken != null) { - appToken.setLastTime(System.currentTimeMillis()); - } - return appToken; + return appTokenService.getToken(token); } /** @@ -65,19 +59,7 @@ public class AppTokenManager implements IAppManager { * @param appTokenUser */ public synchronized void addToken(String token, AppToken.AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser) { - AppToken appToken = new AppToken(); - appToken.setToken(token); - appToken.setAppTokenTypeEnum(appTokenTypeEnum); - appToken.setLastTime(System.currentTimeMillis()); - appToken.setAppTokenUser(appTokenUser); - appToken.setUserId(appTokenUser.getId()); - for (Map.Entry kvs : tokens.entrySet()) { - if (StringUtils.equals(appTokenUser.getId(), kvs.getValue().getUserId())) { - tokens.remove(kvs.getValue().getToken()); - break; - } - } - tokens.put(token, appToken); + appTokenService.addToken(token, appTokenTypeEnum, appTokenUser); } @Override @@ -124,31 +106,20 @@ public class AppTokenManager implements IAppManager { */ @Override public List listCurrentUsers() { - List users = new ArrayList<>(); - for (Map.Entry kvs : tokens.entrySet()) { - AppToken appToken = kvs.getValue(); - users.add(appToken.getAppTokenUser()); - } - return users; + return appTokenService.listCurrentUsers(); + } /** * 清空超时Token */ public synchronized void clearTimeoutToken() { - long currentTime = System.currentTimeMillis(); - List clearTokenKeys = new ArrayList<>(0); - for (Map.Entry kvs : tokens.entrySet()) { - AppToken appToken = kvs.getValue(); - // 超过10分钟 - if (currentTime - appToken.getLastTime() > 600000L) { - clearTokenKeys.add(kvs.getKey()); - } - } - for (String tokenKey : clearTokenKeys) { - tokens.remove(tokenKey); - } - LOG.trace("本次共清理超时Token:{}个", clearTokenKeys.size()); + appTokenService.clearTimeoutToken(); + } + + @Override + public void setAppTokenService(IAppTokenService appTokenService) { + this.appTokenService = appTokenService; } private static class AppTokenManagerBuilder { diff --git a/basic-app/src/main/java/ink/wgink/app/AppTokenTask.java b/basic-app/src/main/java/ink/wgink/app/AppTokenTask.java deleted file mode 100644 index 08780a4f..00000000 --- a/basic-app/src/main/java/ink/wgink/app/AppTokenTask.java +++ /dev/null @@ -1,28 +0,0 @@ -package ink.wgink.app; - -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -/** - * When you feel like quitting. Think about why you started - * 当你想要放弃的时候,想想当初你为何开始 - * - * @ClassName: AppTokenTask - * @Description: app token 定时任务 - * @Author: WangGeng - * @Date: 2019-08-10 14:50 - * @Version: 1.0 - **/ -@Component -@Configuration -@EnableScheduling -public class AppTokenTask { - - @Scheduled(cron = "0 0/1 * * * ?") - public void clearAppTokenUser() { - AppTokenManager.getInstance().clearTimeoutToken(); - } - -} diff --git a/basic-app/src/main/java/ink/wgink/app/filter/AppTokenFilter.java b/basic-app/src/main/java/ink/wgink/app/filter/AppTokenFilter.java index b54c27dc..f390815d 100644 --- a/basic-app/src/main/java/ink/wgink/app/filter/AppTokenFilter.java +++ b/basic-app/src/main/java/ink/wgink/app/filter/AppTokenFilter.java @@ -118,12 +118,10 @@ public class AppTokenFilter extends GenericFilterBean implements InitializingBea */ private void checkToken(String token) throws TokenException { AppTokenManager appTokenManager = AppTokenManager.getInstance(); - LOG.debug("检查token是否存在"); AppToken appToken = appTokenManager.getToken(token); if (appToken != null) { return; } - LOG.debug("解析token是否合法"); AppTokenUser appTokenUser = appTokenManager.parseToAppTokenUser(token); appTokenManager.addToken(token, AppToken.AppTokenTypeEnum.APP, appTokenUser); } diff --git a/basic-app/src/main/java/ink/wgink/app/impl/DefaultAppTokenServiceImpl.java b/basic-app/src/main/java/ink/wgink/app/impl/DefaultAppTokenServiceImpl.java new file mode 100644 index 00000000..275e0162 --- /dev/null +++ b/basic-app/src/main/java/ink/wgink/app/impl/DefaultAppTokenServiceImpl.java @@ -0,0 +1,82 @@ +package ink.wgink.app.impl; + +import ink.wgink.interfaces.manager.IAppTokenService; +import ink.wgink.pojo.app.AppToken; +import ink.wgink.pojo.app.AppTokenUser; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @ClassName: DefaultAppTokenService + * @Description: 默认app token 实现 + * @Author: wanggeng + * @Date: 2021/11/30 2:05 下午 + * @Version: 1.0 + */ +@Service +public class DefaultAppTokenServiceImpl implements IAppTokenService { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultAppTokenServiceImpl.class); + + private static final Map tokens = new ConcurrentHashMap(); + + @Override + public AppToken getToken(String token) { + AppToken appToken = tokens.get(token); + if (appToken != null) { + appToken.setLastTime(System.currentTimeMillis()); + } + return appToken; + } + + @Override + public void addToken(String token, AppToken.AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser) { + AppToken appToken = new AppToken(); + appToken.setToken(token); + appToken.setAppTokenTypeEnum(appTokenTypeEnum); + appToken.setLastTime(System.currentTimeMillis()); + appToken.setAppTokenUser(appTokenUser); + appToken.setUserId(appTokenUser.getId()); + for (Map.Entry kvs : tokens.entrySet()) { + if (StringUtils.equals(appTokenUser.getId(), kvs.getValue().getUserId())) { + tokens.remove(kvs.getValue().getToken()); + break; + } + } + tokens.put(token, appToken); + } + + @Override + public List listCurrentUsers() { + List users = new ArrayList<>(); + for (Map.Entry kvs : tokens.entrySet()) { + AppToken appToken = kvs.getValue(); + users.add(appToken.getAppTokenUser()); + } + return users; + } + + @Override + public void clearTimeoutToken() { + long currentTime = System.currentTimeMillis(); + List clearTokenKeys = new ArrayList<>(0); + for (Map.Entry kvs : tokens.entrySet()) { + AppToken appToken = kvs.getValue(); + // 超过10分钟 + if (currentTime - appToken.getLastTime() > 600000L) { + clearTokenKeys.add(kvs.getKey()); + } + } + for (String tokenKey : clearTokenKeys) { + tokens.remove(tokenKey); + } + LOG.trace("本次共清理超时Token:{}个", clearTokenKeys.size()); + } +} diff --git a/basic-app/src/main/java/ink/wgink/app/startup/AppTokenStartup.java b/basic-app/src/main/java/ink/wgink/app/startup/AppTokenStartup.java new file mode 100644 index 00000000..b0f5dc6c --- /dev/null +++ b/basic-app/src/main/java/ink/wgink/app/startup/AppTokenStartup.java @@ -0,0 +1,34 @@ +package ink.wgink.app.startup; + +import ink.wgink.app.AppTokenManager; +import ink.wgink.interfaces.manager.IAppTokenService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * @ClassName: AppTokenStartup + * @Description: + * @Author: wanggeng + * @Date: 2021/11/30 2:14 下午 + * @Version: 1.0 + */ +@Component +public class AppTokenStartup implements ApplicationRunner { + + @Autowired + private IAppTokenService appTokenService; + + @Override + public void run(ApplicationArguments args) throws Exception { + AppTokenManager.getInstance().setAppTokenService(appTokenService); + } + + @Scheduled(cron = "0 0/1 * * * ?") + public void clearAppTokenUser() { + AppTokenManager.getInstance().clearTimeoutToken(); + } + +} diff --git a/basic-interface/src/main/java/ink/wgink/interfaces/manager/IAppManager.java b/basic-interface/src/main/java/ink/wgink/interfaces/manager/IAppManager.java index a33f04c3..261fee56 100644 --- a/basic-interface/src/main/java/ink/wgink/interfaces/manager/IAppManager.java +++ b/basic-interface/src/main/java/ink/wgink/interfaces/manager/IAppManager.java @@ -45,7 +45,7 @@ public interface IAppManager { /** * 设置redis token 管理器 * - * @param redisAppTokenManager + * @param appTokenService */ - void setRedisAppTokenManager(IRedisAppTokenManager redisAppTokenManager); + void setAppTokenService(IAppTokenService appTokenService); } diff --git a/basic-interface/src/main/java/ink/wgink/interfaces/manager/IRedisAppTokenManager.java b/basic-interface/src/main/java/ink/wgink/interfaces/manager/IAppTokenService.java similarity index 64% rename from basic-interface/src/main/java/ink/wgink/interfaces/manager/IRedisAppTokenManager.java rename to basic-interface/src/main/java/ink/wgink/interfaces/manager/IAppTokenService.java index d98167bd..04402706 100644 --- a/basic-interface/src/main/java/ink/wgink/interfaces/manager/IRedisAppTokenManager.java +++ b/basic-interface/src/main/java/ink/wgink/interfaces/manager/IAppTokenService.java @@ -12,9 +12,9 @@ import java.util.List; * @Date: 2021/11/29 4:30 下午 * @Version: 1.0 */ -public interface IRedisAppTokenManager { +public interface IAppTokenService { - String TOKEN_HASH_KEY = "app:tokens"; + String TOKEN_HASH_KEY = "app:tokens:"; /** * 获取token @@ -27,20 +27,21 @@ public interface IRedisAppTokenManager { /** * 添加token * - * @param appToken + * @param token + * @param appTokenTypeEnum + * @param appTokenUser */ - void addToken(AppToken appToken); + void addToken(String token, AppToken.AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser); /** - * app当前在线用户 + * 获取当前在线的用户列表 * * @return */ List listCurrentUsers(); /** - * 清理超时token - * @param clearTokenKeys + * 清空超时token */ void clearTimeoutToken(); } diff --git a/pom.xml b/pom.xml index a83a67bc..2441d790 100644 --- a/pom.xml +++ b/pom.xml @@ -168,6 +168,11 @@ spring-boot-autoconfigure ${spring-boot.version} + + org.springframework.boot + spring-boot + ${spring-boot.version} + diff --git a/redis-cache/pom.xml b/redis-cache/pom.xml new file mode 100644 index 00000000..84bf9af8 --- /dev/null +++ b/redis-cache/pom.xml @@ -0,0 +1,51 @@ + + + + wg-basic + ink.wgink + 1.0-SNAPSHOT + + 4.0.0 + + redis-cache + redis缓存 + + + + org.springframework.data + spring-data-redis + + + + + io.netty + netty-all + provided + + + + + ink.wgink + basic-exception + 1.0-SNAPSHOT + + + ink.wgink + basic-interface + 1.0-SNAPSHOT + + + ink.wgink + basic-util + 1.0-SNAPSHOT + + + ink.wgink + basic-properties + 1.0-SNAPSHOT + + + + \ No newline at end of file diff --git a/redis-cache/src/main/java/ink/wgink/redis/cache/manager/app/RedisAppTokenService.java b/redis-cache/src/main/java/ink/wgink/redis/cache/manager/app/RedisAppTokenService.java new file mode 100644 index 00000000..10169fc3 --- /dev/null +++ b/redis-cache/src/main/java/ink/wgink/redis/cache/manager/app/RedisAppTokenService.java @@ -0,0 +1,89 @@ +package ink.wgink.redis.cache.manager.app; + +import ink.wgink.interfaces.manager.IAppTokenService; +import ink.wgink.pojo.app.AppToken; +import ink.wgink.pojo.app.AppTokenUser; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @ClassName: RedisAppTokenManager + * @Description: redis app token 管理器 + * @Author: wanggeng + * @Date: 2021/11/29 4:25 下午 + * @Version: 1.0 + */ +@Primary +@Service +public class RedisAppTokenService implements IAppTokenService { + + private static final Logger LOG = LoggerFactory.getLogger(RedisAppTokenService.class); + @Autowired + private RedisTemplate redisTemplate; + + @Override + public AppToken getToken(String token) { + AppToken appToken = (AppToken) redisTemplate.opsForHash().entries(TOKEN_HASH_KEY).get(token); + if (appToken != null) { + appToken.setLastTime(System.currentTimeMillis()); + redisTemplate.opsForHash().put(TOKEN_HASH_KEY, appToken.getToken(), appToken); + } + return appToken; + } + + @Override + public void addToken(String token, AppToken.AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser) { + AppToken appToken = new AppToken(); + appToken.setToken(token); + appToken.setAppTokenTypeEnum(appTokenTypeEnum); + appToken.setLastTime(System.currentTimeMillis()); + appToken.setAppTokenUser(appTokenUser); + appToken.setUserId(appTokenUser.getId()); + Map tokens = redisTemplate.opsForHash().entries(TOKEN_HASH_KEY); + for (Map.Entry kvs : tokens.entrySet()) { + if (StringUtils.equals(appToken.getAppTokenUser().getId(), kvs.getValue().getUserId())) { + redisTemplate.opsForHash().delete(TOKEN_HASH_KEY, kvs.getValue().getToken()); + break; + } + } + redisTemplate.opsForHash().put(TOKEN_HASH_KEY, appToken.getToken(), appToken); + } + + @Override + public List listCurrentUsers() { + List users = new ArrayList<>(); + Map tokens = redisTemplate.opsForHash().entries(TOKEN_HASH_KEY); + for (Map.Entry kvs : tokens.entrySet()) { + AppToken appToken = kvs.getValue(); + users.add(appToken.getAppTokenUser()); + } + return users; + } + + @Override + public void clearTimeoutToken() { + long currentTime = System.currentTimeMillis(); + List clearTokenKeys = new ArrayList<>(0); + Map tokens = redisTemplate.opsForHash().entries(TOKEN_HASH_KEY); + for (Map.Entry kvs : tokens.entrySet()) { + AppToken appToken = kvs.getValue(); + // 超过10分钟 + if (currentTime - appToken.getLastTime() > 600000L) { + clearTokenKeys.add(kvs.getKey()); + } + } + for (String tokenKey : clearTokenKeys) { + redisTemplate.opsForHash().delete(TOKEN_HASH_KEY, tokenKey); + } + LOG.trace("本次共清理超时Token:{}个", clearTokenKeys.size()); + } +} diff --git a/redis-cache/src/main/java/ink/wgink/redis/cache/manager/config/RedisConfig.java b/redis-cache/src/main/java/ink/wgink/redis/cache/manager/config/RedisConfig.java new file mode 100644 index 00000000..521d53c4 --- /dev/null +++ b/redis-cache/src/main/java/ink/wgink/redis/cache/manager/config/RedisConfig.java @@ -0,0 +1,45 @@ +package ink.wgink.redis.cache.manager.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * @ClassName: RedisConfig + * @Description: 解决key的乱码问题 + *

+ * 乱码原因: + * spring-data-redis 的 RedisTemplate模板类 在操作redis时默认使用JdkSerializationRedisSerializer 来进行序列化。spring操作redis是在jedis客户端基础上进行的,而jedis客户端与redis交互的时候协议中定义是用byte类型交互,看到spring-data-redis中RedisTemplate在操作的时候k,v是泛型对象,而不是byte[]类型的, + * 这样导致的一个问题就是,如果不对RedisTemplate进行设置,spring会默认采用defaultSerializer = new JdkSerializationRedisSerializer();这个方法来对key、value进行序列化操作,JdkSerializationRedisSerializer它使用的编码是ISO-8859-1 + *

+ * @Author: wanggeng + * @Date: 2021/11/29 5:37 下午 + * @Version: 1.0 + */ +@Configuration +public class RedisConfig { + + @Bean(name = "redisTemplate") + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + RedisSerializer stringRedisSerializer = new StringRedisSerializer(); + GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); + + template.setConnectionFactory(factory); + //key序列化方式 + template.setKeySerializer(stringRedisSerializer); + //value序列化 + template.setValueSerializer(genericJackson2JsonRedisSerializer); + //value hashmap序列化 + template.setHashValueSerializer(genericJackson2JsonRedisSerializer); + //key haspmap序列化 + template.setHashKeySerializer(stringRedisSerializer); + + return template; + } + +}