refactor: 使用事件解耦业务副作用并优化虚拟线程并发
- 新增登录成功事件,解耦在线用户缓存、登录日志和最近登录信息更新 - 新增在线用户清理事件,角色授权变更后异步清理受影响用户会话 - 新增 OSS 配置变更事件,统一处理配置初始化、删除和默认配置切换后的缓存刷新 - 新增工作流抄送、待办消息、结果消息事件,拆分全局监听器中的副作用逻辑 - 扩展 ThreadUtils 支持带返回值的虚拟线程批量执行 - 在线用户监控批量读取 Redis 会话信息时使用虚拟线程并发处理 - OSS 多文件查询、URL 解析和 DTO 转换使用虚拟线程并发处理 - 工作流办理人回显和用户解析按类型并发查询 - 工作流多渠道消息发送改为并发执行 - WebSocket 与 SSE 广播消息按用户并发发送
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package org.dromara.auth.event;
|
||||
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
|
||||
/**
|
||||
* 用户登录成功事件。
|
||||
*
|
||||
* @param loginId 登录标识
|
||||
* @param tokenValue token 值
|
||||
* @param loginParameter 登录参数
|
||||
*/
|
||||
public record UserLoginSuccessEvent(Object loginId, String tokenValue, SaLoginParameter loginParameter) {
|
||||
}
|
||||
@@ -1,79 +1,30 @@
|
||||
package org.dromara.auth.listener;
|
||||
|
||||
import cn.dev33.satoken.listener.SaTokenListener;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.http.useragent.UserAgent;
|
||||
import cn.hutool.http.useragent.UserAgentUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.dromara.common.core.constant.CacheNames;
|
||||
import org.dromara.common.core.constant.Constants;
|
||||
import org.dromara.common.core.utils.MessageUtils;
|
||||
import org.dromara.common.core.utils.ServletUtils;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.utils.ip.AddressUtils;
|
||||
import org.dromara.common.log.event.LoginInfoEvent;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.resource.api.RemoteMessageService;
|
||||
import org.dromara.system.api.RemoteUserService;
|
||||
import org.dromara.system.api.domain.SysUserOnline;
|
||||
import org.dromara.auth.event.UserLoginSuccessEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* 用户行为 侦听器的实现
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@Slf4j
|
||||
public class UserActionListener implements SaTokenListener {
|
||||
|
||||
@DubboReference
|
||||
private RemoteUserService remoteUserService;
|
||||
@DubboReference
|
||||
private RemoteMessageService remoteMessageService;
|
||||
|
||||
/**
|
||||
* 每次登录时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) {
|
||||
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
|
||||
String ip = ServletUtils.getClientIP();
|
||||
SysUserOnline userOnline = new SysUserOnline();
|
||||
userOnline.setIpaddr(ip);
|
||||
userOnline.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
|
||||
userOnline.setBrowser(userAgent.getBrowser().getName());
|
||||
userOnline.setOs(userAgent.getOs().getName());
|
||||
userOnline.setLoginTime(System.currentTimeMillis());
|
||||
userOnline.setTokenId(tokenValue);
|
||||
String username = (String) loginParameter.getExtra(LoginHelper.USER_NAME_KEY);
|
||||
userOnline.setUserName(username);
|
||||
userOnline.setClientKey((String) loginParameter.getExtra(LoginHelper.CLIENT_KEY));
|
||||
userOnline.setDeviceType(loginParameter.getDeviceType());
|
||||
userOnline.setDeptName((String) loginParameter.getExtra(LoginHelper.DEPT_NAME_KEY));
|
||||
if (loginParameter.getTimeout() == -1) {
|
||||
RedisUtils.setCacheObject(CacheNames.ONLINE_TOKEN_KEY + tokenValue, userOnline);
|
||||
} else {
|
||||
RedisUtils.setCacheObject(CacheNames.ONLINE_TOKEN_KEY + tokenValue, userOnline, Duration.ofSeconds(loginParameter.getTimeout()));
|
||||
}
|
||||
// 记录登录日志
|
||||
LoginInfoEvent loginInfoEvent = new LoginInfoEvent();
|
||||
loginInfoEvent.setUsername(username);
|
||||
loginInfoEvent.setStatus(Constants.LOGIN_SUCCESS);
|
||||
loginInfoEvent.setMessage(MessageUtils.message("user.login.success"));
|
||||
SpringUtils.context().publishEvent(loginInfoEvent);
|
||||
// 更新登录信息
|
||||
remoteUserService.recordLoginInfo((Long) loginParameter.getExtra(LoginHelper.USER_KEY), ip);
|
||||
log.info("user doLogin, useId:{}, token:***{}", loginId, StringUtils.right(tokenValue, 8));
|
||||
SpringUtils.context().publishEvent(new UserLoginSuccessEvent(loginId, tokenValue, loginParameter));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.dromara.auth.listener;
|
||||
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
import cn.hutool.http.useragent.UserAgent;
|
||||
import cn.hutool.http.useragent.UserAgentUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.dromara.auth.event.UserLoginSuccessEvent;
|
||||
import org.dromara.common.core.constant.CacheNames;
|
||||
import org.dromara.common.core.constant.Constants;
|
||||
import org.dromara.common.core.utils.MessageUtils;
|
||||
import org.dromara.common.core.utils.ServletUtils;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.utils.ip.AddressUtils;
|
||||
import org.dromara.common.log.event.LoginInfoEvent;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.system.api.RemoteUserService;
|
||||
import org.dromara.system.api.domain.SysUserOnline;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* 用户登录成功监听器。
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class UserLoginSuccessListener {
|
||||
|
||||
@DubboReference
|
||||
private RemoteUserService remoteUserService;
|
||||
|
||||
/**
|
||||
* 登录成功后记录在线信息、登录日志与最近登录信息。
|
||||
*
|
||||
* @param event 用户登录成功事件
|
||||
*/
|
||||
@EventListener
|
||||
public void handleLoginSuccess(UserLoginSuccessEvent event) {
|
||||
SaLoginParameter loginParameter = event.loginParameter();
|
||||
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
|
||||
String ip = ServletUtils.getClientIP();
|
||||
String username = (String) loginParameter.getExtra(LoginHelper.USER_NAME_KEY);
|
||||
String tokenValue = event.tokenValue();
|
||||
|
||||
SysUserOnline userOnline = new SysUserOnline();
|
||||
userOnline.setIpaddr(ip);
|
||||
userOnline.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
|
||||
userOnline.setBrowser(userAgent.getBrowser().getName());
|
||||
userOnline.setOs(userAgent.getOs().getName());
|
||||
userOnline.setLoginTime(System.currentTimeMillis());
|
||||
userOnline.setTokenId(tokenValue);
|
||||
userOnline.setUserName(username);
|
||||
userOnline.setClientKey((String) loginParameter.getExtra(LoginHelper.CLIENT_KEY));
|
||||
userOnline.setDeviceType(loginParameter.getDeviceType());
|
||||
userOnline.setDeptName((String) loginParameter.getExtra(LoginHelper.DEPT_NAME_KEY));
|
||||
if (loginParameter.getTimeout() == -1) {
|
||||
RedisUtils.setCacheObject(CacheNames.ONLINE_TOKEN_KEY + tokenValue, userOnline);
|
||||
} else {
|
||||
RedisUtils.setCacheObject(CacheNames.ONLINE_TOKEN_KEY + tokenValue, userOnline, Duration.ofSeconds(loginParameter.getTimeout()));
|
||||
}
|
||||
|
||||
LoginInfoEvent loginInfoEvent = new LoginInfoEvent();
|
||||
loginInfoEvent.setUsername(username);
|
||||
loginInfoEvent.setStatus(Constants.LOGIN_SUCCESS);
|
||||
loginInfoEvent.setMessage(MessageUtils.message("user.login.success"));
|
||||
SpringUtils.context().publishEvent(loginInfoEvent);
|
||||
|
||||
remoteUserService.recordLoginInfo((Long) loginParameter.getExtra(LoginHelper.USER_KEY), ip);
|
||||
log.info("user doLogin, userId:{}, token:***{}", event.loginId(), StringUtils.right(tokenValue, 8));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user