From 75f65b3f9c844a446be082a1f4988fb7ae9aecd6 Mon Sep 17 00:00:00 2001 From: RuoYi Date: Sat, 24 Feb 2018 17:46:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BC=9A=E8=AF=9D=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ll_20180223.sql => new_intall_20180224.sql | 25 ++ .../ruoyi/framework/config/ShiroConfig.java | 53 +++- .../ruoyi/project/shiro/ShiroConstants.java | 10 + .../project/shiro/realm/LoginService.java | 2 +- .../shiro/session/OnlineSessionDAO.java | 194 ++++++++++++ .../shiro/session/OnlineSessionFactory.java | 40 +++ .../system/online/dao/IUserOnlineDao.java | 29 ++ .../system/online/dao/UserOnlineDaoImpl.java | 42 +++ .../system/online/domain/OnlineSession.java | 280 ++++++++++++++++++ .../system/online/domain/UserOnline.java | 175 +++++++++++ .../online/service/IUserOnlineService.java | 29 ++ .../online/service/UserOnlineServiceImpl.java | 49 +++ .../project/system/user/dao/IUserDao.java | 2 +- .../project/system/user/dao/UserDaoImpl.java | 4 +- .../system/user/service/IUserService.java | 2 +- .../system/user/service/UserServiceImpl.java | 4 +- .../mybatis/system/SystemOnlineMapper.xml | 46 +++ .../mybatis/system/SystemUserMapper.xml | 2 +- 18 files changed, 971 insertions(+), 17 deletions(-) rename new_intall_20180223.sql => new_intall_20180224.sql (89%) create mode 100644 src/main/java/com/ruoyi/project/shiro/session/OnlineSessionDAO.java create mode 100644 src/main/java/com/ruoyi/project/shiro/session/OnlineSessionFactory.java create mode 100644 src/main/java/com/ruoyi/project/system/online/dao/IUserOnlineDao.java create mode 100644 src/main/java/com/ruoyi/project/system/online/dao/UserOnlineDaoImpl.java create mode 100644 src/main/java/com/ruoyi/project/system/online/domain/OnlineSession.java create mode 100644 src/main/java/com/ruoyi/project/system/online/domain/UserOnline.java create mode 100644 src/main/java/com/ruoyi/project/system/online/service/IUserOnlineService.java create mode 100644 src/main/java/com/ruoyi/project/system/online/service/UserOnlineServiceImpl.java create mode 100644 src/main/resources/mybatis/system/SystemOnlineMapper.xml diff --git a/new_intall_20180223.sql b/new_intall_20180224.sql similarity index 89% rename from new_intall_20180223.sql rename to new_intall_20180224.sql index 4ec65ad7d..2664c2cb5 100644 --- a/new_intall_20180223.sql +++ b/new_intall_20180224.sql @@ -247,6 +247,28 @@ create table sys_logininfor ( insert into sys_logininfor values(1, 'admin', 0 , '127.0.0.1', 'Chrome 45', 'Windows 7', '登录成功' ,'2018-01-01'); +-- ---------------------------- +-- 10、在线用户 +-- ---------------------------- +drop table if exists sys_user_online; +create table sys_user_online ( + sessionId varchar(100) default '' comment '用户会话id', + user_id int(11) default 0 comment '用户ID', + login_name varchar(50) default '' comment '登录名', + ipaddr varchar(50) default '' comment '登录IP地址', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + status varchar(10) default '' comment '在线状态', + start_timestsamp timestamp default current_timestamp comment 'session创建时间', + last_access_time timestamp default current_timestamp comment 'session最后访问时间', + timeout int(5) default 0 comment '超时时间', + onlineSession varchar(50) default '' comment '备份的当前用户会话', + primary key (sessionId) +) engine=innodb default charset=utf8; + +insert into sys_user_online(sessionId, user_id, login_name, ipaddr, browser, os, status) +values('c3b252c3-2229-4be4-a5f7-7aba4b0c314c', 1, 'admin', '127.0.0.1', 'Chrome 45', 'Windows 7', 'on_line'); + -- 用户部门表 SELECT * FROM sys_dept; @@ -273,3 +295,6 @@ SELECT * FROM sys_code; -- 系统访问日志情况信息 SELECT * FROM sys_logininfor; + +-- 在线用户信息 +SELECT * FROM sys_user_online; diff --git a/src/main/java/com/ruoyi/framework/config/ShiroConfig.java b/src/main/java/com/ruoyi/framework/config/ShiroConfig.java index c2119f3ca..f8c942b8a 100644 --- a/src/main/java/com/ruoyi/framework/config/ShiroConfig.java +++ b/src/main/java/com/ruoyi/framework/config/ShiroConfig.java @@ -1,22 +1,27 @@ package com.ruoyi.framework.config; import java.util.LinkedHashMap; + import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; -import org.apache.shiro.session.mgt.eis.MemorySessionDAO; -import org.apache.shiro.session.mgt.eis.SessionDAO; +import org.apache.shiro.session.mgt.SessionFactory; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.filter.authc.LogoutFilter; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; + import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.project.shiro.realm.UserRealm; +import com.ruoyi.project.shiro.session.OnlineSessionDAO; +import com.ruoyi.project.shiro.session.OnlineSessionFactory; import com.ruoyi.project.system.menu.service.MenuServiceImpl; + import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; /** @@ -51,14 +56,40 @@ public class ShiroConfig return userRealm; } + /** + * 自定义sessionDAO会话 + */ + @Bean + OnlineSessionDAO sessionDAO() + { + OnlineSessionDAO sessionDAO = new OnlineSessionDAO(); + return sessionDAO; + } + + /** + * 自定义sessionFactory会话 + */ + @Bean + SessionFactory sessionFactory() + { + OnlineSessionFactory sessionFactory = new OnlineSessionFactory(); + return sessionFactory; + } + /** * 会话管理器 */ @Bean - SessionDAO sessionDAO() + public DefaultWebSessionManager configWebSessionManager() { - MemorySessionDAO sessionDAO = new MemorySessionDAO(); - return sessionDAO; + DefaultWebSessionManager manager = new DefaultWebSessionManager(); + manager.setCacheManager(getEhCacheManager());// 加入缓存管理器 + manager.setSessionDAO(sessionDAO());// 设置SessionDao + manager.setDeleteInvalidSessions(true);// 删除过期的session + manager.setGlobalSessionTimeout(sessionDAO().getExpireTime());// 设置全局session超时时间 + manager.setSessionValidationSchedulerEnabled(true);// 是否定时检查session + manager.setSessionFactory(sessionFactory()); + return manager; } /** @@ -67,10 +98,14 @@ public class ShiroConfig @Bean SecurityManager securityManager(UserRealm userRealm) { - DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); - manager.setRealm(userRealm); - manager.setCacheManager(getEhCacheManager()); - return manager; + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + // 设置realm. + securityManager.setRealm(userRealm); + // 注入缓存管理器; + securityManager.setCacheManager(getEhCacheManager()); + // session管理器 + securityManager.setSessionManager(configWebSessionManager()); + return securityManager; } /** diff --git a/src/main/java/com/ruoyi/project/shiro/ShiroConstants.java b/src/main/java/com/ruoyi/project/shiro/ShiroConstants.java index bd68c8c52..0c255bab4 100644 --- a/src/main/java/com/ruoyi/project/shiro/ShiroConstants.java +++ b/src/main/java/com/ruoyi/project/shiro/ShiroConstants.java @@ -41,4 +41,14 @@ public interface ShiroConstants * 编码格式 */ public static String ENCODING = "UTF-8"; + + /** + * 当前在线会话 + */ + public String ONLINE_SESSION = "online_session"; + + /** + * 仅清空本地缓存 不情况数据库的 + */ + public String ONLY_CLEAR_CACHE = "online_session_only_clear_cache"; } diff --git a/src/main/java/com/ruoyi/project/shiro/realm/LoginService.java b/src/main/java/com/ruoyi/project/shiro/realm/LoginService.java index 2ba80c026..c5a668141 100644 --- a/src/main/java/com/ruoyi/project/shiro/realm/LoginService.java +++ b/src/main/java/com/ruoyi/project/shiro/realm/LoginService.java @@ -58,7 +58,7 @@ public class LoginService } // 查询用户信息 - User user = userService.findByUserName(username); + User user = userService.selectByUserName(username); if (user == null) { diff --git a/src/main/java/com/ruoyi/project/shiro/session/OnlineSessionDAO.java b/src/main/java/com/ruoyi/project/shiro/session/OnlineSessionDAO.java new file mode 100644 index 000000000..136c201a9 --- /dev/null +++ b/src/main/java/com/ruoyi/project/shiro/session/OnlineSessionDAO.java @@ -0,0 +1,194 @@ +package com.ruoyi.project.shiro.session; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; +import org.springframework.beans.factory.annotation.Autowired; +import com.ruoyi.project.system.online.domain.OnlineSession; +import com.ruoyi.project.system.online.domain.UserOnline; +import com.ruoyi.project.system.online.service.IUserOnlineService; +import com.ruoyi.project.util.HttpContextUtils; + +/** + * 针对自定义的ShiroSession的db操作 + */ +public class OnlineSessionDAO extends EnterpriseCacheSessionDAO +{ + // Session超时时间,单位为毫秒 + private long expireTime = 120000; + + /** + * 同步session到数据库的周期 单位为毫秒(默认5分钟) + */ + private long dbSyncPeriod = 5 * 60 * 1000; + + /** + * 上次同步数据库的时间戳 + */ + private static final String LAST_SYNC_DB_TIMESTAMP = OnlineSessionDAO.class.getName() + "LAST_SYNC_DB_TIMESTAMP"; + + @Autowired + private IUserOnlineService onlineService; + + @Autowired + private OnlineSessionFactory onlineSessionFactory; + + public OnlineSessionDAO() + { + super(); + } + + public OnlineSessionDAO(long expireTime) + { + super(); + this.expireTime = expireTime; + } + + /** + * 根据会话ID获取会话 + * + * @param sessionId 会话ID + * @return ShiroSession + */ + @Override + protected Session doReadSession(Serializable sessionId) + { + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + String uri = request.getServletPath(); + // 如果是静态文件,则不更新SESSION + if (checkStaticLink(uri)) + { + return null; + } + System.out.println("==============doReadSession url=================" + uri); + UserOnline userOnline = onlineService.selectByOnlineId(String.valueOf(sessionId)); + if (userOnline == null) + { + return null; + } + return onlineSessionFactory.createSession(userOnline); + } + + /** + * 更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用 + */ + @Override + protected void doUpdate(Session session) + { + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + String uri = request.getServletPath(); + // 如果是静态文件,则不更新SESSION + if (checkStaticLink(uri)) + { + return; + } + System.out.println("==============update url=================" + uri); + if (session == null || session.getId() == null) + { + return; + } + + Session session1 = doReadSession(session.getId()); + OnlineSession onlineSession = (OnlineSession) session1; + + Date lastSyncTimestamp = (Date) session.getAttribute(LAST_SYNC_DB_TIMESTAMP); + if (lastSyncTimestamp != null) + { + boolean needSync = true; + long deltaTime = session.getLastAccessTime().getTime() - lastSyncTimestamp.getTime(); + if (deltaTime < dbSyncPeriod) + { // 时间差不足 无需同步 + needSync = false; + } + boolean isGuest = session.getId() == null; + + // 如果不是游客 且session 数据变更了 同步 + if (isGuest == false && onlineSession.isAttributeChanged()) + { + needSync = true; + } + + if (needSync == false) + { + return; + } + } + session.setAttribute(LAST_SYNC_DB_TIMESTAMP, session.getLastAccessTime()); + // session.setTimeout(expireTime); + // 更新完后 重置标识 + if (onlineSession.isAttributeChanged()) + { + onlineSession.resetAttributeChanged(); + } + onlineService.saveByOnline(UserOnline.fromOnlineSession(onlineSession)); + } + + /** + * 当会话过期/停止(如用户退出时)属性等会调用 + */ + @Override + protected void doDelete(Session session) + { + System.out.println("===============delete================"); + if (null == session) + { + return; + } + String sessionId = String.valueOf(session.getId()); + onlineService.deleteByOnlineId(sessionId); + } + + /** + * 获取当前所有活跃用户 + */ + @Override + public Collection getActiveSessions() + { + System.out.println("==============getActiveSessions================="); + return null; + } + + public long getExpireTime() + { + return expireTime; + } + + public void setExpireTime(long expireTime) + { + this.expireTime = expireTime; + } + + /** + * 检查是否为静态链接 + * + * @return true 是 false 否 + */ + public boolean checkStaticLink(String uri) + { + boolean linkFlag = false; + // 如果是登录请求,则不更新SESSION + if (StringUtils.endsWithAny(uri, new String[] { "/login", "/", "/favicon.ico" })) + { + linkFlag = true; + } + // 如果是静态文件,则不更新SESSION + if (StringUtils.startsWith(uri, "/css") && StringUtils.endsWith(uri, ".css") + || StringUtils.startsWith(uri, "/js") && StringUtils.endsWith(uri, ".js") + || StringUtils.startsWith(uri, "/img") && StringUtils.endsWith(uri, ".jpg") + || StringUtils.startsWith(uri, "/img") && StringUtils.endsWith(uri, ".png") + || StringUtils.startsWith(uri, "/fonts") && StringUtils.endsWith(uri, ".woff2") + || StringUtils.startsWith(uri, "/js") && StringUtils.endsWith(uri, ".css") + || StringUtils.startsWith(uri, "/css") && StringUtils.endsWith(uri, ".png") + || StringUtils.startsWith(uri, "/css") && StringUtils.endsWith(uri, ".woff2")) + { + linkFlag = true; + } + return linkFlag; + } +} diff --git a/src/main/java/com/ruoyi/project/shiro/session/OnlineSessionFactory.java b/src/main/java/com/ruoyi/project/shiro/session/OnlineSessionFactory.java new file mode 100644 index 000000000..270f9516f --- /dev/null +++ b/src/main/java/com/ruoyi/project/shiro/session/OnlineSessionFactory.java @@ -0,0 +1,40 @@ +package com.ruoyi.project.shiro.session; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.shiro.session.Session; +import org.apache.shiro.session.mgt.SessionContext; +import org.apache.shiro.session.mgt.SessionFactory; +import org.apache.shiro.web.session.mgt.WebSessionContext; +import org.springframework.stereotype.Component; + +import com.ruoyi.project.shiro.common.utils.IpUtils; +import com.ruoyi.project.system.online.domain.OnlineSession; +import com.ruoyi.project.system.online.domain.UserOnline; + +@Component +public class OnlineSessionFactory implements SessionFactory +{ + public Session createSession(UserOnline userOnline) + { + return userOnline.getSession(); + } + + @Override + public Session createSession(SessionContext initData) + { + OnlineSession session = new OnlineSession(); + if (initData != null && initData instanceof WebSessionContext) + { + WebSessionContext sessionContext = (WebSessionContext) initData; + HttpServletRequest request = (HttpServletRequest) sessionContext.getServletRequest(); + if (request != null) + { + session.setHost(IpUtils.getIpAddr(request)); + session.setBrowser(request.getHeader("User-Agent")); + session.setHost(request.getLocalAddr() + ":" + request.getLocalPort()); + } + } + return session; + } +} diff --git a/src/main/java/com/ruoyi/project/system/online/dao/IUserOnlineDao.java b/src/main/java/com/ruoyi/project/system/online/dao/IUserOnlineDao.java new file mode 100644 index 000000000..8b2b6e207 --- /dev/null +++ b/src/main/java/com/ruoyi/project/system/online/dao/IUserOnlineDao.java @@ -0,0 +1,29 @@ +package com.ruoyi.project.system.online.dao; + +import com.ruoyi.project.system.online.domain.UserOnline; + +public interface IUserOnlineDao +{ + /** + * 通过会话序号查询信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public UserOnline selectByOnlineId(String sessionId); + + /** + * 通过会话序号删除信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public int deleteByOnlineId(String sessionId); + + /** + * 保存会话信息 + * + * @param online 会话信息 + */ + public int saveByOnline(UserOnline online); +} diff --git a/src/main/java/com/ruoyi/project/system/online/dao/UserOnlineDaoImpl.java b/src/main/java/com/ruoyi/project/system/online/dao/UserOnlineDaoImpl.java new file mode 100644 index 000000000..4326edb8c --- /dev/null +++ b/src/main/java/com/ruoyi/project/system/online/dao/UserOnlineDaoImpl.java @@ -0,0 +1,42 @@ +package com.ruoyi.project.system.online.dao; + +import org.springframework.stereotype.Repository; +import com.ruoyi.framework.core.dao.DynamicObjectBaseDao; +import com.ruoyi.project.system.online.domain.UserOnline; + +@Repository("userOnlineDao") +public class UserOnlineDaoImpl extends DynamicObjectBaseDao implements IUserOnlineDao +{ + /** + * 通过会话序号查询信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + @Override + public UserOnline selectByOnlineId(String sessionId) + { + return this.findForObject("SystemOnlineMapper.selectByOnlineId", sessionId); + } + + /** + * 通过会话序号删除信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public int deleteByOnlineId(String sessionId) + { + return this.delete("SystemOnlineMapper.deleteByOnlineId", sessionId); + } + + /** + * 保存会话信息 + * + * @param online 会话信息 + */ + public int saveByOnline(UserOnline online) + { + return this.save("SystemOnlineMapper.saveByOnline", online); + } +} diff --git a/src/main/java/com/ruoyi/project/system/online/domain/OnlineSession.java b/src/main/java/com/ruoyi/project/system/online/domain/OnlineSession.java new file mode 100644 index 000000000..38b232b93 --- /dev/null +++ b/src/main/java/com/ruoyi/project/system/online/domain/OnlineSession.java @@ -0,0 +1,280 @@ +package com.ruoyi.project.system.online.domain; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import org.apache.shiro.session.mgt.SimpleSession; + +/** + * + */ +public class OnlineSession extends SimpleSession +{ + + // Serialization reminder: + // You _MUST_ change this number if you introduce a change to this class + // that is NOT serialization backwards compatible. Serialization-compatible + // changes do not require a change to this number. If you need to generate + // a new number in this case, use the JDK's 'serialver' program to generate + // it. + private static final long serialVersionUID = -7125642695178165650L; + static int bitIndexCounter = 0; + private static final int USER_ID_BIT_MASK = 1 << bitIndexCounter++; + private static final int USER_AGENT_BIT_MASK = 1 << bitIndexCounter++; + private static final int STATUS_BIT_MASK = 1 << bitIndexCounter++; + private static final int USERNAME_BIT_MASK = 1 << bitIndexCounter++; + // private static final int REMEMBER_ME_BIT_MASK = 1 << bitIndexCounter++; + + public static enum OnlineStatus + { + on_line("在线"), hidden("隐身"), force_logout("强制退出"); + private final String info; + + private OnlineStatus(String info) + { + this.info = info; + } + + public String getInfo() + { + return info; + } + + @Override + public String toString() + { + return super.toString(); + } + } + + // sessionId + private String id; + + // 当前登录的用户Id + private String userId; + + // 登录名 + private String loginName; + + // 登录IP地址 + private String host; + + // 浏览器类型 + private String browser; + + // 操作系统 + private String os; + + // 在线状态 + private OnlineStatus status = OnlineStatus.on_line; + + public OnlineSession() + { + super(); + } + + public OnlineSession(String host) + { + super(host); + } + + public String getId() + { + return id; + } + + public void setId(String id) + { + this.id = id; + } + + public String getUserId() + { + return userId; + } + + public void setUserId(String userId) + { + this.userId = userId; + } + + public String getLoginName() + { + return loginName; + } + + public void setLoginName(String loginName) + { + this.loginName = loginName; + } + + public String getHost() + { + return host; + } + + public void setHost(String host) + { + this.host = host; + } + + public String getBrowser() + { + return browser; + } + + public void setBrowser(String browser) + { + this.browser = browser; + } + + public String getOs() + { + return os; + } + + public void setOs(String os) + { + this.os = os; + } + + public OnlineStatus getStatus() + { + return status; + } + + public void setStatus(OnlineStatus status) + { + this.status = status; + } + + /** + * 属性是否改变 优化session数据同步 + */ + private transient boolean attributeChanged = false; + + public void markAttributeChanged() + { + this.attributeChanged = true; + } + + public void resetAttributeChanged() + { + this.attributeChanged = false; + } + + public boolean isAttributeChanged() + { + return attributeChanged; + } + + @Override + public void setAttribute(Object key, Object value) + { + super.setAttribute(key, value); + } + + @Override + public Object removeAttribute(Object key) + { + return super.removeAttribute(key); + } + + /** + * Serializes this object to the specified output stream for JDK Serialization. + * + * @param out output stream used for Object serialization. + * @throws java.io.IOException if any of this object's fields cannot be written to the stream. + * @since 1.0 + */ + private void writeObject(ObjectOutputStream out) throws IOException + { + out.defaultWriteObject(); + short alteredFieldsBitMask = getAlteredFieldsBitMask(); + out.writeShort(alteredFieldsBitMask); + if (userId != null) + { + out.writeObject(userId); + } + if (browser != null) + { + out.writeObject(browser); + } + if (status != null) + { + out.writeObject(status); + } + + if (loginName != null) + { + out.writeObject(loginName); + } + } + + /** + * Reconstitutes this object based on the specified InputStream for JDK Serialization. + * + * @param in the input stream to use for reading data to populate this object. + * @throws IOException if the input stream cannot be used. + * @throws ClassNotFoundException if a required class needed for instantiation is not available in the present JVM + * @since 1.0 + */ + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + short bitMask = in.readShort(); + + if (isFieldPresent(bitMask, USER_ID_BIT_MASK)) + { + this.userId = (String) in.readObject(); + } + if (isFieldPresent(bitMask, USER_AGENT_BIT_MASK)) + { + this.browser = (String) in.readObject(); + } + if (isFieldPresent(bitMask, STATUS_BIT_MASK)) + { + this.status = (OnlineStatus) in.readObject(); + } + if (isFieldPresent(bitMask, USERNAME_BIT_MASK)) + { + this.loginName = (String) in.readObject(); + } + } + + /** + * Returns a bit mask used during serialization indicating which fields have been serialized. Fields that have been + * altered (not null and/or not retaining the class defaults) will be serialized and have 1 in their respective + * index, fields that are null and/or retain class default values have 0. + * + * @return a bit mask used during serialization indicating which fields have been serialized. + * @since 1.0 + */ + private short getAlteredFieldsBitMask() + { + int bitMask = 0; + bitMask = userId != null ? bitMask | USER_ID_BIT_MASK : bitMask; + bitMask = browser != null ? bitMask | USER_AGENT_BIT_MASK : bitMask; + bitMask = status != null ? bitMask | STATUS_BIT_MASK : bitMask; + bitMask = loginName != null ? bitMask | USERNAME_BIT_MASK : bitMask; + return (short) bitMask; + } + + /** + * Returns {@code true} if the given {@code bitMask} argument indicates that the specified field has been serialized + * and therefore should be read during deserialization, {@code false} otherwise. + * + * @param bitMask the aggregate bitmask for all fields that have been serialized. Individual bits represent the + * fields that have been serialized. A bit set to 1 means that corresponding field has been serialized, 0 + * means it hasn't been serialized. + * @param fieldBitMask the field bit mask constant identifying which bit to inspect (corresponds to a class + * attribute). + * @return {@code true} if the given {@code bitMask} argument indicates that the specified field has been serialized + * and therefore should be read during deserialization, {@code false} otherwise. + * @since 1.0 + */ + private static boolean isFieldPresent(short bitMask, int fieldBitMask) + { + return (bitMask & fieldBitMask) != 0; + } +} diff --git a/src/main/java/com/ruoyi/project/system/online/domain/UserOnline.java b/src/main/java/com/ruoyi/project/system/online/domain/UserOnline.java new file mode 100644 index 000000000..9c6779c87 --- /dev/null +++ b/src/main/java/com/ruoyi/project/system/online/domain/UserOnline.java @@ -0,0 +1,175 @@ +package com.ruoyi.project.system.online.domain; + +import java.io.Serializable; +import java.util.Date; + +/** + * 当前在线会话 sys_user_online + * + * @author yangzz + */ +public class UserOnline implements Serializable +{ + private static final long serialVersionUID = 1L; + + // 用户会话id + private String sessionId; + + // 当前登录的用户Id + private String userId; + + // 登录名 + private String loginName; + + // 登录IP地址 + private String host; + + // 浏览器类型 + private String browser; + + // 操作系统 + private String os; + + // 在线状态 + private OnlineSession.OnlineStatus status = OnlineSession.OnlineStatus.on_line; + + // 在线状态 + private Date startTimestamp; + + // session最后访问时间 + private Date lastAccessTime; + + // 超时时间 + private Long timeout; + + // 备份的当前用户会话 + private OnlineSession session; + + public String getSessionId() + { + return sessionId; + } + + public void setSessionId(String sessionId) + { + this.sessionId = sessionId; + } + + public String getUserId() + { + return userId; + } + + public void setUserId(String userId) + { + this.userId = userId; + } + + public String getLoginName() + { + return loginName; + } + + public void setLoginName(String loginName) + { + this.loginName = loginName; + } + + public String getHost() + { + return host; + } + + public void setHost(String host) + { + this.host = host; + } + + public String getBrowser() + { + return browser; + } + + public void setBrowser(String browser) + { + this.browser = browser; + } + + public String getOs() + { + return os; + } + + public void setOs(String os) + { + this.os = os; + } + + public OnlineSession.OnlineStatus getStatus() + { + return status; + } + + public void setStatus(OnlineSession.OnlineStatus status) + { + this.status = status; + } + + public Date getStartTimestamp() + { + return startTimestamp; + } + + public void setStartTimestamp(Date startTimestamp) + { + this.startTimestamp = startTimestamp; + } + + public Date getLastAccessTime() + { + return lastAccessTime; + } + + public void setLastAccessTime(Date lastAccessTime) + { + this.lastAccessTime = lastAccessTime; + } + + public Long getTimeout() + { + return timeout; + } + + public void setTimeout(Long timeout) + { + this.timeout = timeout; + } + + public OnlineSession getSession() + { + return session; + } + + public void setSession(OnlineSession session) + { + this.session = session; + } + + public static final UserOnline fromOnlineSession(OnlineSession session) + { + UserOnline online = new UserOnline(); + online.setSessionId(String.valueOf(session.getId())); + online.setUserId(session.getUserId()); + online.setLoginName(session.getLoginName()); + online.setStartTimestamp(session.getStartTimestamp()); + online.setLastAccessTime(session.getLastAccessTime()); + online.setTimeout(session.getTimeout()); + online.setHost(session.getHost()); + online.setBrowser(session.getBrowser()); + online.setOs(session.getOs()); + online.setSession(session); + + return online; + } + +} diff --git a/src/main/java/com/ruoyi/project/system/online/service/IUserOnlineService.java b/src/main/java/com/ruoyi/project/system/online/service/IUserOnlineService.java new file mode 100644 index 000000000..e24e6f905 --- /dev/null +++ b/src/main/java/com/ruoyi/project/system/online/service/IUserOnlineService.java @@ -0,0 +1,29 @@ +package com.ruoyi.project.system.online.service; + +import com.ruoyi.project.system.online.domain.UserOnline; + +public interface IUserOnlineService +{ + /** + * 通过会话序号查询信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public UserOnline selectByOnlineId(String sessionId); + + /** + * 通过会话序号删除信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public void deleteByOnlineId(String sessionId); + + /** + * 保存会话信息 + * + * @param online 会话信息 + */ + public void saveByOnline(UserOnline online); +} diff --git a/src/main/java/com/ruoyi/project/system/online/service/UserOnlineServiceImpl.java b/src/main/java/com/ruoyi/project/system/online/service/UserOnlineServiceImpl.java new file mode 100644 index 000000000..ff6db91f0 --- /dev/null +++ b/src/main/java/com/ruoyi/project/system/online/service/UserOnlineServiceImpl.java @@ -0,0 +1,49 @@ +package com.ruoyi.project.system.online.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.project.system.online.dao.IUserOnlineDao; +import com.ruoyi.project.system.online.domain.UserOnline; + +@Service("userOnlineService") +public class UserOnlineServiceImpl implements IUserOnlineService +{ + @Autowired + private IUserOnlineDao userOnlineDao; + + /** + * 通过会话序号查询信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public UserOnline selectByOnlineId(String sessionId) + { + return userOnlineDao.selectByOnlineId(sessionId); + } + + /** + * 通过会话序号删除信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public void deleteByOnlineId(String sessionId) + { + UserOnline userOnline = selectByOnlineId(sessionId); + if (userOnline != null) + { + userOnlineDao.deleteByOnlineId(sessionId); + } + } + + /** + * 保存会话信息 + * + * @param online 会话信息 + */ + public void saveByOnline(UserOnline online) + { + + } +} diff --git a/src/main/java/com/ruoyi/project/system/user/dao/IUserDao.java b/src/main/java/com/ruoyi/project/system/user/dao/IUserDao.java index ab713e74d..544701292 100644 --- a/src/main/java/com/ruoyi/project/system/user/dao/IUserDao.java +++ b/src/main/java/com/ruoyi/project/system/user/dao/IUserDao.java @@ -26,6 +26,6 @@ public interface IUserDao * @param userName 用户名 * @return 用户对象信息 */ - public User findByUserName(String userName); + public User selectByUserName(String userName); } diff --git a/src/main/java/com/ruoyi/project/system/user/dao/UserDaoImpl.java b/src/main/java/com/ruoyi/project/system/user/dao/UserDaoImpl.java index deec0717e..c069db15f 100644 --- a/src/main/java/com/ruoyi/project/system/user/dao/UserDaoImpl.java +++ b/src/main/java/com/ruoyi/project/system/user/dao/UserDaoImpl.java @@ -45,9 +45,9 @@ public class UserDaoImpl extends DynamicObjectBaseDao implements IUserDao * @return 用户对象信息 */ @Override - public User findByUserName(String username) + public User selectByUserName(String username) { - return this.findForObject("SystemUserMapper.findByUserName", username); + return this.findForObject("SystemUserMapper.selectByUserName", username); } } diff --git a/src/main/java/com/ruoyi/project/system/user/service/IUserService.java b/src/main/java/com/ruoyi/project/system/user/service/IUserService.java index 878f4e4bc..7ac616469 100644 --- a/src/main/java/com/ruoyi/project/system/user/service/IUserService.java +++ b/src/main/java/com/ruoyi/project/system/user/service/IUserService.java @@ -26,5 +26,5 @@ public interface IUserService * @param userName 用户名 * @return 用户对象信息 */ - public User findByUserName(String userName); + public User selectByUserName(String userName); } diff --git a/src/main/java/com/ruoyi/project/system/user/service/UserServiceImpl.java b/src/main/java/com/ruoyi/project/system/user/service/UserServiceImpl.java index b1c2af716..811e42f76 100644 --- a/src/main/java/com/ruoyi/project/system/user/service/UserServiceImpl.java +++ b/src/main/java/com/ruoyi/project/system/user/service/UserServiceImpl.java @@ -39,9 +39,9 @@ public class UserServiceImpl implements IUserService * @return 用户对象信息 */ @Override - public User findByUserName(String userName) + public User selectByUserName(String userName) { - return userDao.findByUserName(userName); + return userDao.selectByUserName(userName); } } diff --git a/src/main/resources/mybatis/system/SystemOnlineMapper.xml b/src/main/resources/mybatis/system/SystemOnlineMapper.xml new file mode 100644 index 000000000..851847d22 --- /dev/null +++ b/src/main/resources/mybatis/system/SystemOnlineMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + replace into sys_user_online(sessionId, user_id, login_name, ipaddr, browser, os, STATUS) + values (#{sessionId}, #{user_id}, #{login_name}, #{host}, #{browser}, #{os}, #{STATUS}) + + + + delete from sys_user_online where sessionId = #{sessionId} + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/system/SystemUserMapper.xml b/src/main/resources/mybatis/system/SystemUserMapper.xml index 044ab5367..b09ac048e 100644 --- a/src/main/resources/mybatis/system/SystemUserMapper.xml +++ b/src/main/resources/mybatis/system/SystemUserMapper.xml @@ -44,7 +44,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select * from sys_user - SELECT u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.phonenumber, u.password, u.salt, u.status, u.refuse_des, u.create_time, d.dept_id, d.parent_id, d.dept_name, d.order_num, d.status as dept_status, r.role_id, r.role_name, r.status as role_status, r.remark