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