若依系统(Ruoyi-Vue)去除redis数据库
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档。
·
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 目的
- 一、去除redis 配置
- 二、去除ruoyi-framework下RedisConfig的配置
- 三、在ruoyi-common的core/redis下新建MyMapCache类
- 四、关于RedisCache类
- 五、修改ruoyi-common下utils/DictUtils
- 六、修改基于redis的限流处理,使用令牌桶算法进行限流
- 七、修改ruoyi-framework下TokenService
目的
因为根据项目需求需要进行国产化适配,redis安装在国产化系统比较麻烦,并且不能通过国产化测评,所以现在对redis进行剥离。
一、去除redis 配置
去除ruoyi-admin下application.yml的redis配置!
二、去除ruoyi-framework下RedisConfig的配置
直接注释@Bean、@Configuration和@EnableCaching注解就可以了,不用删除RedisConfig,防止后期又要使用redis,直接放开就可以了。
三、在ruoyi-common的core/redis下新建MyMapCache类
@Component
public class MyMapCache{
public ConcurrentHashMap<String, Object> concurrentHashMap = new ConcurrentHashMap<String, Object>();
/**
* 放入值
*
* @param key
* @param value
*/
public void put(String key, Object value) {
concurrentHashMap.put(key, value);
}
/**
* 取值
*
* @param key
* @return
*/
public Object get(String key) {
return concurrentHashMap.get(key);
}
/**
* 移除
*
* @param k
*/
public void remove(String key) {
concurrentHashMap.remove(key);
}
}
四、关于RedisCache类
暂时用不到,但是为了防止系统报错,暂时不需要整改和删除。
五、修改ruoyi-common下utils/DictUtils
public class DictUtils {
/**
* 分隔符
*/
public static final String SEPARATOR = ",";
/**
* 设置字典缓存
*
* @param key 参数键
* @param dictDatas 字典数据列表
*/
public static void setDictCache(String key, List<SysDictData> dictDatas) {
SpringUtils.getBean(MyMapCache.class).put(getCacheKey(key), dictDatas);
}
/**
* 获取字典缓存
*
* @param key 参数键
* @return dictDatas 字典数据列表
*/
public static List<SysDictData> getDictCache(String key) {
Object cacheObj = SpringUtils.getBean(MyMapCache.class).get(getCacheKey(key));
if (StringUtils.isNotNull(cacheObj)) {
List<SysDictData> dictDatas = StringUtils.cast(cacheObj);
return dictDatas;
}
return null;
}
/**
* 根据字典类型和字典值获取字典标签
*
* @param dictType 字典类型
* @param dictValue 字典值
* @return 字典标签
*/
public static String getDictLabel(String dictType, String dictValue) {
return getDictLabel(dictType, dictValue, SEPARATOR);
}
/**
* 根据字典类型和字典标签获取字典值
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @return 字典值
*/
public static String getDictValue(String dictType, String dictLabel) {
return getDictValue(dictType, dictLabel, SEPARATOR);
}
/**
* 根据字典类型和字典值获取字典标签
*
* @param dictType 字典类型
* @param dictValue 字典值
* @param separator 分隔符
* @return 字典标签
*/
public static String getDictLabel(String dictType, String dictValue, String separator) {
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.containsAny(separator, dictValue) && StringUtils.isNotEmpty(datas)) {
for (SysDictData dict : datas) {
for (String value : dictValue.split(separator)) {
if (value.equals(dict.getDictValue())) {
propertyString.append(dict.getDictLabel() + separator);
break;
}
}
}
} else {
for (SysDictData dict : datas) {
if (dictValue.equals(dict.getDictValue())) {
return dict.getDictLabel();
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 根据字典类型和字典标签获取字典值
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @param separator 分隔符
* @return 字典值
*/
public static String getDictValue(String dictType, String dictLabel, String separator) {
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) {
for (SysDictData dict : datas) {
for (String label : dictLabel.split(separator)) {
if (label.equals(dict.getDictLabel())) {
propertyString.append(dict.getDictValue() + separator);
break;
}
}
}
} else {
for (SysDictData dict : datas) {
if (dictLabel.equals(dict.getDictLabel())) {
return dict.getDictValue();
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 删除指定字典缓存
*
* @param key 字典键
*/
public static void removeDictCache(String key) {
List<String> keys = new ArrayList<>();
MyCache myMapCache = SpringUtils.getBean(MyCache.class);
for (Map.Entry<String, Object> entry : myMapCache.concurrentHashMap.entrySet()) {
if (entry.getKey().startsWith(Constants.SYS_DICT_KEY)) {
keys.add(entry.getKey());
}
}
keys.forEach(item -> {
if (item.equals(key)) {
myMapCache.remove(item);
}
});
}
/**
* 清空字典缓存
*/
public static void clearDictCache() {
List<String> keys = new ArrayList<>();
MyMapCache myMapCache = SpringUtils.getBean(MyCache.class);
for (Map.Entry<String, Object> entry : myMapCache.concurrentHashMap.entrySet()) {
if (entry.getKey().startsWith(Constants.SYS_DICT_KEY)) {
keys.add(entry.getKey());
}
}
keys.forEach(item -> {
myMapCache.remove(item);
});
}
/**
* 设置cache key
*
* @param configKey 参数键
* @return 缓存键key
*/
public static String getCacheKey(String configKey) {
return Constants.SYS_DICT_KEY + configKey;
}
六、修改基于redis的限流处理,使用令牌桶算法进行限流
@Aspect
@Component
public class RateLimiterAspect {
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
private ConcurrentMap<String, TokenBucket> buckets = new ConcurrentHashMap<>();
@Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable {
String key = rateLimiter.key();
int time = rateLimiter.time();
int count = rateLimiter.count();
String combineKey = getCombineKey(rateLimiter, point);
TokenBucket bucket = buckets.computeIfAbsent(combineKey, k -> new TokenBucket(count, time));
if (!bucket.tryConsume()) {
throw new ServiceException("访问过于频繁,请稍候再试");
}
log.info("限制请求'{}',当前请求数'{}',缓存key'{}'", count, bucket.getTokens(), key);
}
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
StringBuilder stringBuilder = new StringBuilder(rateLimiter.key());
if (rateLimiter.limitType() == LimitType.IP) {
stringBuilder.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
}
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = method.getDeclaringClass();
stringBuilder.append(targetClass.getName()).append("-").append(method.getName());
return stringBuilder.toString();
}
private static class TokenBucket {
private final int capacity;
private long lastRefillTime;
private double tokens;
TokenBucket(int capacity, long refillInterval) {
this.capacity = capacity;
this.tokens = capacity;
this.lastRefillTime = System.currentTimeMillis();
// Start a background thread to refill the bucket periodically
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
() -> {
synchronized (TokenBucket.this) {
long now = System.currentTimeMillis();
double elapsedSeconds = (now - lastRefillTime) / 1000.0;
tokens = Math.min(capacity, tokens + elapsedSeconds * capacity / refillInterval);
lastRefillTime = now;
}
},
refillInterval,
refillInterval,
TimeUnit.MILLISECONDS
);
}
synchronized boolean tryConsume() {
if (tokens > 0) {
tokens--;
return true;
} else {
return false;
}
}
synchronized int getTokens() {
return (int) tokens;
}
}
}
七、修改ruoyi-framework下TokenService
@Component
public class TokenService
{
// 令牌自定义标识
@Value("${token.header}")
private String header;
// 令牌秘钥
@Value("${token.secret}")
private String secret;
// 令牌有效期(默认30分钟)
@Value("${token.expireTime}")
private int expireTime;
// 是否允许账户多终端同时登录(true允许 false不允许)
@Value("${token.soloLogin}")
private boolean soloLogin;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
@Autowired
MyMapCache myMapCache;
/**
* 获取用户身份信息
*
* @return 用户信息
*/
public LoginUser getLoginUser(HttpServletRequest request)
{
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token))
{
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = (LoginUser) myMapCache.get(userKey);
return user;
}
return null;
}
public LoginUser getLoginUser(String token){
if (StringUtils.isNotEmpty(token)){
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = (LoginUser) myMapCache.get(userKey);
return user;
}
return null;
}
/**
* 设置用户身份信息
*/
public void setLoginUser(LoginUser loginUser)
{
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
{
refreshToken(loginUser);
}
}
/**
* 删除用户身份信息
*/
public void delLoginUser(String token,Long userId)
{
if (StringUtils.isNotEmpty(token))
{
String userKey = getTokenKey(token);
myMapCache.remove(token);
myMapCache.remove(userKey);
}
if (!soloLogin && StringUtils.isNotNull(userId))
{
String userIdKey = getUserIdKey(userId);
myMapCache.remove(userIdKey);
}
}
/**
* 创建令牌
*
* @param loginUser 用户信息
* @return 令牌
* (在Constants定义一个
* public static final String LOGIN_USERID_KEY = "login_userid:";)
*/
private String getUserIdKey(Long userId)
{
return Constants.LOGIN_USERID_KEY + userId;
}
/**
* 创建令牌
*
* @param loginUser 用户信息
* @return 令牌
*/
public String createToken(LoginUser loginUser)
{
String token = IdUtils.fastUUID();
loginUser.setToken(token);
setUserAgent(loginUser);
refreshToken(loginUser);
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token);
return createToken(claims);
}
/**
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
*
* @param loginUser
* @return 令牌
*/
public void verifyToken(LoginUser loginUser)
{
long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
{
refreshToken(loginUser);
}
}
/**
* 刷新令牌有效期
*
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser)
{
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
String userKey = getTokenKey(loginUser.getToken());
myMapCache.put(userKey, loginUser);
if (!soloLogin)
{
// 缓存用户唯一标识,防止同一帐号,同时登录
String userIdKey = getUserIdKey(loginUser.getUser().getUserId());
myMapCache.put(userIdKey, userKey);
}
}
/**
* 设置用户代理信息
*
* @param loginUser 登录信息
*/
public void setUserAgent(LoginUser loginUser)
{
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
loginUser.setIpaddr(ip);
loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
loginUser.setBrowser(userAgent.getBrowser().getName());
loginUser.setOs(userAgent.getOperatingSystem().getName());
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims)
{
String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private Claims parseToken(String token)
{
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
public String getUsernameFromToken(String token)
{
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @param request
* @return token
*/
private String getToken(HttpServletRequest request)
{
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
{
token = token.replace(Constants.TOKEN_PREFIX, "");
}
return token;
}
private String getTokenKey(String uuid)
{
return Constants.LOGIN_TOKEN_KEY + uuid;
}
更多推荐
已为社区贡献1条内容
所有评论(0)