From 40b8ef8fade90026bbc745146543453fd91b9c57 Mon Sep 17 00:00:00 2001 From: fengshuonan Date: Sun, 2 Jul 2023 13:56:55 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=907.6.0=E3=80=91=E3=80=90sys=E3=80=91?= =?UTF-8?q?=E3=80=90loginuser=E3=80=91=E6=9B=B4=E6=96=B0=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E7=94=A8=E6=88=B7=E5=88=97=E8=A1=A8=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kernel/sys/api/SysUserServiceApi.java | 23 ++++ .../exception/enums/UserExceptionEnum.java | 7 +- .../sys/api/pojo/user/OnlineUserItem.java | 72 ++++++++++++ .../user/service/impl/SysUserServiceImpl.java | 57 +++++++++- .../controller/OnlineUserController.java | 58 ++++++++++ .../modular/login/pojo/OnlineUserResult.java | 29 +++++ .../login/service/OnlineUserService.java | 104 ++++++++++++++++++ 7 files changed, 345 insertions(+), 5 deletions(-) create mode 100644 kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/pojo/user/OnlineUserItem.java create mode 100644 kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/controller/OnlineUserController.java create mode 100644 kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/pojo/OnlineUserResult.java create mode 100644 kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/service/OnlineUserService.java diff --git a/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/SysUserServiceApi.java b/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/SysUserServiceApi.java index 31d1425eb..91ac24567 100644 --- a/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/SysUserServiceApi.java +++ b/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/SysUserServiceApi.java @@ -24,6 +24,7 @@ */ package cn.stylefeng.roses.kernel.sys.api; +import cn.stylefeng.roses.kernel.sys.api.pojo.user.OnlineUserItem; import cn.stylefeng.roses.kernel.sys.api.pojo.user.SimpleUserDTO; import cn.stylefeng.roses.kernel.sys.api.pojo.user.UserValidateDTO; @@ -94,4 +95,26 @@ public interface SysUserServiceApi { */ Boolean userExist(Long userId); + /** + * 获取用户的账号和姓名信息 + *

+ * 一般用在获取在线用户列表 + * + * @author fengshuonan + * @since 2023/7/2 13:22 + */ + OnlineUserItem getUserNameAccountInfo(Long userId); + + /** + * 获取用户账号和姓名信息 + *

+ * 一般用在获取在线用户列表 + * + * @param onlineUserItems 查询条件,在此用户id列表中查询 + * @param searchText 查询条件,查询账号或姓名包含此字符串的结果 + * @author fengshuonan + * @since 2023/7/2 13:36 + */ + List getUserNameAccountInfoListByCondition(List onlineUserItems, String searchText); + } diff --git a/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/exception/enums/UserExceptionEnum.java b/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/exception/enums/UserExceptionEnum.java index 6ed2e368e..4c37fe432 100644 --- a/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/exception/enums/UserExceptionEnum.java +++ b/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/exception/enums/UserExceptionEnum.java @@ -26,7 +26,12 @@ public enum UserExceptionEnum implements AbstractExceptionEnum { /** * 无法操作,只有超级管理员可以重置密码! */ - RESET_PASSWORD_ERROR(RuleConstants.USER_OPERATION_ERROR_TYPE_CODE + "10003", "无法操作,只有超级管理员可以重置密码!"); + RESET_PASSWORD_ERROR(RuleConstants.USER_OPERATION_ERROR_TYPE_CODE + "10003", "无法操作,只有超级管理员可以重置密码!"), + + /** + * 无法操作,只有超级管理员可以踢下线用户 + */ + KICK_OFF_ERROR(RuleConstants.USER_OPERATION_ERROR_TYPE_CODE + "10004", "无法操作,只有超级管理员可以踢下线用户"); /** * 错误编码 diff --git a/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/pojo/user/OnlineUserItem.java b/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/pojo/user/OnlineUserItem.java new file mode 100644 index 000000000..033851ae5 --- /dev/null +++ b/kernel-s-sys/sys-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/pojo/user/OnlineUserItem.java @@ -0,0 +1,72 @@ +package cn.stylefeng.roses.kernel.sys.api.pojo.user; + +import cn.stylefeng.roses.kernel.rule.annotation.ChineseDescription; +import cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import java.util.Date; + +/** + * 用在响应获取在线用户列表 + * + * @author fengshuonan + * @since 2023/7/2 11:30 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class OnlineUserItem extends BaseRequest { + + /** + * 用户主键id + */ + @ChineseDescription("用户主键id") + private Long userId; + + /** + * 用户token + */ + @ChineseDescription("用户token") + @NotBlank(message = "用户token不能为空", groups = offlineUser.class) + private String token; + + /** + * 真实姓名 + */ + @ChineseDescription("真实姓名") + private String realName; + + /** + * 账号 + */ + @ChineseDescription("账号") + private String account; + + /** + * 登录时的ip + */ + @ChineseDescription("登录时的ip") + private String loginIp; + + /** + * 登录时间 + */ + @ChineseDescription("登录时间") + private Date loginTime; + + /** + * 参数校验分组:踢下线某个token + */ + public @interface offlineUser { + } + + public OnlineUserItem() { + } + + public OnlineUserItem(Long userId, String realName, String account) { + this.userId = userId; + this.realName = realName; + this.account = account; + } +} diff --git a/kernel-s-sys/sys-business-hr/src/main/java/cn/stylefeng/roses/kernel/sys/modular/user/service/impl/SysUserServiceImpl.java b/kernel-s-sys/sys-business-hr/src/main/java/cn/stylefeng/roses/kernel/sys/modular/user/service/impl/SysUserServiceImpl.java index 7bd760f34..e792ebe53 100644 --- a/kernel-s-sys/sys-business-hr/src/main/java/cn/stylefeng/roses/kernel/sys/modular/user/service/impl/SysUserServiceImpl.java +++ b/kernel-s-sys/sys-business-hr/src/main/java/cn/stylefeng/roses/kernel/sys/modular/user/service/impl/SysUserServiceImpl.java @@ -21,6 +21,7 @@ import cn.stylefeng.roses.kernel.sys.api.constants.SysConstants; import cn.stylefeng.roses.kernel.sys.api.enums.user.UserStatusEnum; import cn.stylefeng.roses.kernel.sys.api.exception.enums.UserExceptionEnum; import cn.stylefeng.roses.kernel.sys.api.expander.SysConfigExpander; +import cn.stylefeng.roses.kernel.sys.api.pojo.user.OnlineUserItem; import cn.stylefeng.roses.kernel.sys.api.pojo.user.SimpleUserDTO; import cn.stylefeng.roses.kernel.sys.api.pojo.user.UserOrgDTO; import cn.stylefeng.roses.kernel.sys.api.pojo.user.UserValidateDTO; @@ -41,10 +42,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; /** @@ -438,6 +436,57 @@ public class SysUserServiceImpl extends ServiceImpl impl return count > 0; } + @Override + public OnlineUserItem getUserNameAccountInfo(Long userId) { + + if (userId == null) { + return new OnlineUserItem(); + } + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysUser::getUserId, userId); + wrapper.select(SysUser::getRealName, SysUser::getAccount); + SysUser sysUser = this.getOne(wrapper, false); + + return new OnlineUserItem(userId, sysUser.getRealName(), sysUser.getAccount()); + } + + @Override + public List getUserNameAccountInfoListByCondition(List onlineUserItems, String searchText) { + + if (ObjectUtil.isEmpty(onlineUserItems) || ObjectUtil.isEmpty(searchText)) { + return new ArrayList<>(); + } + + // 在线用户列表的id集合 + Set userIdList = onlineUserItems.stream().map(OnlineUserItem::getUserId).collect(Collectors.toSet()); + + // 在这些id集合和查询条件中筛选符合条件的用户,并组装上他们的姓名和账号 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(SysUser::getUserId, userIdList); + wrapper.nested(wrap -> { + wrap.like(SysUser::getRealName, searchText).or().like(SysUser::getAccount, searchText); + }); + wrapper.select(SysUser::getUserId, SysUser::getRealName, SysUser::getAccount); + List sysUserList = this.list(wrapper); + + List resultList = new ArrayList<>(); + if (ObjectUtil.isEmpty(sysUserList)) { + return resultList; + } + + Map userMap = sysUserList.stream().collect(Collectors.toMap(SysUser::getUserId, item -> item)); + + // 从在线用户中查找包含这些key的元素 + for (OnlineUserItem onlineUserItem : onlineUserItems) { + if (userMap.containsKey(onlineUserItem.getUserId())) { + resultList.add(onlineUserItem); + } + } + + return resultList; + } + /** * 获取信息 * diff --git a/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/controller/OnlineUserController.java b/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/controller/OnlineUserController.java new file mode 100644 index 000000000..0ad426988 --- /dev/null +++ b/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/controller/OnlineUserController.java @@ -0,0 +1,58 @@ +package cn.stylefeng.roses.kernel.sys.modular.login.controller; + +import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData; +import cn.stylefeng.roses.kernel.rule.pojo.response.SuccessResponseData; +import cn.stylefeng.roses.kernel.scanner.api.annotation.ApiResource; +import cn.stylefeng.roses.kernel.scanner.api.annotation.GetResource; +import cn.stylefeng.roses.kernel.sys.api.pojo.user.OnlineUserItem; +import cn.stylefeng.roses.kernel.sys.modular.login.pojo.OnlineUserResult; +import cn.stylefeng.roses.kernel.sys.modular.login.service.OnlineUserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * 获取用户在线信息的接口 + * + * @author fengshuonan + * @since 2023/7/2 11:25 + */ +@RestController +@Slf4j +@ApiResource(name = "获取用户在线信息的接口") +public class OnlineUserController { + + @Resource + private OnlineUserService onlineUserService; + + /** + * 获取在线用户列表 + * + * @param searchText 查询条件,可以根据用户姓名和账号进行查询 + * @author fengshuonan + * @since 2023/7/2 11:26 + */ + @GetResource(name = "获取在线用户列表", path = "/getOnlineUserList") + public ResponseData getOnlineUserList(@RequestParam(value = "searchText", required = false) String searchText) { + OnlineUserResult result = onlineUserService.getOnlineUserList(searchText); + return new SuccessResponseData<>(result); + } + + /** + * 踢掉在线的某个人token + * + * @param onlineUserInfo 请求参数 + * @author fengshuonan + * @since 2023/7/2 11:26 + */ + @GetResource(name = "获取在线用户列表", path = "/offlineUser") + public ResponseData offlineUser(@RequestBody @Validated(OnlineUserItem.offlineUser.class) OnlineUserItem onlineUserInfo) { + onlineUserService.offlineUser(onlineUserInfo); + return new SuccessResponseData<>(); + } + +} diff --git a/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/pojo/OnlineUserResult.java b/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/pojo/OnlineUserResult.java new file mode 100644 index 000000000..71d65c7a8 --- /dev/null +++ b/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/pojo/OnlineUserResult.java @@ -0,0 +1,29 @@ +package cn.stylefeng.roses.kernel.sys.modular.login.pojo; + +import cn.stylefeng.roses.kernel.rule.annotation.ChineseDescription; +import cn.stylefeng.roses.kernel.sys.api.pojo.user.OnlineUserItem; +import lombok.Data; + +import java.util.List; + +/** + * 在线用户的返回结果 + * + * @author fengshuonan + * @since 2023/7/2 12:29 + */ +@Data +public class OnlineUserResult { + + /** + * 总的在线用户数 + */ + private Integer totalUserCount = 0; + + /** + * 用户在线列表人数 + */ + @ChineseDescription("用户在线列表人数") + private List onlineUserList; + +} diff --git a/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/service/OnlineUserService.java b/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/service/OnlineUserService.java new file mode 100644 index 000000000..b96256b66 --- /dev/null +++ b/kernel-s-sys/sys-business-permission/src/main/java/cn/stylefeng/roses/kernel/sys/modular/login/service/OnlineUserService.java @@ -0,0 +1,104 @@ +package cn.stylefeng.roses.kernel.sys.modular.login.service; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi; +import cn.stylefeng.roses.kernel.auth.api.context.LoginContext; +import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser; +import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException; +import cn.stylefeng.roses.kernel.sys.api.SysUserServiceApi; +import cn.stylefeng.roses.kernel.sys.api.exception.enums.UserExceptionEnum; +import cn.stylefeng.roses.kernel.sys.api.pojo.user.OnlineUserItem; +import cn.stylefeng.roses.kernel.sys.modular.login.pojo.OnlineUserResult; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +/** + * 获取用户在线登录信息业务 + * + * @author fengshuonan + * @since 2023/7/2 11:25 + */ +@Service +public class OnlineUserService { + + @Resource + private SessionManagerApi sessionManagerApi; + + @Resource + private SysUserServiceApi sysUserServiceApi; + + /** + * 获取当前在线用户列表 + *

+ * 可以根据用户名称和账号进行查询 + * + * @author fengshuonan + * @since 2023/7/2 12:09 + */ + public OnlineUserResult getOnlineUserList(String searchText) { + + OnlineUserResult onlineUserResult = new OnlineUserResult(); + + List loginUsers = sessionManagerApi.onlineUserList(); + if (ObjectUtil.isEmpty(loginUsers)) { + return new OnlineUserResult(); + } + + // 返回总的在线人数 + onlineUserResult.setTotalUserCount(loginUsers.size()); + + // 转化为用户的在线信息 + List onlineUserInfos = new ArrayList<>(); + for (LoginUser loginUser : loginUsers) { + OnlineUserItem onlineUserInfo = new OnlineUserItem(); + onlineUserInfo.setUserId(loginUser.getUserId()); + onlineUserInfo.setToken(loginUser.getToken()); + onlineUserInfos.add(onlineUserInfo); + } + + // 如果没传查询条件,只返回前10条 + if (StrUtil.isBlank(searchText)) { + if (onlineUserInfos.size() > 10) { + onlineUserInfos = onlineUserInfos.subList(0, 9); + } + + // 用户信息补充姓名和账号返回 + for (OnlineUserItem onlineUserInfo : onlineUserInfos) { + OnlineUserItem userNameAccountInfo = sysUserServiceApi.getUserNameAccountInfo(onlineUserInfo.getUserId()); + onlineUserInfo.setAccount(userNameAccountInfo.getAccount()); + onlineUserInfo.setRealName(userNameAccountInfo.getRealName()); + } + + onlineUserResult.setOnlineUserList(onlineUserInfos); + return onlineUserResult; + } + + // 如果传递了查询条件,则从在线用户id和指定查询条件中筛选出来结果 + else { + List resultUserList = sysUserServiceApi.getUserNameAccountInfoListByCondition(onlineUserInfos, searchText); + onlineUserResult.setOnlineUserList(resultUserList); + return onlineUserResult; + } + } + + /** + * 踢下线某个用户,根据参数中的token + * + * @author fengshuonan + * @since 2023/7/2 12:23 + */ + public void offlineUser(OnlineUserItem onlineUserInfo) throws ServiceException { + + if (!LoginContext.me().getSuperAdminFlag()) { + throw new ServiceException(UserExceptionEnum.KICK_OFF_ERROR); + } + + sessionManagerApi.removeSession(onlineUserInfo.getToken()); + + } + +}