新增会话管理过滤器
This commit is contained in:
parent
0cbb3a034a
commit
623c70d6fc
|
|
@ -110,10 +110,10 @@ insert into sys_menu values('4', '角色管理', '1', '2', '/system/role/roleLis
|
|||
insert into sys_menu values('5', '菜单管理', '1', '3', '/system/menu/menuList', 'C', '0', 'system:menu:list', '#', '2018-01-01', '', 'system', '菜单管理菜单');
|
||||
insert into sys_menu values('6', '操作日志', '1', '4', '/system/operlog/operlogList', 'C', '0', 'system:operlog:list', '#', '2018-01-01', '', 'system', '操作日志菜单');
|
||||
insert into sys_menu values('7', '登录日志', '1', '5', '/system/userlog/userlogList', 'C', '0', 'system:userlog:list', '#', '2018-01-01', '', 'system', '登录日志菜单');
|
||||
insert into sys_menu values('8', '在线用户', '2', '1', '/monitor/userOnline', 'C', '0', 'monitor:userOnline', '#', '2018-01-01', '', 'system', '在线用户菜单');
|
||||
insert into sys_menu values('8', '在线用户', '2', '1', '/monitor/online', 'C', '0', 'monitor:online', '#', '2018-01-01', '', 'system', '在线用户菜单');
|
||||
insert into sys_menu values('9', '数据监控', '2', '2', '/monitor/druid/index.html', 'C', '0', 'monitor:druid:list', '#', '2018-01-01', '', 'system', '数据监控菜单');
|
||||
--- 三级用户按钮
|
||||
insert into sys_menu values('10', '用户新增', '3', '1', '/system/user/add', 'F', '0', 'sys:user:add', '#', '2018-01-01', '', 'system', '用户管理新增按钮');
|
||||
insert into sys_menu values('10', '用户新增', '3', '1', '/system/user/add', 'F', '0', 'sys:user:add', '#', '2018-01-01', '', 'system', '用户管理新增按钮');
|
||||
insert into sys_menu values('11', '用户修改', '3', '2', '/system/user/update', 'F', '0', 'sys:user:update', '#', '2018-01-01', '', 'system', '用户管理修改按钮');
|
||||
insert into sys_menu values('12', '用户删除', '3', '3', '/system/user/delete', 'F', '0', 'sys:user:delete', '#', '2018-01-01', '', 'system', '用户管理删除按钮');
|
||||
insert into sys_menu values('13', '用户查询', '3', '4', '/system/user/select', 'F', '0', 'sys:user:select', '#', '2018-01-01', '', 'system', '用户管理查询按钮');
|
||||
|
|
@ -254,22 +254,22 @@ insert into sys_logininfor values(1, 'admin', 0 , '127.0.0.1', 'Chrome 45', 'Win
|
|||
-- ----------------------------
|
||||
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 '登录名',
|
||||
sessionId varchar(50) default '' comment '用户会话id',
|
||||
login_name varchar(50) default '' comment '登录名称',
|
||||
dept_name varchar(50) default '' comment '部门名称',
|
||||
role_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 '在线状态',
|
||||
status varchar(10) default '' comment '在线状态on_line在线off_line离线',
|
||||
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 '备份的当前用户会话',
|
||||
expireTime int(5) default 0 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');
|
||||
insert into sys_user_online(sessionId, login_name, dept_name, login_name, ipaddr, browser, os, status)
|
||||
values('c3b252c3-2229-4be4-a5f7-7aba4b0c314c', 'admin', '开发部', '管理员', '127.0.0.1', 'Chrome 45', 'Windows 7');
|
||||
|
||||
-- 用户部门表
|
||||
SELECT * FROM sys_dept;
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.apache.shiro.cache.ehcache.EhCacheManager;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
|
|
@ -20,6 +23,8 @@ 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.shiro.web.OnlineSessionFilter;
|
||||
import com.ruoyi.project.shiro.web.sync.SyncOnlineSessionFilter;
|
||||
import com.ruoyi.project.system.menu.service.MenuServiceImpl;
|
||||
|
||||
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
|
||||
|
|
@ -140,12 +145,43 @@ public class ShiroConfig
|
|||
// 系统权限列表
|
||||
MenuServiceImpl menuService = SpringUtils.getBean(MenuServiceImpl.class);
|
||||
filterChainDefinitionMap.putAll(menuService.selectPermsAll());
|
||||
|
||||
Map<String, Filter> filters = new LinkedHashMap<>();
|
||||
filters.put("onlineSession", onlineSessionFilter());
|
||||
filters.put("syncOnlineSession", syncOnlineSessionFilter());
|
||||
shiroFilterFactoryBean.setFilters(filters);
|
||||
|
||||
// 所有请求需要认证
|
||||
filterChainDefinitionMap.put("/**", "authc");
|
||||
// 系统请求记录当前会话
|
||||
filterChainDefinitionMap.put("/system/**", "onlineSession,syncOnlineSession");
|
||||
filterChainDefinitionMap.put("/monitor/**", "onlineSession,syncOnlineSession");
|
||||
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
||||
|
||||
return shiroFilterFactoryBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义在线用户处理过滤器
|
||||
*/
|
||||
@Bean
|
||||
OnlineSessionFilter onlineSessionFilter()
|
||||
{
|
||||
OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter();
|
||||
onlineSessionFilter.setLoginUrl("/login");
|
||||
return onlineSessionFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义在线用户同步过滤器
|
||||
*/
|
||||
@Bean
|
||||
SyncOnlineSessionFilter syncOnlineSessionFilter()
|
||||
{
|
||||
SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter();
|
||||
return syncOnlineSessionFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保证实现了Shiro内部lifecycle函数的bean执行
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -77,35 +77,22 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
|
|||
/**
|
||||
* 更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用
|
||||
*/
|
||||
@Override
|
||||
protected void doUpdate(Session session)
|
||||
public void syncToDb(OnlineSession onlineSession)
|
||||
{
|
||||
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
|
||||
String uri = request.getServletPath();
|
||||
// 如果是静态文件,则不更新SESSION
|
||||
if (checkStaticLink(uri))
|
||||
{
|
||||
return;
|
||||
}
|
||||
System.out.println("==============update url=================" + uri);
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnlineSession onlineSession = (OnlineSession) session;
|
||||
|
||||
Date lastSyncTimestamp = (Date) session.getAttribute(LAST_SYNC_DB_TIMESTAMP);
|
||||
System.out.println("===============update================" + uri);
|
||||
Date lastSyncTimestamp = (Date) onlineSession.getAttribute(LAST_SYNC_DB_TIMESTAMP);
|
||||
if (lastSyncTimestamp != null)
|
||||
{
|
||||
boolean needSync = true;
|
||||
long deltaTime = session.getLastAccessTime().getTime() - lastSyncTimestamp.getTime();
|
||||
long deltaTime = onlineSession.getLastAccessTime().getTime() - lastSyncTimestamp.getTime();
|
||||
if (deltaTime < dbSyncPeriod)
|
||||
{
|
||||
// 时间差不足 无需同步
|
||||
needSync = false;
|
||||
}
|
||||
boolean isGuest = session.getId() == null;
|
||||
boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L;
|
||||
|
||||
// 如果不是游客 且session 数据变更了 同步
|
||||
if (isGuest == false && onlineSession.isAttributeChanged())
|
||||
|
|
@ -118,8 +105,7 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
|
|||
return;
|
||||
}
|
||||
}
|
||||
session.setAttribute(LAST_SYNC_DB_TIMESTAMP, session.getLastAccessTime());
|
||||
// session.setTimeout(expireTime);
|
||||
onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime());
|
||||
// 更新完后 重置标识
|
||||
if (onlineSession.isAttributeChanged())
|
||||
{
|
||||
|
|
@ -134,14 +120,16 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
|
|||
@Override
|
||||
protected void doDelete(Session session)
|
||||
{
|
||||
System.out.println("===============delete================");
|
||||
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
|
||||
String uri = request.getServletPath();
|
||||
System.out.println("===============delete================" + uri);
|
||||
OnlineSession onlineSession = (OnlineSession) session;
|
||||
if (null == onlineSession)
|
||||
{
|
||||
return;
|
||||
}
|
||||
String sessionId = String.valueOf(onlineSession.getId());
|
||||
onlineService.deleteByOnlineId(sessionId);
|
||||
onlineSession.setStatus(OnlineSession.OnlineStatus.off_line);
|
||||
onlineService.deleteByOnlineId(String.valueOf(onlineSession.getId()));
|
||||
}
|
||||
|
||||
public long getExpireTime()
|
||||
|
|
@ -163,7 +151,8 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
|
|||
{
|
||||
boolean linkFlag = false;
|
||||
// 如果是登录请求,则不更新SESSION
|
||||
if (StringUtils.endsWithAny(uri, new String[] { "/login", "/logout", "/index", "/", "/favicon.ico" }))
|
||||
if (StringUtils.startsWithAny(uri,
|
||||
new String[] { "/monitor/online/forceLogout", "/login", "/logout", "/index", "/favicon.ico" }))
|
||||
{
|
||||
linkFlag = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
package com.ruoyi.project.shiro.web;
|
||||
|
||||
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.Autowired;
|
||||
import com.ruoyi.common.utils.security.ShiroUtils;
|
||||
import com.ruoyi.project.shiro.ShiroConstants;
|
||||
import com.ruoyi.project.shiro.session.OnlineSessionDAO;
|
||||
import com.ruoyi.project.system.online.domain.OnlineSession;
|
||||
import com.ruoyi.project.system.user.domain.User;
|
||||
|
||||
public class OnlineSessionFilter extends AccessControlFilter
|
||||
{
|
||||
|
||||
/**
|
||||
* 强制退出后重定向的地址
|
||||
*/
|
||||
private String forceLogoutUrl = "/login";
|
||||
|
||||
@Autowired
|
||||
private OnlineSessionDAO onlineSessionDAO;
|
||||
|
||||
public String getForceLogoutUrl()
|
||||
{
|
||||
return forceLogoutUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表示是否允许访问;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)
|
||||
{
|
||||
User user = ShiroUtils.getUser();
|
||||
if (user != null)
|
||||
{
|
||||
onlineSession.setUserId(user.getUserId());
|
||||
onlineSession.setLoginName(user.getLoginName());
|
||||
onlineSession.setDeptName(user.getDept().getDeptName());
|
||||
onlineSession.setRoleName(user.getRole().getRoleName());
|
||||
onlineSession.markAttributeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineSession.getStatus() == OnlineSession.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 true;
|
||||
}
|
||||
|
||||
// 跳转到登录页
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException
|
||||
{
|
||||
String loginUrl = getForceLogoutUrl();
|
||||
WebUtils.issueRedirect(request, response, loginUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.ruoyi.project.shiro.web.sync;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import org.apache.shiro.web.filter.PathMatchingFilter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.ruoyi.project.shiro.ShiroConstants;
|
||||
import com.ruoyi.project.shiro.session.OnlineSessionDAO;
|
||||
import com.ruoyi.project.system.online.domain.OnlineSession;
|
||||
|
||||
public class SyncOnlineSessionFilter extends PathMatchingFilter
|
||||
{
|
||||
@Autowired
|
||||
private OnlineSessionDAO onlineSessionDAO;
|
||||
|
||||
/**
|
||||
* 同步会话数据到DB 一次请求最多同步一次 防止过多处理 需要放到Shiro过滤器之前
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception
|
||||
{
|
||||
OnlineSession session = (OnlineSession) request.getAttribute(ShiroConstants.ONLINE_SESSION);
|
||||
// 如果session stop了 也不同步
|
||||
if (session != null && session.getUserId() != null && session.getStopTimestamp() == null)
|
||||
{
|
||||
onlineSessionDAO.syncToDb(session);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,26 @@
|
|||
package com.ruoyi.project.system.online.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.ruoyi.common.tools.StringTools;
|
||||
import com.ruoyi.common.utils.TableDataInfo;
|
||||
import com.ruoyi.framework.core.controller.BaseController;
|
||||
import com.ruoyi.framework.core.domain.R;
|
||||
import com.ruoyi.project.shiro.session.OnlineSessionDAO;
|
||||
import com.ruoyi.project.system.online.domain.OnlineSession;
|
||||
import com.ruoyi.project.system.online.domain.UserOnline;
|
||||
import com.ruoyi.project.system.online.service.IUserOnlineService;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/monitor/userOnline")
|
||||
@RequestMapping("/monitor/online")
|
||||
public class UserOnlineController extends BaseController
|
||||
{
|
||||
|
||||
|
|
@ -25,19 +29,21 @@ public class UserOnlineController extends BaseController
|
|||
@Autowired
|
||||
private IUserOnlineService userOnlineService;
|
||||
|
||||
@Autowired
|
||||
private OnlineSessionDAO onlineSessionDAO;
|
||||
|
||||
@GetMapping()
|
||||
public String userOnline()
|
||||
public String online()
|
||||
{
|
||||
return prefix + "/online";
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@ResponseBody
|
||||
public TableDataInfo list(Model model)
|
||||
public List<UserOnline> list(Model model)
|
||||
{
|
||||
List<UserOnline> list = userOnlineService.selectUserOnlines();
|
||||
TableDataInfo tableDataInfo = new TableDataInfo(list, 12);
|
||||
return tableDataInfo;
|
||||
return list;
|
||||
}
|
||||
|
||||
@GetMapping("/forceLogout")
|
||||
|
|
@ -68,4 +74,32 @@ public class UserOnlineController extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/forceLogout/{sessionId}")
|
||||
public R forceLogout(@PathVariable("sessionId") String sessionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserOnline online = userOnlineService.selectByOnlineId(sessionId);
|
||||
if (online == null)
|
||||
{
|
||||
return R.error("用户已下线。数据不存在");
|
||||
}
|
||||
OnlineSession onlineSession = (OnlineSession) onlineSessionDAO.readSession(online.getSessionId());
|
||||
if (onlineSession == null)
|
||||
{
|
||||
return R.error("用户已下线。会话不存在");
|
||||
}
|
||||
onlineSession.setStatus(OnlineSession.OnlineStatus.off_line);
|
||||
online.setStatus(OnlineSession.OnlineStatus.off_line);
|
||||
userOnlineService.saveByOnline(online);
|
||||
return R.ok();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
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;
|
||||
|
||||
/**
|
||||
|
|
@ -11,48 +8,20 @@ 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++;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static enum OnlineStatus
|
||||
{
|
||||
on_line("在线"), hidden("隐身"), force_logout("强制退出");
|
||||
private final String info;
|
||||
// 用户ID
|
||||
private Long userId;
|
||||
|
||||
private OnlineStatus(String info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public String getInfo()
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// 当前登录的用户Id
|
||||
private String userId;
|
||||
|
||||
// 登录名
|
||||
// 用户名称
|
||||
private String loginName;
|
||||
|
||||
// 部门名称
|
||||
private String deptName;
|
||||
|
||||
// 角色名称
|
||||
private String roleName;
|
||||
|
||||
// 登录IP地址
|
||||
private String host;
|
||||
|
||||
|
|
@ -65,35 +34,8 @@ public class OnlineSession extends SimpleSession
|
|||
// 在线状态
|
||||
private OnlineStatus status = OnlineStatus.on_line;
|
||||
|
||||
public OnlineSession()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public OnlineSession(String host)
|
||||
{
|
||||
super(host);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// 属性是否改变 优化session数据同步
|
||||
private transient boolean attributeChanged = false;
|
||||
|
||||
public String getHost()
|
||||
{
|
||||
|
|
@ -125,6 +67,46 @@ public class OnlineSession extends SimpleSession
|
|||
this.os = os;
|
||||
}
|
||||
|
||||
public Long getUserId()
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getLoginName()
|
||||
{
|
||||
return loginName;
|
||||
}
|
||||
|
||||
public void setLoginName(String loginName)
|
||||
{
|
||||
this.loginName = loginName;
|
||||
}
|
||||
|
||||
public String getDeptName()
|
||||
{
|
||||
return deptName;
|
||||
}
|
||||
|
||||
public void setDeptName(String deptName)
|
||||
{
|
||||
this.deptName = deptName;
|
||||
}
|
||||
|
||||
public String getRoleName()
|
||||
{
|
||||
return roleName;
|
||||
}
|
||||
|
||||
public void setRoleName(String roleName)
|
||||
{
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public OnlineStatus getStatus()
|
||||
{
|
||||
return status;
|
||||
|
|
@ -135,11 +117,6 @@ public class OnlineSession extends SimpleSession
|
|||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性是否改变 优化session数据同步
|
||||
*/
|
||||
private transient boolean attributeChanged = false;
|
||||
|
||||
public void markAttributeChanged()
|
||||
{
|
||||
this.attributeChanged = true;
|
||||
|
|
@ -167,101 +144,20 @@ public class OnlineSession extends SimpleSession
|
|||
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
|
||||
public static enum OnlineStatus
|
||||
{
|
||||
out.defaultWriteObject();
|
||||
short alteredFieldsBitMask = getAlteredFieldsBitMask();
|
||||
out.writeShort(alteredFieldsBitMask);
|
||||
if (userId != null)
|
||||
on_line("在线"), off_line("离线");
|
||||
private final String info;
|
||||
|
||||
private OnlineStatus(String info)
|
||||
{
|
||||
out.writeObject(userId);
|
||||
}
|
||||
if (browser != null)
|
||||
{
|
||||
out.writeObject(browser);
|
||||
}
|
||||
if (status != null)
|
||||
{
|
||||
out.writeObject(status);
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
if (loginName != null)
|
||||
public String getInfo()
|
||||
{
|
||||
out.writeObject(loginName);
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ package com.ruoyi.project.system.online.domain;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import com.ruoyi.common.utils.security.ShiroUtils;
|
||||
import com.ruoyi.project.system.online.domain.OnlineSession.OnlineStatus;
|
||||
|
||||
/**
|
||||
* 当前在线会话 sys_user_online
|
||||
|
|
@ -17,14 +16,17 @@ public class UserOnline implements Serializable
|
|||
// 用户会话id
|
||||
private String sessionId;
|
||||
|
||||
// 当前登录的用户Id
|
||||
private String userId;
|
||||
// 部门名称
|
||||
private String deptName;
|
||||
|
||||
// 登录名
|
||||
// 登录名称
|
||||
private String loginName;
|
||||
|
||||
// 角色名称
|
||||
private String roleName;
|
||||
|
||||
// 登录IP地址
|
||||
private String host;
|
||||
private String ipaddr;
|
||||
|
||||
// 浏览器类型
|
||||
private String browser;
|
||||
|
|
@ -32,17 +34,17 @@ public class UserOnline implements Serializable
|
|||
// 操作系统
|
||||
private String os;
|
||||
|
||||
// 在线状态
|
||||
private OnlineSession.OnlineStatus status = OnlineSession.OnlineStatus.on_line;
|
||||
|
||||
// 在线状态
|
||||
// session创建时间
|
||||
private Date startTimestamp;
|
||||
|
||||
// session最后访问时间
|
||||
private Date lastAccessTime;
|
||||
|
||||
// 超时时间
|
||||
private Long timeout;
|
||||
// 超时时间,单位为分钟
|
||||
private Long expireTime;
|
||||
|
||||
// 在线状态
|
||||
private OnlineStatus status = OnlineStatus.on_line;
|
||||
|
||||
// 备份的当前用户会话
|
||||
private OnlineSession session;
|
||||
|
|
@ -57,14 +59,14 @@ public class UserOnline implements Serializable
|
|||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public String getUserId()
|
||||
public String getDeptName()
|
||||
{
|
||||
return userId;
|
||||
return deptName;
|
||||
}
|
||||
|
||||
public void setUserId(String userId)
|
||||
public void setDeptName(String deptName)
|
||||
{
|
||||
this.userId = userId;
|
||||
this.deptName = deptName;
|
||||
}
|
||||
|
||||
public String getLoginName()
|
||||
|
|
@ -77,14 +79,24 @@ public class UserOnline implements Serializable
|
|||
this.loginName = loginName;
|
||||
}
|
||||
|
||||
public String getHost()
|
||||
public String getRoleName()
|
||||
{
|
||||
return host;
|
||||
return roleName;
|
||||
}
|
||||
|
||||
public void setHost(String host)
|
||||
public void setRoleName(String roleName)
|
||||
{
|
||||
this.host = host;
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public String getIpaddr()
|
||||
{
|
||||
return ipaddr;
|
||||
}
|
||||
|
||||
public void setIpaddr(String ipaddr)
|
||||
{
|
||||
this.ipaddr = ipaddr;
|
||||
}
|
||||
|
||||
public String getBrowser()
|
||||
|
|
@ -107,16 +119,6 @@ public class UserOnline implements Serializable
|
|||
this.os = os;
|
||||
}
|
||||
|
||||
public OnlineSession.OnlineStatus getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(OnlineSession.OnlineStatus status)
|
||||
{
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Date getStartTimestamp()
|
||||
{
|
||||
return startTimestamp;
|
||||
|
|
@ -137,14 +139,24 @@ public class UserOnline implements Serializable
|
|||
this.lastAccessTime = lastAccessTime;
|
||||
}
|
||||
|
||||
public Long getTimeout()
|
||||
public Long getExpireTime()
|
||||
{
|
||||
return timeout;
|
||||
return expireTime;
|
||||
}
|
||||
|
||||
public void setTimeout(Long timeout)
|
||||
public void setExpireTime(Long expireTime)
|
||||
{
|
||||
this.timeout = timeout;
|
||||
this.expireTime = expireTime;
|
||||
}
|
||||
|
||||
public OnlineStatus getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(OnlineStatus status)
|
||||
{
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public OnlineSession getSession()
|
||||
|
|
@ -157,20 +169,24 @@ public class UserOnline implements Serializable
|
|||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置session对象
|
||||
*/
|
||||
public static final UserOnline fromOnlineSession(OnlineSession session)
|
||||
{
|
||||
UserOnline online = new UserOnline();
|
||||
online.setSessionId(String.valueOf(session.getId()));
|
||||
online.setUserId(ShiroUtils.getUser().getUserId() + "");
|
||||
online.setLoginName(ShiroUtils.getUser().getLoginName());
|
||||
online.setDeptName(session.getDeptName());
|
||||
online.setLoginName(session.getLoginName());
|
||||
online.setRoleName(session.getRoleName());
|
||||
online.setStartTimestamp(session.getStartTimestamp());
|
||||
online.setLastAccessTime(session.getLastAccessTime());
|
||||
online.setTimeout(session.getTimeout());
|
||||
online.setHost(session.getHost());
|
||||
online.setExpireTime(session.getTimeout());
|
||||
online.setIpaddr(session.getHost());
|
||||
online.setBrowser(session.getBrowser());
|
||||
online.setOs(session.getOs());
|
||||
online.setStatus(session.getStatus());
|
||||
online.setSession(session);
|
||||
|
||||
return online;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ public class UserOnlineServiceImpl implements IUserOnlineService
|
|||
{
|
||||
return;
|
||||
}
|
||||
session.setTimeout(0);
|
||||
session.setTimeout(1000);
|
||||
userOnlineDao.deleteByOnlineId(sessionId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public class IndexController extends BaseController
|
|||
}
|
||||
|
||||
// 系统介绍
|
||||
@GetMapping("/main")
|
||||
@GetMapping("/system/main")
|
||||
public String main()
|
||||
{
|
||||
return "main";
|
||||
|
|
|
|||
|
|
@ -6,21 +6,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
|
||||
<resultMap type="UserOnline" id="UserOnlineResult">
|
||||
<id property="sessionId" column="sessionId" />
|
||||
<result property="userId" column="user_id" />
|
||||
<result property="loginName" column="login_name" />
|
||||
<result property="host" column="ipaddr" />
|
||||
<result property="deptName" column="dept_name" />
|
||||
<result property="roleName" column="role_name" />
|
||||
<result property="ipaddr" column="ipaddr" />
|
||||
<result property="browser" column="browser" />
|
||||
<result property="os" column="os" />
|
||||
<result property="status" column="status" />
|
||||
<result property="startTimestamp" column="start_timestsamp" />
|
||||
<result property="lastAccessTime" column="last_access_time" />
|
||||
<result property="timeout" column="timeout" />
|
||||
<result property="expireTime" column="expireTime" />
|
||||
<association property="session" javaType="OnlineSession" resultMap="OnlineSessionResult" />
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="OnlineSession" id="OnlineSessionResult">
|
||||
<result property="userId" column="user_id" />
|
||||
<result property="loginName" column="login_name" />
|
||||
<result property="host" column="ipaddr" />
|
||||
<result property="browser" column="browser" />
|
||||
<result property="os" column="os" />
|
||||
|
|
@ -34,8 +33,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
</select>
|
||||
|
||||
<insert id="saveByOnline" parameterType="UserOnline">
|
||||
replace into sys_user_online(sessionId, user_id, login_name, ipaddr, browser, os, status, start_timestsamp, last_access_time, timeout)
|
||||
values (#{sessionId}, #{userId}, #{loginName}, #{host}, #{browser}, #{os}, #{status}, #{startTimestamp}, #{lastAccessTime}, #{timeout})
|
||||
replace into sys_user_online(sessionId, login_name, dept_name, role_name, ipaddr, browser, os, status, start_timestsamp, last_access_time, expireTime)
|
||||
values (#{sessionId}, #{loginName}, #{deptName}, #{roleName}, #{ipaddr}, #{browser}, #{os}, #{status}, #{startTimestamp}, #{lastAccessTime}, #{expireTime})
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByOnlineId" parameterType="String">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
var prefix = "/sys/online"
|
||||
var prefix = "/monitor/online"
|
||||
$(function() {
|
||||
load();
|
||||
});
|
||||
|
|
@ -47,28 +47,32 @@ function load() {
|
|||
checkbox : true
|
||||
},
|
||||
{
|
||||
field : 'id', // 列字段名
|
||||
title : '序号' // 列标题
|
||||
field : 'sessionId', // 列字段名
|
||||
title : '会话编号' // 列标题
|
||||
},
|
||||
{
|
||||
field : 'username',
|
||||
title : '用户名'
|
||||
field : 'loginName',
|
||||
title : '登录名称'
|
||||
},
|
||||
{
|
||||
field : 'host',
|
||||
field : 'deptName',
|
||||
title : '部门名称'
|
||||
},
|
||||
{
|
||||
field : 'roleName',
|
||||
title : '角色名称'
|
||||
},
|
||||
{
|
||||
field : 'ipaddr',
|
||||
title : '主机'
|
||||
},
|
||||
{
|
||||
field : 'startTimestamp',
|
||||
title : '登录时间'
|
||||
field : 'browser',
|
||||
title : '浏览器'
|
||||
},
|
||||
{
|
||||
field : 'lastAccessTime',
|
||||
title : '最后访问时间'
|
||||
},
|
||||
{
|
||||
field : 'timeout',
|
||||
title : '过期时间'
|
||||
field : 'os',
|
||||
title : '操作系统'
|
||||
},
|
||||
{
|
||||
field : 'status',
|
||||
|
|
@ -82,13 +86,21 @@ function load() {
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field : 'startTimestamp',
|
||||
title : '登录时间'
|
||||
},
|
||||
{
|
||||
field : 'lastAccessTime',
|
||||
title : '最后访问时间'
|
||||
},
|
||||
{
|
||||
title : '操作',
|
||||
field : 'id',
|
||||
align : 'center',
|
||||
formatter : function(value, row, index) {
|
||||
var d = '<a class="btn btn-warning btn-sm" href="#" title="删除" mce_href="#" onclick="forceLogout(\''
|
||||
+ row.id
|
||||
var d = '<a class="btn btn-warning btn-sm" href="#" title="删除" onclick="forceLogout(\''
|
||||
+ row.sessionId
|
||||
+ '\')"><i class="fa fa-remove"></i></a> ';
|
||||
return d;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
<head th:fragment="header">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title></title>
|
||||
<meta name="keywords" content="">
|
||||
<meta name="description" content="">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link href="css/bootstrap.min.css?v=3.3.6" th:href="@{/css/bootstrap.min.css?v=3.3.6}" rel="stylesheet">
|
||||
<link href="/css/font-awesome.css?v=4.4.0" th:href="@{/css/font-awesome.css?v=4.4.0}" rel="stylesheet">
|
||||
<link href="/css/plugins/bootstrap-table/bootstrap-table.min.css" th:href="@{/css/plugins/bootstrap-table/bootstrap-table.min.css}" rel="stylesheet">
|
||||
<link href="/css/plugins/jsTree/style.min.css" rel="stylesheet">
|
||||
<link href="/css/plugins/jqTreeGrid/jquery.treegrid.css" rel="stylesheet">
|
||||
<!--summernote css -->
|
||||
<link href="/css/plugins/summernote/summernote-0.8.8.css" rel="stylesheet">
|
||||
<link href="css/animate.css" th:href="@{/css/animate.css}" rel="stylesheet">
|
||||
<link href="/css/plugins/chosen/chosen.css" rel="stylesheet">
|
||||
<link href="/css/style.css?v=4.1.0" th:href="@{/css/style.css?v=4.1.0}" rel="stylesheet">
|
||||
</head>
|
||||
<div th:fragment="footer">
|
||||
<script src="/js/jquery.min.js?v=2.1.4"></script>
|
||||
<script src="/js/bootstrap.min.js?v=3.3.6"></script>
|
||||
<script src="/js/plugins/bootstrap-table/bootstrap-table.min.js"></script>
|
||||
<script src="/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js"></script>
|
||||
<script
|
||||
src="/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
|
||||
<script src="/js/plugins/validate/jquery.validate.min.js"></script>
|
||||
<script src="/js/plugins/validate/messages_zh.min.js"></script>
|
||||
<script src="/js/plugins/jsTree/jstree.min.js"></script>
|
||||
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.min.js"></script>
|
||||
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.extension.js"></script>
|
||||
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.bootstrap3.js"></script>
|
||||
<script src="/js/plugins/chosen/chosen.jquery.js"></script>
|
||||
<script src="/js/plugins/layer/layer.js"></script>
|
||||
<script src="/js/content.js?v=1.0.0"></script>
|
||||
<!--summernote-->
|
||||
<script src="/js/plugins/summernote/summernote.js"></script>
|
||||
<script src="/js/plugins/summernote/summernote-zh-CN.min.js"></script>
|
||||
</div>
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
<li class="active">
|
||||
<a href="index.html"><i class="fa fa-home"></i> <span class="nav-label">主页</span> <span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li class="active"><a class="J_menuItem" th:href="@{/main}">了解若依</a></li>
|
||||
<li class="active"><a class="J_menuItem" th:href="@{/system/main}">了解若依</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li th:each="menu : ${menus}">
|
||||
|
|
@ -114,7 +114,7 @@
|
|||
</div>
|
||||
<div class="row J_mainContent" id="content-main">
|
||||
<iframe class="J_iframe" name="iframe0" width="100%" height="100%"
|
||||
th:src="@{/main}" frameborder="0" seamless></iframe>
|
||||
th:src="@{/system/main}" frameborder="0" seamless></iframe>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="pull-right">© 2018-2020 RuoYi Copyright</div>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
<small>移动设备访问请扫描以下二维码:</small>
|
||||
<br>
|
||||
<br>
|
||||
<img src="img/qr_code.png" width="100%" style="max-width:264px;">
|
||||
<img src="/img/qr_code.png" width="100%" style="max-width:264px;">
|
||||
<br>
|
||||
</div>
|
||||
<div class="col-sm-5">
|
||||
|
|
@ -146,7 +146,7 @@
|
|||
<br>如果图片太小,可以点击图片放大。
|
||||
</div>
|
||||
<p id="pay-qrcode">
|
||||
<a href="javascript:;"><img src="img/pay.png" width="100%" alt="请使用手机支付宝或者微信扫码支付">
|
||||
<a href="javascript:;"><img src="/img/pay.png" width="100%" alt="请使用手机支付宝或者微信扫码支付">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
|
@ -155,7 +155,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/jquery.min.js?v=2.1.4"></script>
|
||||
<script src="js/bootstrap.min.js?v=3.3.6"></script>
|
||||
<script src="/js/jquery.min.js?v=2.1.4"></script>
|
||||
<script src="/js/bootstrap.min.js?v=3.3.6"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Reference in New Issue