youjianchi
1 year ago
30 changed files with 969 additions and 1411 deletions
@ -1,91 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||
<ehcache name="ruoyi" updateCheck="false"> |
|
||||
|
|
||||
<!-- 磁盘缓存位置 --> |
|
||||
<diskStore path="java.io.tmpdir"/> |
|
||||
|
|
||||
<!-- maxEntriesLocalHeap:堆内存中最大缓存对象数,0没有限制 --> |
|
||||
<!-- maxElementsInMemory: 在内存中缓存的element的最大数目。--> |
|
||||
<!-- eternal:elements是否永久有效,如果为true,timeouts将被忽略,element将永不过期 --> |
|
||||
<!-- timeToIdleSeconds:失效前的空闲秒数,当eternal为false时,这个属性才有效,0为不限制 --> |
|
||||
<!-- timeToLiveSeconds:失效前的存活秒数,创建时间到失效时间的间隔为存活时间,当eternal为false时,这个属性才有效,0为不限制 --> |
|
||||
<!-- overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上 --> |
|
||||
<!-- statistics:是否收集统计信息。如果需要监控缓存使用情况,应该打开这个选项。默认为关闭(统计会影响性能)。设置statistics="true"开启统计 --> |
|
||||
|
|
||||
<!-- 默认缓存 --> |
|
||||
<defaultCache |
|
||||
maxEntriesLocalHeap="1000" |
|
||||
eternal="false" |
|
||||
timeToIdleSeconds="3600" |
|
||||
timeToLiveSeconds="3600" |
|
||||
overflowToDisk="false"> |
|
||||
</defaultCache> |
|
||||
|
|
||||
<!-- 登录记录缓存 锁定10分钟 --> |
|
||||
<cache name="loginRecordCache" |
|
||||
maxEntriesLocalHeap="2000" |
|
||||
eternal="false" |
|
||||
timeToIdleSeconds="600" |
|
||||
timeToLiveSeconds="0" |
|
||||
overflowToDisk="false" |
|
||||
statistics="false"> |
|
||||
</cache> |
|
||||
|
|
||||
<!-- 系统活跃用户缓存 --> |
|
||||
<cache name="sys-userCache" |
|
||||
maxEntriesLocalHeap="10000" |
|
||||
overflowToDisk="false" |
|
||||
eternal="false" |
|
||||
diskPersistent="false" |
|
||||
timeToLiveSeconds="0" |
|
||||
timeToIdleSeconds="0" |
|
||||
statistics="false"> |
|
||||
</cache> |
|
||||
|
|
||||
<!-- 系统用户授权缓存 没必要过期 --> |
|
||||
<cache name="sys-authCache" |
|
||||
maxEntriesLocalHeap="10000" |
|
||||
overflowToDisk="false" |
|
||||
eternal="false" |
|
||||
diskPersistent="false" |
|
||||
timeToLiveSeconds="0" |
|
||||
timeToIdleSeconds="0" |
|
||||
memoryStoreEvictionPolicy="LRU" |
|
||||
statistics="false"/> |
|
||||
|
|
||||
<!-- 系统缓存 --> |
|
||||
<cache name="sys-cache" |
|
||||
maxEntriesLocalHeap="1000" |
|
||||
eternal="true" |
|
||||
overflowToDisk="true" |
|
||||
statistics="false"> |
|
||||
</cache> |
|
||||
|
|
||||
<!-- 系统参数缓存 --> |
|
||||
<cache name="sys-config" |
|
||||
maxEntriesLocalHeap="1000" |
|
||||
eternal="true" |
|
||||
overflowToDisk="true" |
|
||||
statistics="false"> |
|
||||
</cache> |
|
||||
|
|
||||
<!-- 系统字典缓存 --> |
|
||||
<cache name="sys-dict" |
|
||||
maxEntriesLocalHeap="1000" |
|
||||
eternal="true" |
|
||||
overflowToDisk="true" |
|
||||
statistics="false"> |
|
||||
</cache> |
|
||||
|
|
||||
<!-- 系统会话缓存 --> |
|
||||
<cache name="shiro-activeSessionCache" |
|
||||
maxEntriesLocalHeap="10000" |
|
||||
overflowToDisk="false" |
|
||||
eternal="false" |
|
||||
diskPersistent="false" |
|
||||
timeToLiveSeconds="0" |
|
||||
timeToIdleSeconds="0" |
|
||||
statistics="false"/> |
|
||||
|
|
||||
</ehcache> |
|
||||
|
|
@ -0,0 +1,316 @@ |
|||||
|
package com.ruoyi.common.core.redis; |
||||
|
|
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.util.*; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.data.redis.core.BoundSetOperations; |
||||
|
import org.springframework.data.redis.core.HashOperations; |
||||
|
import org.springframework.data.redis.core.RedisTemplate; |
||||
|
import org.springframework.data.redis.core.ValueOperations; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* spring redis 工具类 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
**/ |
||||
|
@SuppressWarnings(value = { "unchecked", "rawtypes" }) |
||||
|
@Component |
||||
|
public class RedisCache |
||||
|
{ |
||||
|
@Autowired |
||||
|
public RedisTemplate redisTemplate; |
||||
|
|
||||
|
/** |
||||
|
* 缓存基本的对象,Integer、String、实体类等 |
||||
|
* |
||||
|
* @param key 缓存的键值 |
||||
|
* @param value 缓存的值 |
||||
|
*/ |
||||
|
public <T> void setCacheObject(final String key, final T value) |
||||
|
{ |
||||
|
redisTemplate.opsForValue().set(key, value); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据key获取缓存中的val+1 |
||||
|
* |
||||
|
* @param key 缓存的值 |
||||
|
* @return 数值 |
||||
|
*/ |
||||
|
public Long increment(final String key) |
||||
|
{ |
||||
|
return redisTemplate.boundValueOps(key).increment(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 缓存基本的对象,Integer、String、实体类等 |
||||
|
* |
||||
|
* @param key 缓存的键值 |
||||
|
* @param value 缓存的值 |
||||
|
* @param timeout 时间 |
||||
|
* @param timeUnit 时间颗粒度 |
||||
|
*/ |
||||
|
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) |
||||
|
{ |
||||
|
redisTemplate.opsForValue().set(key, value, timeout, timeUnit); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置有效时间 |
||||
|
* |
||||
|
* @param key Redis键 |
||||
|
* @param timeout 超时时间 |
||||
|
* @return true=设置成功;false=设置失败 |
||||
|
*/ |
||||
|
public boolean expire(final String key, final long timeout) |
||||
|
{ |
||||
|
return expire(key, timeout, TimeUnit.SECONDS); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置有效时间 |
||||
|
* |
||||
|
* @param key Redis键 |
||||
|
* @param timeout 超时时间 |
||||
|
* @param unit 时间单位 |
||||
|
* @return true=设置成功;false=设置失败 |
||||
|
*/ |
||||
|
public boolean expire(final String key, final long timeout, final TimeUnit unit) |
||||
|
{ |
||||
|
return redisTemplate.expire(key, timeout, unit); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获得缓存的基本对象。 |
||||
|
* |
||||
|
* @param key 缓存键值 |
||||
|
* @return 缓存键值对应的数据 |
||||
|
*/ |
||||
|
public <T> T getCacheObject(final String key) |
||||
|
{ |
||||
|
ValueOperations<String, T> operation = redisTemplate.opsForValue(); |
||||
|
return operation.get(key); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除单个对象 |
||||
|
* |
||||
|
* @param key |
||||
|
*/ |
||||
|
public boolean deleteObject(final String key) |
||||
|
{ |
||||
|
return redisTemplate.delete(key); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除集合对象 |
||||
|
* |
||||
|
* @param collection 多个对象 |
||||
|
* @return |
||||
|
*/ |
||||
|
public long deleteObject(final Collection collection) |
||||
|
{ |
||||
|
return redisTemplate.delete(collection); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 缓存List数据 |
||||
|
* |
||||
|
* @param key 缓存的键值 |
||||
|
* @param dataList 待缓存的List数据 |
||||
|
* @return 缓存的对象 |
||||
|
*/ |
||||
|
public <T> long setCacheList(final String key, final List<T> dataList) |
||||
|
{ |
||||
|
Long count = redisTemplate.opsForList().rightPushAll(key, dataList); |
||||
|
return count == null ? 0 : count; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获得缓存的list对象 |
||||
|
* |
||||
|
* @param key 缓存的键值 |
||||
|
* @return 缓存键值对应的数据 |
||||
|
*/ |
||||
|
public <T> List<T> getCacheList(final String key) |
||||
|
{ |
||||
|
return redisTemplate.opsForList().range(key, 0, -1); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 缓存Set |
||||
|
* |
||||
|
* @param key 缓存键值 |
||||
|
* @param dataSet 缓存的数据 |
||||
|
* @return 缓存数据的对象 |
||||
|
*/ |
||||
|
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) |
||||
|
{ |
||||
|
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); |
||||
|
Iterator<T> it = dataSet.iterator(); |
||||
|
while (it.hasNext()) |
||||
|
{ |
||||
|
setOperation.add(it.next()); |
||||
|
} |
||||
|
return setOperation; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获得缓存的set |
||||
|
* |
||||
|
* @param key |
||||
|
* @return |
||||
|
*/ |
||||
|
public <T> Set<T> getCacheSet(final String key) |
||||
|
{ |
||||
|
return redisTemplate.opsForSet().members(key); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 缓存Map |
||||
|
* |
||||
|
* @param key |
||||
|
* @param dataMap |
||||
|
*/ |
||||
|
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) |
||||
|
{ |
||||
|
if (dataMap != null) { |
||||
|
redisTemplate.opsForHash().putAll(key, dataMap); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获得缓存的Map |
||||
|
* |
||||
|
* @param key |
||||
|
* @return |
||||
|
*/ |
||||
|
public <T> Map<String, T> getCacheMap(final String key) |
||||
|
{ |
||||
|
return redisTemplate.opsForHash().entries(key); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 往Hash中存入数据 |
||||
|
* |
||||
|
* @param key Redis键 |
||||
|
* @param hKey Hash键 |
||||
|
* @param value 值 |
||||
|
*/ |
||||
|
public <T> void setCacheMapValue(final String key, final String hKey, final T value) |
||||
|
{ |
||||
|
redisTemplate.opsForHash().put(key, hKey, value); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取Hash中的数据 |
||||
|
* |
||||
|
* @param key Redis键 |
||||
|
* @param hKey Hash键 |
||||
|
* @return Hash中的对象 |
||||
|
*/ |
||||
|
public <T> T getCacheMapValue(final String key, final String hKey) |
||||
|
{ |
||||
|
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash(); |
||||
|
return opsForHash.get(key, hKey); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取多个Hash中的数据 |
||||
|
* |
||||
|
* @param key Redis键 |
||||
|
* @param hKeys Hash键集合 |
||||
|
* @return Hash对象集合 |
||||
|
*/ |
||||
|
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) |
||||
|
{ |
||||
|
return redisTemplate.opsForHash().multiGet(key, hKeys); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获得缓存的基本对象列表 |
||||
|
* |
||||
|
* @param pattern 字符串前缀 |
||||
|
* @return 对象列表 |
||||
|
*/ |
||||
|
public Collection<String> keys(final String pattern) |
||||
|
{ |
||||
|
return redisTemplate.keys(pattern); |
||||
|
} |
||||
|
|
||||
|
public boolean set(String key, Object value, long time) { |
||||
|
try { |
||||
|
if (time > 0) { |
||||
|
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); |
||||
|
} else { |
||||
|
set(key, value); |
||||
|
} |
||||
|
return true; |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public boolean set(String key, Object value) { |
||||
|
try { |
||||
|
redisTemplate.opsForValue().set(key, value); |
||||
|
return true; |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public long incr(String key, long delta) { |
||||
|
if (delta < 0) { |
||||
|
throw new RuntimeException("递增因子必须大于0"); |
||||
|
} |
||||
|
return redisTemplate.opsForValue().increment(key, delta); |
||||
|
} |
||||
|
|
||||
|
public Object get(String key) { |
||||
|
return key == null ? null : redisTemplate.opsForValue().get(key); |
||||
|
} |
||||
|
|
||||
|
public boolean hasKey(String key) { |
||||
|
try { |
||||
|
return redisTemplate.hasKey(key); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成流水号 |
||||
|
* @param prefix |
||||
|
* @return |
||||
|
*/ |
||||
|
public String generateBillNo(String prefix) { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
||||
|
String yearMonthDay = sdf.format(new Date()); |
||||
|
String codeKey = prefix+yearMonthDay; |
||||
|
Long no = 0L; |
||||
|
//获取每日流水
|
||||
|
if (hasKey(codeKey)) { |
||||
|
no = Long.valueOf(get(codeKey).toString()); |
||||
|
} |
||||
|
//新增每日流水
|
||||
|
else{ |
||||
|
//每日流水设置3天过期,避免生成过多
|
||||
|
if(!set(codeKey,0,60*60*24*3)){ |
||||
|
throw new RuntimeException("Redis新增单据编号流水失败"); |
||||
|
} |
||||
|
} |
||||
|
no = incr(codeKey, 1); |
||||
|
if (no == null) { |
||||
|
throw new RuntimeException("Redis单据编号流水递增失败"); |
||||
|
} |
||||
|
String serialNum = String.format("%03d",no); |
||||
|
return codeKey+serialNum; |
||||
|
} |
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
package com.ruoyi.framework.config; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.serializer.SerializerFeature; |
||||
|
import com.fasterxml.jackson.databind.JavaType; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import com.fasterxml.jackson.databind.type.TypeFactory; |
||||
|
import org.springframework.data.redis.serializer.RedisSerializer; |
||||
|
import org.springframework.data.redis.serializer.SerializationException; |
||||
|
import com.alibaba.fastjson.parser.ParserConfig; |
||||
|
import org.springframework.util.Assert; |
||||
|
import java.nio.charset.Charset; |
||||
|
|
||||
|
/** |
||||
|
* Redis使用FastJson序列化 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> |
||||
|
{ |
||||
|
@SuppressWarnings("unused") |
||||
|
private ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
|
||||
|
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); |
||||
|
|
||||
|
private Class<T> clazz; |
||||
|
|
||||
|
static |
||||
|
{ |
||||
|
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); |
||||
|
} |
||||
|
|
||||
|
public FastJson2JsonRedisSerializer(Class<T> clazz) |
||||
|
{ |
||||
|
super(); |
||||
|
this.clazz = clazz; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public byte[] serialize(T t) throws SerializationException |
||||
|
{ |
||||
|
if (t == null) |
||||
|
{ |
||||
|
return new byte[0]; |
||||
|
} |
||||
|
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public T deserialize(byte[] bytes) throws SerializationException |
||||
|
{ |
||||
|
if (bytes == null || bytes.length <= 0) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
String str = new String(bytes, DEFAULT_CHARSET); |
||||
|
|
||||
|
return JSON.parseObject(str, clazz); |
||||
|
} |
||||
|
|
||||
|
public void setObjectMapper(ObjectMapper objectMapper) |
||||
|
{ |
||||
|
Assert.notNull(objectMapper, "'objectMapper' must not be null"); |
||||
|
this.objectMapper = objectMapper; |
||||
|
} |
||||
|
|
||||
|
protected JavaType getJavaType(Class<?> clazz) |
||||
|
{ |
||||
|
return TypeFactory.defaultInstance().constructType(clazz); |
||||
|
} |
||||
|
} |
@ -0,0 +1,45 @@ |
|||||
|
package com.ruoyi.framework.config; |
||||
|
|
||||
|
import org.springframework.cache.annotation.CachingConfigurerSupport; |
||||
|
import org.springframework.cache.annotation.EnableCaching; |
||||
|
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.StringRedisSerializer; |
||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect; |
||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; |
||||
|
|
||||
|
/** |
||||
|
* redis配置 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
@Configuration |
||||
|
@EnableCaching |
||||
|
public class RedisConfig extends CachingConfigurerSupport |
||||
|
{ |
||||
|
@Bean |
||||
|
@SuppressWarnings(value = { "unchecked", "rawtypes" }) |
||||
|
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) |
||||
|
{ |
||||
|
RedisTemplate<Object, Object> template = new RedisTemplate<>(); |
||||
|
template.setConnectionFactory(connectionFactory); |
||||
|
|
||||
|
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); |
||||
|
|
||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||
|
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); |
||||
|
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); |
||||
|
serializer.setObjectMapper(mapper); |
||||
|
|
||||
|
template.setValueSerializer(serializer); |
||||
|
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||
|
template.setKeySerializer(new StringRedisSerializer()); |
||||
|
template.afterPropertiesSet(); |
||||
|
return template; |
||||
|
} |
||||
|
} |
@ -1,62 +0,0 @@ |
|||||
package com.ruoyi.framework.shiro.service; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import org.apache.shiro.session.Session; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
import com.ruoyi.common.utils.StringUtils; |
|
||||
import com.ruoyi.framework.shiro.session.OnlineSession; |
|
||||
import com.ruoyi.system.domain.SysUserOnline; |
|
||||
import com.ruoyi.system.service.ISysUserOnlineService; |
|
||||
|
|
||||
/** |
|
||||
* 会话db操作处理 |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
@Component |
|
||||
public class SysShiroService |
|
||||
{ |
|
||||
@Autowired |
|
||||
private ISysUserOnlineService onlineService; |
|
||||
|
|
||||
/** |
|
||||
* 删除会话 |
|
||||
* |
|
||||
* @param onlineSession 会话信息 |
|
||||
*/ |
|
||||
public void deleteSession(OnlineSession onlineSession) |
|
||||
{ |
|
||||
onlineService.deleteOnlineById(String.valueOf(onlineSession.getId())); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取会话信息 |
|
||||
* |
|
||||
* @param sessionId |
|
||||
* @return |
|
||||
*/ |
|
||||
public Session getSession(Serializable sessionId) |
|
||||
{ |
|
||||
SysUserOnline userOnline = onlineService.selectOnlineById(String.valueOf(sessionId)); |
|
||||
return StringUtils.isNull(userOnline) ? null : createSession(userOnline); |
|
||||
} |
|
||||
|
|
||||
public Session createSession(SysUserOnline userOnline) |
|
||||
{ |
|
||||
OnlineSession onlineSession = new OnlineSession(); |
|
||||
if (StringUtils.isNotNull(userOnline)) |
|
||||
{ |
|
||||
onlineSession.setId(userOnline.getSessionId()); |
|
||||
onlineSession.setHost(userOnline.getIpaddr()); |
|
||||
onlineSession.setBrowser(userOnline.getBrowser()); |
|
||||
onlineSession.setOs(userOnline.getOs()); |
|
||||
onlineSession.setDeptName(userOnline.getDeptName()); |
|
||||
onlineSession.setLoginName(userOnline.getLoginName()); |
|
||||
onlineSession.setStartTimestamp(userOnline.getStartTimestamp()); |
|
||||
onlineSession.setLastAccessTime(userOnline.getLastAccessTime()); |
|
||||
onlineSession.setTimeout(userOnline.getExpireTime()); |
|
||||
} |
|
||||
return onlineSession; |
|
||||
} |
|
||||
} |
|
@ -1,117 +0,0 @@ |
|||||
package com.ruoyi.framework.shiro.session; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.util.Date; |
|
||||
import org.apache.shiro.session.Session; |
|
||||
import org.apache.shiro.session.UnknownSessionException; |
|
||||
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.beans.factory.annotation.Value; |
|
||||
import com.ruoyi.common.enums.OnlineStatus; |
|
||||
import com.ruoyi.framework.manager.AsyncManager; |
|
||||
import com.ruoyi.framework.manager.factory.AsyncFactory; |
|
||||
import com.ruoyi.framework.shiro.service.SysShiroService; |
|
||||
|
|
||||
/** |
|
||||
* 针对自定义的ShiroSession的db操作 |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
public class OnlineSessionDAO extends EnterpriseCacheSessionDAO |
|
||||
{ |
|
||||
/** |
|
||||
* 同步session到数据库的周期 单位为毫秒(默认1分钟) |
|
||||
*/ |
|
||||
@Value("${shiro.session.dbSyncPeriod}") |
|
||||
private int dbSyncPeriod; |
|
||||
|
|
||||
/** |
|
||||
* 上次同步数据库的时间戳 |
|
||||
*/ |
|
||||
private static final String LAST_SYNC_DB_TIMESTAMP = OnlineSessionDAO.class.getName() + "LAST_SYNC_DB_TIMESTAMP"; |
|
||||
|
|
||||
@Autowired |
|
||||
private SysShiroService sysShiroService; |
|
||||
|
|
||||
public OnlineSessionDAO() |
|
||||
{ |
|
||||
super(); |
|
||||
} |
|
||||
|
|
||||
public OnlineSessionDAO(long expireTime) |
|
||||
{ |
|
||||
super(); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 根据会话ID获取会话 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
* @return ShiroSession |
|
||||
*/ |
|
||||
@Override |
|
||||
protected Session doReadSession(Serializable sessionId) |
|
||||
{ |
|
||||
return sysShiroService.getSession(sessionId); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void update(Session session) throws UnknownSessionException |
|
||||
{ |
|
||||
super.update(session); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用 |
|
||||
*/ |
|
||||
public void syncToDb(OnlineSession onlineSession) |
|
||||
{ |
|
||||
Date lastSyncTimestamp = (Date) onlineSession.getAttribute(LAST_SYNC_DB_TIMESTAMP); |
|
||||
if (lastSyncTimestamp != null) |
|
||||
{ |
|
||||
boolean needSync = true; |
|
||||
long deltaTime = onlineSession.getLastAccessTime().getTime() - lastSyncTimestamp.getTime(); |
|
||||
if (deltaTime < dbSyncPeriod * 60 * 1000) |
|
||||
{ |
|
||||
// 时间差不足 无需同步
|
|
||||
needSync = false; |
|
||||
} |
|
||||
// isGuest = true 访客
|
|
||||
boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L; |
|
||||
|
|
||||
// session 数据变更了 同步
|
|
||||
if (!isGuest && onlineSession.isAttributeChanged()) |
|
||||
{ |
|
||||
needSync = true; |
|
||||
} |
|
||||
|
|
||||
if (!needSync) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
// 更新上次同步数据库时间
|
|
||||
onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime()); |
|
||||
// 更新完后 重置标识
|
|
||||
if (onlineSession.isAttributeChanged()) |
|
||||
{ |
|
||||
onlineSession.resetAttributeChanged(); |
|
||||
} |
|
||||
AsyncManager.me().execute(AsyncFactory.syncSessionToDb(onlineSession)); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 当会话过期/停止(如用户退出时)属性等会调用 |
|
||||
*/ |
|
||||
@Override |
|
||||
protected void doDelete(Session session) |
|
||||
{ |
|
||||
OnlineSession onlineSession = (OnlineSession) session; |
|
||||
if (null == onlineSession) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
onlineSession.setStatus(OnlineStatus.off_line); |
|
||||
sysShiroService.deleteSession(onlineSession); |
|
||||
} |
|
||||
} |
|
@ -1,99 +0,0 @@ |
|||||
package com.ruoyi.framework.shiro.web.filter.online; |
|
||||
|
|
||||
import java.io.IOException; |
|
||||
import javax.servlet.ServletRequest; |
|
||||
import javax.servlet.ServletResponse; |
|
||||
import org.apache.shiro.session.Session; |
|
||||
import org.apache.shiro.subject.Subject; |
|
||||
import org.apache.shiro.web.filter.AccessControlFilter; |
|
||||
import org.apache.shiro.web.util.WebUtils; |
|
||||
import org.springframework.beans.factory.annotation.Value; |
|
||||
import com.ruoyi.common.constant.ShiroConstants; |
|
||||
import com.ruoyi.common.core.domain.entity.SysUser; |
|
||||
import com.ruoyi.common.enums.OnlineStatus; |
|
||||
import com.ruoyi.common.utils.ShiroUtils; |
|
||||
import com.ruoyi.framework.shiro.session.OnlineSession; |
|
||||
import com.ruoyi.framework.shiro.session.OnlineSessionDAO; |
|
||||
|
|
||||
/** |
|
||||
* 自定义访问控制 |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
public class OnlineSessionFilter extends AccessControlFilter |
|
||||
{ |
|
||||
/** |
|
||||
* 强制退出后重定向的地址 |
|
||||
*/ |
|
||||
@Value("${shiro.user.loginUrl}") |
|
||||
private String loginUrl; |
|
||||
|
|
||||
private OnlineSessionDAO onlineSessionDAO; |
|
||||
|
|
||||
/** |
|
||||
* 表示是否允许访问;mappedValue就是[urls]配置中拦截器参数部分,如果允许访问返回true,否则false; |
|
||||
*/ |
|
||||
@Override |
|
||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) |
|
||||
throws Exception |
|
||||
{ |
|
||||
Subject subject = getSubject(request, response); |
|
||||
if (subject == null || subject.getSession() == null) |
|
||||
{ |
|
||||
return true; |
|
||||
} |
|
||||
Session session = onlineSessionDAO.readSession(subject.getSession().getId()); |
|
||||
if (session != null && session instanceof OnlineSession) |
|
||||
{ |
|
||||
OnlineSession onlineSession = (OnlineSession) session; |
|
||||
request.setAttribute(ShiroConstants.ONLINE_SESSION, onlineSession); |
|
||||
// 把user对象设置进去
|
|
||||
boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L; |
|
||||
if (isGuest == true) |
|
||||
{ |
|
||||
SysUser user = ShiroUtils.getSysUser(); |
|
||||
if (user != null) |
|
||||
{ |
|
||||
onlineSession.setUserId(user.getUserId()); |
|
||||
onlineSession.setLoginName(user.getLoginName()); |
|
||||
onlineSession.setAvatar(user.getAvatar()); |
|
||||
onlineSession.setDeptName(user.getDept().getDeptName()); |
|
||||
onlineSession.markAttributeChanged(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (onlineSession.getStatus() == OnlineStatus.off_line) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。 |
|
||||
*/ |
|
||||
@Override |
|
||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception |
|
||||
{ |
|
||||
Subject subject = getSubject(request, response); |
|
||||
if (subject != null) |
|
||||
{ |
|
||||
subject.logout(); |
|
||||
} |
|
||||
saveRequestAndRedirectToLogin(request, response); |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
// 跳转到登录页
|
|
||||
@Override |
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException |
|
||||
{ |
|
||||
WebUtils.issueRedirect(request, response, loginUrl); |
|
||||
} |
|
||||
|
|
||||
public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO) |
|
||||
{ |
|
||||
this.onlineSessionDAO = onlineSessionDAO; |
|
||||
} |
|
||||
} |
|
@ -1,39 +0,0 @@ |
|||||
package com.ruoyi.framework.shiro.web.filter.sync; |
|
||||
|
|
||||
import javax.servlet.ServletRequest; |
|
||||
import javax.servlet.ServletResponse; |
|
||||
import org.apache.shiro.web.filter.PathMatchingFilter; |
|
||||
import com.ruoyi.common.constant.ShiroConstants; |
|
||||
import com.ruoyi.framework.shiro.session.OnlineSession; |
|
||||
import com.ruoyi.framework.shiro.session.OnlineSessionDAO; |
|
||||
|
|
||||
/** |
|
||||
* 同步Session数据到Db |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
public class SyncOnlineSessionFilter extends PathMatchingFilter |
|
||||
{ |
|
||||
private OnlineSessionDAO onlineSessionDAO; |
|
||||
|
|
||||
/** |
|
||||
* 同步会话数据到DB 一次请求最多同步一次 防止过多处理 需要放到Shiro过滤器之前 |
|
||||
*/ |
|
||||
@Override |
|
||||
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception |
|
||||
{ |
|
||||
OnlineSession session = (OnlineSession) request.getAttribute(ShiroConstants.ONLINE_SESSION); |
|
||||
// 如果session stop了 也不同步
|
|
||||
// session停止时间,如果stopTimestamp不为null,则代表已停止
|
|
||||
if (session != null && session.getUserId() != null && session.getStopTimestamp() == null) |
|
||||
{ |
|
||||
onlineSessionDAO.syncToDb(session); |
|
||||
} |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO) |
|
||||
{ |
|
||||
this.onlineSessionDAO = onlineSessionDAO; |
|
||||
} |
|
||||
} |
|
@ -1,175 +0,0 @@ |
|||||
package com.ruoyi.framework.shiro.web.session; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.Collection; |
|
||||
import java.util.Date; |
|
||||
import java.util.List; |
|
||||
import org.apache.commons.lang3.time.DateUtils; |
|
||||
import org.apache.shiro.session.ExpiredSessionException; |
|
||||
import org.apache.shiro.session.InvalidSessionException; |
|
||||
import org.apache.shiro.session.Session; |
|
||||
import org.apache.shiro.session.mgt.DefaultSessionKey; |
|
||||
import org.apache.shiro.session.mgt.SessionKey; |
|
||||
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; |
|
||||
import org.slf4j.Logger; |
|
||||
import org.slf4j.LoggerFactory; |
|
||||
import com.ruoyi.common.constant.ShiroConstants; |
|
||||
import com.ruoyi.common.utils.StringUtils; |
|
||||
import com.ruoyi.common.utils.bean.BeanUtils; |
|
||||
import com.ruoyi.common.utils.spring.SpringUtils; |
|
||||
import com.ruoyi.framework.shiro.session.OnlineSession; |
|
||||
import com.ruoyi.system.domain.SysUserOnline; |
|
||||
import com.ruoyi.system.service.ISysUserOnlineService; |
|
||||
|
|
||||
/** |
|
||||
* 主要是在此如果会话的属性修改了 就标识下其修改了 然后方便 OnlineSessionDao同步 |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
public class OnlineWebSessionManager extends DefaultWebSessionManager |
|
||||
{ |
|
||||
private static final Logger log = LoggerFactory.getLogger(OnlineWebSessionManager.class); |
|
||||
|
|
||||
@Override |
|
||||
public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) throws InvalidSessionException |
|
||||
{ |
|
||||
super.setAttribute(sessionKey, attributeKey, value); |
|
||||
if (value != null && needMarkAttributeChanged(attributeKey)) |
|
||||
{ |
|
||||
OnlineSession session = getOnlineSession(sessionKey); |
|
||||
session.markAttributeChanged(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private boolean needMarkAttributeChanged(Object attributeKey) |
|
||||
{ |
|
||||
if (attributeKey == null) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
String attributeKeyStr = attributeKey.toString(); |
|
||||
// 优化 flash属性没必要持久化
|
|
||||
if (attributeKeyStr.startsWith("org.springframework")) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
if (attributeKeyStr.startsWith("javax.servlet")) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
if (attributeKeyStr.equals(ShiroConstants.CURRENT_USERNAME)) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Object removeAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException |
|
||||
{ |
|
||||
Object removed = super.removeAttribute(sessionKey, attributeKey); |
|
||||
if (removed != null) |
|
||||
{ |
|
||||
OnlineSession s = getOnlineSession(sessionKey); |
|
||||
s.markAttributeChanged(); |
|
||||
} |
|
||||
|
|
||||
return removed; |
|
||||
} |
|
||||
|
|
||||
public OnlineSession getOnlineSession(SessionKey sessionKey) |
|
||||
{ |
|
||||
OnlineSession session = null; |
|
||||
Object obj = doGetSession(sessionKey); |
|
||||
if (StringUtils.isNotNull(obj)) |
|
||||
{ |
|
||||
session = new OnlineSession(); |
|
||||
BeanUtils.copyBeanProp(session, obj); |
|
||||
} |
|
||||
return session; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 验证session是否有效 用于删除过期session |
|
||||
*/ |
|
||||
@Override |
|
||||
public void validateSessions() |
|
||||
{ |
|
||||
if (log.isInfoEnabled()) |
|
||||
{ |
|
||||
log.info("invalidation sessions..."); |
|
||||
} |
|
||||
|
|
||||
int invalidCount = 0; |
|
||||
|
|
||||
int timeout = (int) this.getGlobalSessionTimeout(); |
|
||||
if (timeout < 0) |
|
||||
{ |
|
||||
// 永不过期不进行处理
|
|
||||
return; |
|
||||
} |
|
||||
Date expiredDate = DateUtils.addMilliseconds(new Date(), 0 - timeout); |
|
||||
ISysUserOnlineService userOnlineService = SpringUtils.getBean(ISysUserOnlineService.class); |
|
||||
List<SysUserOnline> userOnlineList = userOnlineService.selectOnlineByExpired(expiredDate); |
|
||||
// 批量过期删除
|
|
||||
List<String> needOfflineIdList = new ArrayList<String>(); |
|
||||
for (SysUserOnline userOnline : userOnlineList) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
SessionKey key = new DefaultSessionKey(userOnline.getSessionId()); |
|
||||
Session session = retrieveSession(key); |
|
||||
if (session != null) |
|
||||
{ |
|
||||
throw new InvalidSessionException(); |
|
||||
} |
|
||||
} |
|
||||
catch (InvalidSessionException e) |
|
||||
{ |
|
||||
if (log.isDebugEnabled()) |
|
||||
{ |
|
||||
boolean expired = (e instanceof ExpiredSessionException); |
|
||||
String msg = "Invalidated session with id [" + userOnline.getSessionId() + "]" |
|
||||
+ (expired ? " (expired)" : " (stopped)"); |
|
||||
log.debug(msg); |
|
||||
} |
|
||||
invalidCount++; |
|
||||
needOfflineIdList.add(userOnline.getSessionId()); |
|
||||
userOnlineService.removeUserCache(userOnline.getLoginName(), userOnline.getSessionId()); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
if (needOfflineIdList.size() > 0) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
userOnlineService.batchDeleteOnline(needOfflineIdList); |
|
||||
} |
|
||||
catch (Exception e) |
|
||||
{ |
|
||||
log.error("batch delete db session error.", e); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (log.isInfoEnabled()) |
|
||||
{ |
|
||||
String msg = "Finished invalidation session."; |
|
||||
if (invalidCount > 0) |
|
||||
{ |
|
||||
msg += " [" + invalidCount + "] sessions were stopped."; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
msg += " No sessions were stopped."; |
|
||||
} |
|
||||
log.info(msg); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
protected Collection<Session> getActiveSessions() |
|
||||
{ |
|
||||
throw new UnsupportedOperationException("getActiveSessions method not supported"); |
|
||||
} |
|
||||
} |
|
@ -1,131 +0,0 @@ |
|||||
package com.ruoyi.framework.shiro.web.session; |
|
||||
|
|
||||
import java.util.concurrent.ScheduledExecutorService; |
|
||||
import java.util.concurrent.TimeUnit; |
|
||||
import org.apache.shiro.session.mgt.DefaultSessionManager; |
|
||||
import org.apache.shiro.session.mgt.SessionValidationScheduler; |
|
||||
import org.apache.shiro.session.mgt.ValidatingSessionManager; |
|
||||
import org.slf4j.Logger; |
|
||||
import org.slf4j.LoggerFactory; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.beans.factory.annotation.Qualifier; |
|
||||
import org.springframework.beans.factory.annotation.Value; |
|
||||
import org.springframework.context.annotation.Lazy; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
import com.ruoyi.common.utils.Threads; |
|
||||
|
|
||||
/** |
|
||||
* 自定义任务调度器完成 |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
@Component |
|
||||
public class SpringSessionValidationScheduler implements SessionValidationScheduler |
|
||||
{ |
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringSessionValidationScheduler.class); |
|
||||
|
|
||||
public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL; |
|
||||
|
|
||||
/** |
|
||||
* 定时器,用于处理超时的挂起请求,也用于连接断开时的重连。 |
|
||||
*/ |
|
||||
@Autowired |
|
||||
@Qualifier("scheduledExecutorService") |
|
||||
private ScheduledExecutorService executorService; |
|
||||
|
|
||||
private volatile boolean enabled = false; |
|
||||
|
|
||||
/** |
|
||||
* 会话验证管理器 |
|
||||
*/ |
|
||||
@Autowired |
|
||||
@Qualifier("sessionManager") |
|
||||
@Lazy |
|
||||
private ValidatingSessionManager sessionManager; |
|
||||
|
|
||||
// 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟
|
|
||||
@Value("${shiro.session.validationInterval}") |
|
||||
private long sessionValidationInterval; |
|
||||
|
|
||||
@Override |
|
||||
public boolean isEnabled() |
|
||||
{ |
|
||||
return this.enabled; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Specifies how frequently (in milliseconds) this Scheduler will call the |
|
||||
* {@link org.apache.shiro.session.mgt.ValidatingSessionManager#validateSessions() |
|
||||
* ValidatingSessionManager#validateSessions()} method. |
|
||||
* |
|
||||
* <p> |
|
||||
* Unless this method is called, the default value is {@link #DEFAULT_SESSION_VALIDATION_INTERVAL}. |
|
||||
* |
|
||||
* @param sessionValidationInterval |
|
||||
*/ |
|
||||
public void setSessionValidationInterval(long sessionValidationInterval) |
|
||||
{ |
|
||||
this.sessionValidationInterval = sessionValidationInterval; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Starts session validation by creating a spring PeriodicTrigger. |
|
||||
*/ |
|
||||
@Override |
|
||||
public void enableSessionValidation() |
|
||||
{ |
|
||||
|
|
||||
enabled = true; |
|
||||
|
|
||||
if (log.isDebugEnabled()) |
|
||||
{ |
|
||||
log.debug("Scheduling session validation job using Spring Scheduler with " |
|
||||
+ "session validation interval of [" + sessionValidationInterval + "]ms..."); |
|
||||
} |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
executorService.scheduleAtFixedRate(new Runnable() |
|
||||
{ |
|
||||
@Override |
|
||||
public void run() |
|
||||
{ |
|
||||
if (enabled) |
|
||||
{ |
|
||||
sessionManager.validateSessions(); |
|
||||
} |
|
||||
} |
|
||||
}, 1000, sessionValidationInterval * 60 * 1000, TimeUnit.MILLISECONDS); |
|
||||
|
|
||||
this.enabled = true; |
|
||||
|
|
||||
if (log.isDebugEnabled()) |
|
||||
{ |
|
||||
log.debug("Session validation job successfully scheduled with Spring Scheduler."); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
catch (Exception e) |
|
||||
{ |
|
||||
if (log.isErrorEnabled()) |
|
||||
{ |
|
||||
log.error("Error starting the Spring Scheduler session validation job. Session validation may not occur.", e); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void disableSessionValidation() |
|
||||
{ |
|
||||
if (log.isDebugEnabled()) |
|
||||
{ |
|
||||
log.debug("Stopping Spring Scheduler session validation job..."); |
|
||||
} |
|
||||
|
|
||||
if (this.enabled) |
|
||||
{ |
|
||||
Threads.shutdownAndAwaitTermination(executorService); |
|
||||
} |
|
||||
this.enabled = false; |
|
||||
} |
|
||||
} |
|
@ -1,52 +0,0 @@ |
|||||
package com.ruoyi.system.mapper; |
|
||||
|
|
||||
import java.util.List; |
|
||||
import com.ruoyi.system.domain.SysUserOnline; |
|
||||
|
|
||||
/** |
|
||||
* 在线用户 数据层 |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
public interface SysUserOnlineMapper |
|
||||
{ |
|
||||
/** |
|
||||
* 通过会话序号查询信息 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
* @return 在线用户信息 |
|
||||
*/ |
|
||||
public SysUserOnline selectOnlineById(String sessionId); |
|
||||
|
|
||||
/** |
|
||||
* 通过会话序号删除信息 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
* @return 在线用户信息 |
|
||||
*/ |
|
||||
public int deleteOnlineById(String sessionId); |
|
||||
|
|
||||
/** |
|
||||
* 保存会话信息 |
|
||||
* |
|
||||
* @param online 会话信息 |
|
||||
* @return 结果 |
|
||||
*/ |
|
||||
public int saveOnline(SysUserOnline online); |
|
||||
|
|
||||
/** |
|
||||
* 查询会话集合 |
|
||||
* |
|
||||
* @param userOnline 会话参数 |
|
||||
* @return 会话集合 |
|
||||
*/ |
|
||||
public List<SysUserOnline> selectUserOnlineList(SysUserOnline userOnline); |
|
||||
|
|
||||
/** |
|
||||
* 查询过期会话集合 |
|
||||
* |
|
||||
* @param lastAccessTime 过期时间 |
|
||||
* @return 会话集合 |
|
||||
*/ |
|
||||
public List<SysUserOnline> selectOnlineByExpired(String lastAccessTime); |
|
||||
} |
|
@ -1,75 +0,0 @@ |
|||||
package com.ruoyi.system.service; |
|
||||
|
|
||||
import java.util.Date; |
|
||||
import java.util.List; |
|
||||
import com.ruoyi.system.domain.SysUserOnline; |
|
||||
|
|
||||
/** |
|
||||
* 在线用户 服务层 |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
public interface ISysUserOnlineService |
|
||||
{ |
|
||||
/** |
|
||||
* 通过会话序号查询信息 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
* @return 在线用户信息 |
|
||||
*/ |
|
||||
public SysUserOnline selectOnlineById(String sessionId); |
|
||||
|
|
||||
/** |
|
||||
* 通过会话序号删除信息 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
* @return 在线用户信息 |
|
||||
*/ |
|
||||
public void deleteOnlineById(String sessionId); |
|
||||
|
|
||||
/** |
|
||||
* 通过会话序号删除信息 |
|
||||
* |
|
||||
* @param sessions 会话ID集合 |
|
||||
* @return 在线用户信息 |
|
||||
*/ |
|
||||
public void batchDeleteOnline(List<String> sessions); |
|
||||
|
|
||||
/** |
|
||||
* 保存会话信息 |
|
||||
* |
|
||||
* @param online 会话信息 |
|
||||
*/ |
|
||||
public void saveOnline(SysUserOnline online); |
|
||||
|
|
||||
/** |
|
||||
* 查询会话集合 |
|
||||
* |
|
||||
* @param userOnline 分页参数 |
|
||||
* @return 会话集合 |
|
||||
*/ |
|
||||
public List<SysUserOnline> selectUserOnlineList(SysUserOnline userOnline); |
|
||||
|
|
||||
/** |
|
||||
* 强退用户 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
*/ |
|
||||
public void forceLogout(String sessionId); |
|
||||
|
|
||||
/** |
|
||||
* 清理用户缓存 |
|
||||
* |
|
||||
* @param loginName 登录名称 |
|
||||
* @param sessionId 会话ID |
|
||||
*/ |
|
||||
public void removeUserCache(String loginName, String sessionId); |
|
||||
|
|
||||
/** |
|
||||
* 查询会话集合 |
|
||||
* |
|
||||
* @param expiredDate 有效期 |
|
||||
* @return 会话集合 |
|
||||
*/ |
|
||||
public List<SysUserOnline> selectOnlineByExpired(Date expiredDate); |
|
||||
} |
|
@ -1,141 +0,0 @@ |
|||||
package com.ruoyi.system.service.impl; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.util.Date; |
|
||||
import java.util.Deque; |
|
||||
import java.util.List; |
|
||||
import org.apache.shiro.cache.Cache; |
|
||||
import org.apache.shiro.cache.ehcache.EhCacheManager; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.stereotype.Service; |
|
||||
import com.ruoyi.common.constant.ShiroConstants; |
|
||||
import com.ruoyi.common.utils.DateUtils; |
|
||||
import com.ruoyi.common.utils.StringUtils; |
|
||||
import com.ruoyi.system.domain.SysUserOnline; |
|
||||
import com.ruoyi.system.mapper.SysUserOnlineMapper; |
|
||||
import com.ruoyi.system.service.ISysUserOnlineService; |
|
||||
|
|
||||
/** |
|
||||
* 在线用户 服务层处理 |
|
||||
* |
|
||||
* @author ruoyi |
|
||||
*/ |
|
||||
@Service |
|
||||
public class SysUserOnlineServiceImpl implements ISysUserOnlineService |
|
||||
{ |
|
||||
@Autowired |
|
||||
private SysUserOnlineMapper userOnlineDao; |
|
||||
|
|
||||
@Autowired |
|
||||
private EhCacheManager ehCacheManager; |
|
||||
|
|
||||
/** |
|
||||
* 通过会话序号查询信息 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
* @return 在线用户信息 |
|
||||
*/ |
|
||||
@Override |
|
||||
public SysUserOnline selectOnlineById(String sessionId) |
|
||||
{ |
|
||||
return userOnlineDao.selectOnlineById(sessionId); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 通过会话序号删除信息 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
* @return 在线用户信息 |
|
||||
*/ |
|
||||
@Override |
|
||||
public void deleteOnlineById(String sessionId) |
|
||||
{ |
|
||||
SysUserOnline userOnline = selectOnlineById(sessionId); |
|
||||
if (StringUtils.isNotNull(userOnline)) |
|
||||
{ |
|
||||
userOnlineDao.deleteOnlineById(sessionId); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 通过会话序号删除信息 |
|
||||
* |
|
||||
* @param sessions 会话ID集合 |
|
||||
* @return 在线用户信息 |
|
||||
*/ |
|
||||
@Override |
|
||||
public void batchDeleteOnline(List<String> sessions) |
|
||||
{ |
|
||||
for (String sessionId : sessions) |
|
||||
{ |
|
||||
SysUserOnline userOnline = selectOnlineById(sessionId); |
|
||||
if (StringUtils.isNotNull(userOnline)) |
|
||||
{ |
|
||||
userOnlineDao.deleteOnlineById(sessionId); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 保存会话信息 |
|
||||
* |
|
||||
* @param online 会话信息 |
|
||||
*/ |
|
||||
@Override |
|
||||
public void saveOnline(SysUserOnline online) |
|
||||
{ |
|
||||
userOnlineDao.saveOnline(online); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 查询会话集合 |
|
||||
* |
|
||||
* @param userOnline 在线用户 |
|
||||
*/ |
|
||||
@Override |
|
||||
public List<SysUserOnline> selectUserOnlineList(SysUserOnline userOnline) |
|
||||
{ |
|
||||
return userOnlineDao.selectUserOnlineList(userOnline); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 强退用户 |
|
||||
* |
|
||||
* @param sessionId 会话ID |
|
||||
*/ |
|
||||
@Override |
|
||||
public void forceLogout(String sessionId) |
|
||||
{ |
|
||||
userOnlineDao.deleteOnlineById(sessionId); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 清理用户缓存 |
|
||||
* |
|
||||
* @param loginName 登录名称 |
|
||||
* @param sessionId 会话ID |
|
||||
*/ |
|
||||
@Override |
|
||||
public void removeUserCache(String loginName, String sessionId) |
|
||||
{ |
|
||||
Cache<String, Deque<Serializable>> cache = ehCacheManager.getCache(ShiroConstants.SYS_USERCACHE); |
|
||||
Deque<Serializable> deque = cache.get(loginName); |
|
||||
if (StringUtils.isEmpty(deque) || deque.size() == 0) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
deque.remove(sessionId); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 查询会话集合 |
|
||||
* |
|
||||
* @param expiredDate 失效日期 |
|
||||
*/ |
|
||||
@Override |
|
||||
public List<SysUserOnline> selectOnlineByExpired(Date expiredDate) |
|
||||
{ |
|
||||
String lastAccessTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, expiredDate); |
|
||||
return userOnlineDao.selectOnlineByExpired(lastAccessTime); |
|
||||
} |
|
||||
} |
|
@ -1,57 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8" ?> |
|
||||
<!DOCTYPE mapper |
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|
||||
<mapper namespace="com.ruoyi.system.mapper.SysUserOnlineMapper"> |
|
||||
|
|
||||
<resultMap type="SysUserOnline" id="SysUserOnlineResult"> |
|
||||
<id property="sessionId" column="sessionId" /> |
|
||||
<result property="loginName" column="login_name" /> |
|
||||
<result property="deptName" column="dept_name" /> |
|
||||
<result property="ipaddr" column="ipaddr" /> |
|
||||
<result property="loginLocation" column="login_location" /> |
|
||||
<result property="browser" column="browser" /> |
|
||||
<result property="os" column="os" /> |
|
||||
<result property="status" column="status" /> |
|
||||
<result property="startTimestamp" column="start_timestamp" /> |
|
||||
<result property="lastAccessTime" column="last_access_time" /> |
|
||||
<result property="expireTime" column="expire_time" /> |
|
||||
</resultMap> |
|
||||
|
|
||||
<sql id="selectOnlineVo"> |
|
||||
select sessionId, login_name, dept_name, ipaddr, login_location, browser, os, status, start_timestamp, last_access_time, expire_time |
|
||||
from sys_user_online |
|
||||
</sql> |
|
||||
|
|
||||
<select id="selectOnlineById" parameterType="String" resultMap="SysUserOnlineResult"> |
|
||||
<include refid="selectOnlineVo"/> |
|
||||
where sessionId = #{sessionId} |
|
||||
</select> |
|
||||
|
|
||||
<insert id="saveOnline" parameterType="SysUserOnline"> |
|
||||
replace into sys_user_online(sessionId, login_name, dept_name, ipaddr, login_location, browser, os, status, start_timestamp, last_access_time, expire_time) |
|
||||
values (#{sessionId}, #{loginName}, #{deptName}, #{ipaddr}, #{loginLocation}, #{browser}, #{os}, #{status}, #{startTimestamp}, #{lastAccessTime}, #{expireTime}) |
|
||||
</insert> |
|
||||
|
|
||||
<delete id="deleteOnlineById" parameterType="String"> |
|
||||
delete from sys_user_online where sessionId = #{sessionId} |
|
||||
</delete> |
|
||||
|
|
||||
<select id="selectUserOnlineList" parameterType="SysUserOnline" resultMap="SysUserOnlineResult"> |
|
||||
<include refid="selectOnlineVo"/> |
|
||||
<where> |
|
||||
<if test="ipaddr != null and ipaddr != ''"> |
|
||||
AND ipaddr like concat('%', #{ipaddr}, '%') |
|
||||
</if> |
|
||||
<if test="loginName != null and loginName != ''"> |
|
||||
AND login_name like concat('%', #{loginName}, '%') |
|
||||
</if> |
|
||||
</where> |
|
||||
</select> |
|
||||
|
|
||||
<select id="selectOnlineByExpired" parameterType="String" resultMap="SysUserOnlineResult"> |
|
||||
<include refid="selectOnlineVo"/> o |
|
||||
WHERE o.last_access_time <![CDATA[ <= ]]> #{lastAccessTime} ORDER BY o.last_access_time ASC |
|
||||
</select> |
|
||||
|
|
||||
</mapper> |
|
Loading…
Reference in new issue