调整AppToken代码结构

This commit is contained in:
wanggeng 2021-11-30 14:36:49 +08:00
parent 186d3dcc68
commit d5b16d2b0d
12 changed files with 337 additions and 83 deletions

View File

@ -12,6 +12,12 @@
<artifactId>basic-app</artifactId> <artifactId>basic-app</artifactId>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>ink.wgink</groupId> <groupId>ink.wgink</groupId>
<artifactId>basic-interface</artifactId> <artifactId>basic-interface</artifactId>

View File

@ -1,23 +1,20 @@
package ink.wgink.app; package ink.wgink.app;
import com.alibaba.fastjson.JSONObject; 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.exceptions.TokenException;
import ink.wgink.interfaces.consts.ISystemConstant; import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.interfaces.manager.IAppManager; 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 ink.wgink.util.AesUtil;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* When you feel like quitting. Think about why you started * 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 final Logger LOG = LoggerFactory.getLogger(AppTokenManager.class);
private static AppTokenManager appTokenManager = AppTokenManagerBuilder.appTokenManager; private static AppTokenManager appTokenManager = AppTokenManagerBuilder.appTokenManager;
private static final Map<String, AppToken> tokens = new ConcurrentHashMap();
private IAppTokenService appTokenService;
private AppTokenManager() { private AppTokenManager() {
} }
@ -50,11 +48,7 @@ public class AppTokenManager implements IAppManager {
*/ */
@Override @Override
public AppToken getToken(String token) { public AppToken getToken(String token) {
AppToken appToken = tokens.get(token); return appTokenService.getToken(token);
if (appToken != null) {
appToken.setLastTime(System.currentTimeMillis());
}
return appToken;
} }
/** /**
@ -65,19 +59,7 @@ public class AppTokenManager implements IAppManager {
* @param appTokenUser * @param appTokenUser
*/ */
public synchronized void addToken(String token, AppToken.AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser) { public synchronized void addToken(String token, AppToken.AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser) {
AppToken appToken = new AppToken(); appTokenService.addToken(token, appTokenTypeEnum, appTokenUser);
appToken.setToken(token);
appToken.setAppTokenTypeEnum(appTokenTypeEnum);
appToken.setLastTime(System.currentTimeMillis());
appToken.setAppTokenUser(appTokenUser);
appToken.setUserId(appTokenUser.getId());
for (Map.Entry<String, AppToken> kvs : tokens.entrySet()) {
if (StringUtils.equals(appTokenUser.getId(), kvs.getValue().getUserId())) {
tokens.remove(kvs.getValue().getToken());
break;
}
}
tokens.put(token, appToken);
} }
@Override @Override
@ -124,31 +106,20 @@ public class AppTokenManager implements IAppManager {
*/ */
@Override @Override
public List<AppTokenUser> listCurrentUsers() { public List<AppTokenUser> listCurrentUsers() {
List<AppTokenUser> users = new ArrayList<>(); return appTokenService.listCurrentUsers();
for (Map.Entry<String, AppToken> kvs : tokens.entrySet()) {
AppToken appToken = kvs.getValue();
users.add(appToken.getAppTokenUser());
}
return users;
} }
/** /**
* 清空超时Token * 清空超时Token
*/ */
public synchronized void clearTimeoutToken() { public synchronized void clearTimeoutToken() {
long currentTime = System.currentTimeMillis(); appTokenService.clearTimeoutToken();
List<String> clearTokenKeys = new ArrayList<>(0);
for (Map.Entry<String, AppToken> kvs : tokens.entrySet()) {
AppToken appToken = kvs.getValue();
// 超过10分钟
if (currentTime - appToken.getLastTime() > 600000L) {
clearTokenKeys.add(kvs.getKey());
} }
}
for (String tokenKey : clearTokenKeys) { @Override
tokens.remove(tokenKey); public void setAppTokenService(IAppTokenService appTokenService) {
} this.appTokenService = appTokenService;
LOG.trace("本次共清理超时Token:{}个", clearTokenKeys.size());
} }
private static class AppTokenManagerBuilder { private static class AppTokenManagerBuilder {

View File

@ -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();
}
}

View File

@ -118,12 +118,10 @@ public class AppTokenFilter extends GenericFilterBean implements InitializingBea
*/ */
private void checkToken(String token) throws TokenException { private void checkToken(String token) throws TokenException {
AppTokenManager appTokenManager = AppTokenManager.getInstance(); AppTokenManager appTokenManager = AppTokenManager.getInstance();
LOG.debug("检查token是否存在");
AppToken appToken = appTokenManager.getToken(token); AppToken appToken = appTokenManager.getToken(token);
if (appToken != null) { if (appToken != null) {
return; return;
} }
LOG.debug("解析token是否合法");
AppTokenUser appTokenUser = appTokenManager.parseToAppTokenUser(token); AppTokenUser appTokenUser = appTokenManager.parseToAppTokenUser(token);
appTokenManager.addToken(token, AppToken.AppTokenTypeEnum.APP, appTokenUser); appTokenManager.addToken(token, AppToken.AppTokenTypeEnum.APP, appTokenUser);
} }

View File

@ -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<String, AppToken> 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<String, AppToken> kvs : tokens.entrySet()) {
if (StringUtils.equals(appTokenUser.getId(), kvs.getValue().getUserId())) {
tokens.remove(kvs.getValue().getToken());
break;
}
}
tokens.put(token, appToken);
}
@Override
public List<AppTokenUser> listCurrentUsers() {
List<AppTokenUser> users = new ArrayList<>();
for (Map.Entry<String, AppToken> kvs : tokens.entrySet()) {
AppToken appToken = kvs.getValue();
users.add(appToken.getAppTokenUser());
}
return users;
}
@Override
public void clearTimeoutToken() {
long currentTime = System.currentTimeMillis();
List<String> clearTokenKeys = new ArrayList<>(0);
for (Map.Entry<String, AppToken> 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());
}
}

