调整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>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ink.wgink</groupId>
<artifactId>basic-interface</artifactId>

View File

@ -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<String, AppToken> 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<String, AppToken> 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<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;
return appTokenService.listCurrentUsers();
}
/**
* 清空超时Token
*/
public synchronized 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());
appTokenService.clearTimeoutToken();
}
}
for (String tokenKey : clearTokenKeys) {
tokens.remove(tokenKey);
}
LOG.trace("本次共清理超时Token:{}个", clearTokenKeys.size());
@Override
public void setAppTokenService(IAppTokenService appTokenService) {
this.appTokenService = appTokenService;
}
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 {
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);
}

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 管理器
*
* @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 下午
* @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<AppTokenUser> listCurrentUsers();
/**
* 清理超时token
* @param clearTokenKeys
* 清空超时token
*/
void clearTimeoutToken();
}

View File

@ -168,6 +168,11 @@
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- springboot end -->
<!-- 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;
}
}