View File

@ -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();
}
}

View File

@ -45,7 +45,7 @@ public interface IAppManager {
/** /**
* 设置redis token 管理器 * 设置redis token 管理器
* *
* @param redisAppTokenManager * @param appTokenService
*/ */
void setRedisAppTokenManager(IRedisAppTokenManager redisAppTokenManager); void setAppTokenService(IAppTokenService appTokenService);
} }

View File

@ -12,9 +12,9 @@ import java.util.List;
* @Date: 2021/11/29 4:30 下午 * @Date: 2021/11/29 4:30 下午
* @Version: 1.0 * @Version: 1.0
*/ */
public interface IRedisAppTokenManager { public interface IAppTokenService {
String TOKEN_HASH_KEY = "app:tokens"; String TOKEN_HASH_KEY = "app:tokens:";
/** /**
* 获取token * 获取token
@ -27,20 +27,21 @@ public interface IRedisAppTokenManager {
/** /**
* 添加token * 添加token
* *
* @param appToken * @param token
* @param appTokenTypeEnum
* @param appTokenUser
*/ */
void addToken(AppToken appToken); void addToken(String token, AppToken.AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser);
/** /**
* app当前在线用户 * 获取当前在线的用户列表
* *
* @return * @return
*/ */
List<AppTokenUser> listCurrentUsers(); List<AppTokenUser> listCurrentUsers();
/** /**
* 清理超时token * 清空超时token
* @param clearTokenKeys
*/ */
void clearTimeoutToken(); void clearTimeoutToken();
} }

View File

@ -168,6 +168,11 @@
<artifactId>spring-boot-autoconfigure</artifactId> <artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version> <version>${spring-boot.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- springboot end --> <!-- springboot end -->
<!-- fastjson start --> <!-- fastjson start -->

51
redis-cache/pom.xml Normal file
View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>wg-basic</artifactId>
<groupId>ink.wgink</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>redis-cache</artifactId>
<description>redis缓存</description>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<!-- netty start -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<scope>provided</scope>
</dependency>
<!-- netty end -->
<dependency>
<groupId>ink.wgink</groupId>
<artifactId>basic-exception</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ink.wgink</groupId>
<artifactId>basic-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ink.wgink</groupId>
<artifactId>basic-util</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ink.wgink</groupId>
<artifactId>basic-properties</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -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<String, AppToken> tokens = redisTemplate.opsForHash().entries(TOKEN_HASH_KEY);
for (Map.Entry<String, AppToken> 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<AppTokenUser> listCurrentUsers() {
List<AppTokenUser> users = new ArrayList<>();
Map<String, AppToken> tokens = redisTemplate.opsForHash().entries(TOKEN_HASH_KEY);
for (Map.Entry<String, AppToken> kvs : tokens.entrySet()) {
AppToken appToken = kvs.getValue();
users.add(appToken.getAppTokenUser());
}
return users;
}
@Override
public void clearTimeoutToken() {
long currentTime = System.currentTimeMillis();
List<String> clearTokenKeys = new ArrayList<>(0);
Map<String, AppToken> tokens = redisTemplate.opsForHash().entries(TOKEN_HASH_KEY);
for (Map.Entry<String, AppToken> 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());
}
}

View File

@ -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的乱码问题
* <p>
* 乱码原因
* spring-data-redis RedisTemplate<K, V>模板类 在操作redis时默认使用JdkSerializationRedisSerializer 来进行序列化spring操作redis是在jedis客户端基础上进行的而jedis客户端与redis交互的时候协议中定义是用byte类型交互看到spring-data-redis中RedisTemplate<K, V>在操作的时候kv是泛型对象而不是byte[]类型的
* 这样导致的一个问题就是如果不对RedisTemplate进行设置spring会默认采用defaultSerializer = new JdkSerializationRedisSerializer();这个方法来对keyvalue进行序列化操作JdkSerializationRedisSerializer它使用的编码是ISO-8859-1
* </p>
* @Author: wanggeng
* @Date: 2021/11/29 5:37 下午
* @Version: 1.0
*/
@Configuration
public class RedisConfig {
@Bean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
RedisSerializer<String> 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;
}
}