Commit 5b723d02b23f7be2dd78760892af19228ad85e01

Authored by YunaiV
1 parent e999cc31

增加 yudao-core-service 模块,提供共享逻辑

Showing 50 changed files with 761 additions and 408 deletions
... ... @@ -12,6 +12,7 @@
12 12 <module>yudao-framework</module>
13 13 <module>yudao-admin-server</module>
14 14 <module>yudao-user-server</module>
  15 + <module>yudao-core-service</module>
15 16 </modules>
16 17  
17 18 <name>${artifactId}</name>
... ...
yudao-admin-server/pom.xml
... ... @@ -20,6 +20,11 @@
20 20 <!-- 业务组件 -->
21 21 <dependency>
22 22 <groupId>cn.iocoder.boot</groupId>
  23 + <artifactId>yudao-core-service</artifactId>
  24 + </dependency>
  25 +
  26 + <dependency>
  27 + <groupId>cn.iocoder.boot</groupId>
23 28 <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
24 29 </dependency>
25 30 <dependency>
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/AdminServerApplication.java
... ... @@ -3,7 +3,8 @@ package cn.iocoder.yudao.adminserver;
3 3 import org.springframework.boot.SpringApplication;
4 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 5  
6   -@SpringBootApplication
  6 +@SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} 和 ${yudao.core-service.base-package}
  7 +@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"})
7 8 public class AdminServerApplication {
8 9  
9 10 public static void main(String[] args) {
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysUserSessionController.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.controller.auth;
2 2  
  3 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
  4 +import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
3 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 7 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO;
6 8 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
7 9 import cn.iocoder.yudao.adminserver.modules.system.convert.auth.SysUserSessionConvert;
8   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth.SysUserSessionDO;
9 10 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
10 11 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
11 12 import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
... ... @@ -35,6 +36,8 @@ public class SysUserSessionController {
35 36 @Resource
36 37 private SysUserSessionService userSessionService;
37 38 @Resource
  39 + private SysUserSessionCoreService userSessionCoreService;
  40 + @Resource
38 41 private SysUserService userService;
39 42 @Resource
40 43 private SysDeptService deptService;
... ... @@ -72,7 +75,7 @@ public class SysUserSessionController {
72 75 example = "fe50b9f6-d177-44b1-8da9-72ea34f63db7")
73 76 @PreAuthorize("@ss.hasPermission('system:user-session:delete')")
74 77 public CommonResult<Boolean> deleteUserSession(@RequestParam("id") String id) {
75   - userSessionService.deleteUserSession(id);
  78 + userSessionCoreService.deleteUserSession(id);
76 79 return success(true);
77 80 }
78 81  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/auth/SysAuthConvert.java
... ... @@ -10,6 +10,7 @@ import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.Sys
10 10 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO;
11 11 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
12 12 import cn.iocoder.yudao.adminserver.modules.system.enums.permission.MenuIdEnum;
  13 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
13 14 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
14 15 import cn.iocoder.yudao.framework.security.core.LoginUser;
15 16 import me.zhyd.oauth.model.AuthCallback;
... ... @@ -27,7 +28,12 @@ public interface SysAuthConvert {
27 28  
28 29 @Mapping(source = "updateTime", target = "updateTime", ignore = true)
29 30 // 字段相同,但是含义不同,忽略
30   - LoginUser convert(SysUserDO bean);
  31 + LoginUser convert0(SysUserDO bean);
  32 +
  33 + default LoginUser convert(SysUserDO bean) {
  34 + // 目的,为了设置 UserTypeEnum.ADMIN.getValue()
  35 + return convert0(bean).setUserType(UserTypeEnum.ADMIN.getValue());
  36 + }
31 37  
32 38 default SysAuthPermissionInfoRespVO convert(SysUserDO user, List<SysRoleDO> roleList, List<SysMenuDO> menuList) {
33 39 return SysAuthPermissionInfoRespVO.builder()
... ... @@ -39,10 +45,6 @@ public interface SysAuthConvert {
39 45  
40 46 SysAuthMenuRespVO convertTreeNode(SysMenuDO menu);
41 47  
42   - LoginUser convert(SysUserProfileUpdateReqVO reqVO);
43   -
44   - LoginUser convert(SysUserProfileUpdatePasswordReqVO reqVO);
45   -
46 48 /**
47 49 * 将菜单列表,构建成菜单树
48 50 *
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/auth/SysUserSessionConvert.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.convert.auth;
2 2  
3 3 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO;
4   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth.SysUserSessionDO;
  4 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
5 5 import org.mapstruct.Mapper;
6 6 import org.mapstruct.factory.Mappers;
7 7  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/auth/SysUserSessionMapper.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.auth;
2 2  
  3 +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
  4 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
3 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 7 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
6   -import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
7   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth.SysUserSessionDO;
8 8 import org.apache.ibatis.annotations.Mapper;
9 9  
10 10 import java.util.Collection;
... ... @@ -23,4 +23,5 @@ public interface SysUserSessionMapper extends BaseMapperX&lt;SysUserSessionDO&gt; {
23 23 default List<SysUserSessionDO> selectListBySessionTimoutLt() {
24 24 return selectList(new QueryWrapperX<SysUserSessionDO>().lt("session_timeout",new Date()));
25 25 }
  26 +
26 27 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/RedisKeyConstants.java deleted
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/SysRedisKeyConstants.java
... ... @@ -15,10 +15,6 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S
15 15 */
16 16 public interface SysRedisKeyConstants {
17 17  
18   - RedisKeyDefine LOGIN_USER = new RedisKeyDefine("登录用户的缓存",
19   - "login_user:%s", // 参数为 sessionId
20   - STRING, LoginUser.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
21   -
22 18 RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("验证码的缓存",
23 19 "captcha_code:%s", // 参数为 uuid
24 20 STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysUserSessionService.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.service.auth;
2 2  
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.framework.security.core.LoginUser;
5 3 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
6   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth.SysUserSessionDO;
  4 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 6  
8 7 /**
9 8 * 在线用户 Session Service 接口
... ... @@ -13,46 +12,6 @@ import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth.SysUserSe
13 12 public interface SysUserSessionService {
14 13  
15 14 /**
16   - * 创建在线用户 Session
17   - *
18   - * @param loginUser 登录用户
19   - * @param userIp 用户 IP
20   - * @param userAgent 用户 UA
21   - * @return Session 编号
22   - */
23   - String createUserSession(LoginUser loginUser, String userIp, String userAgent);
24   -
25   - /**
26   - * 刷新在线用户 Session 的更新时间
27   - *
28   - * @param sessionId Session 编号
29   - * @param loginUser 登录用户
30   - */
31   - void refreshUserSession(String sessionId, LoginUser loginUser);
32   -
33   - /**
34   - * 删除在线用户 Session
35   - *
36   - * @param sessionId Session 编号
37   - */
38   - void deleteUserSession(String sessionId);
39   -
40   - /**
41   - * 获得 Session 编号对应的在线用户
42   - *
43   - * @param sessionId Session 编号
44   - * @return 在线用户
45   - */
46   - LoginUser getLoginUser(String sessionId);
47   -
48   - /**
49   - * 获得 Session 超时时间,单位:毫秒
50   - *
51   - * @return 超时时间
52   - */
53   - Long getSessionTimeoutMillis();
54   -
55   - /**
56 15 * 获得在线用户分页列表
57 16 *
58 17 * @param reqVO 分页条件
... ... @@ -66,4 +25,5 @@ public interface SysUserSessionService {
66 25 * @return {@link Long } 移出的超时用户数量
67 26 **/
68 27 long clearSessionTimeout();
  28 +
69 29 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
... ... @@ -11,13 +11,13 @@ import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO
11 11 import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginLogTypeEnum;
12 12 import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginResultEnum;
13 13 import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysAuthService;
14   -import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
15 14 import cn.iocoder.yudao.adminserver.modules.system.service.common.SysCaptchaService;
16 15 import cn.iocoder.yudao.adminserver.modules.system.service.logger.SysLoginLogService;
17 16 import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
18 17 import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
19 18 import cn.iocoder.yudao.adminserver.modules.system.service.social.SysSocialService;
20 19 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
  20 +import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
21 21 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
22 22 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
23 23 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
... ... @@ -67,7 +67,7 @@ public class SysAuthServiceImpl implements SysAuthService {
67 67 @Resource
68 68 private SysLoginLogService loginLogService;
69 69 @Resource
70   - private SysUserSessionService userSessionService;
  70 + private SysUserSessionCoreService userSessionCoreService;
71 71 @Resource
72 72 private SysSocialService socialService;
73 73  
... ... @@ -107,7 +107,7 @@ public class SysAuthServiceImpl implements SysAuthService {
107 107 loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
108 108  
109 109 // 缓存登录用户到 Redis 中,返回 sessionId 编号
110   - return userSessionService.createUserSession(loginUser, userIp, userAgent);
  110 + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
111 111 }
112 112  
113 113 private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
... ... @@ -214,7 +214,7 @@ public class SysAuthServiceImpl implements SysAuthService {
214 214 socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser);
215 215  
216 216 // 缓存登录用户到 Redis 中,返回 sessionId 编号
217   - return userSessionService.createUserSession(loginUser, userIp, userAgent);
  217 + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
218 218 }
219 219  
220 220 @Override
... ... @@ -231,7 +231,7 @@ public class SysAuthServiceImpl implements SysAuthService {
231 231 socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser);
232 232  
233 233 // 缓存登录用户到 Redis 中,返回 sessionId 编号
234   - return userSessionService.createUserSession(loginUser, userIp, userAgent);
  234 + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
235 235 }
236 236  
237 237 @Override
... ... @@ -247,12 +247,12 @@ public class SysAuthServiceImpl implements SysAuthService {
247 247 @Override
248 248 public void logout(String token) {
249 249 // 查询用户信息
250   - LoginUser loginUser = userSessionService.getLoginUser(token);
  250 + LoginUser loginUser = userSessionCoreService.getLoginUser(token);
251 251 if (loginUser == null) {
252 252 return;
253 253 }
254 254 // 删除 session
255   - userSessionService.deleteUserSession(token);
  255 + userSessionCoreService.deleteUserSession(token);
256 256 // 记录登出日子和
257 257 this.createLogoutLog(loginUser.getUsername());
258 258 }
... ... @@ -271,7 +271,7 @@ public class SysAuthServiceImpl implements SysAuthService {
271 271 @Override
272 272 public LoginUser verifyTokenAndRefresh(String token) {
273 273 // 获得 LoginUser
274   - LoginUser loginUser = userSessionService.getLoginUser(token);
  274 + LoginUser loginUser = userSessionCoreService.getLoginUser(token);
275 275 if (loginUser == null) {
276 276 return null;
277 277 }
... ... @@ -283,7 +283,7 @@ public class SysAuthServiceImpl implements SysAuthService {
283 283 private void refreshLoginUserCache(String token, LoginUser loginUser) {
284 284 // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存
285 285 if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() <
286   - userSessionService.getSessionTimeoutMillis() / 3) {
  286 + userSessionCoreService.getSessionTimeoutMillis() / 3) {
287 287 return;
288 288 }
289 289  
... ... @@ -296,7 +296,7 @@ public class SysAuthServiceImpl implements SysAuthService {
296 296 // 刷新 LoginUser 缓存
297 297 loginUser.setDeptId(user.getDeptId());
298 298 loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
299   - userSessionService.refreshUserSession(token, loginUser);
  299 + userSessionCoreService.refreshUserSession(token, loginUser);
300 300 }
301 301  
302 302 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysUserSessionServiceImpl.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.service.auth.impl;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.util.IdUtil;
5 4 import cn.hutool.core.util.StrUtil;
6 5 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
7   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth.SysUserSessionDO;
8 6 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
9 7 import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.auth.SysUserSessionMapper;
10   -import cn.iocoder.yudao.adminserver.modules.system.dal.redis.auth.SysLoginUserRedisDAO;
11 8 import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginLogTypeEnum;
12 9 import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginResultEnum;
13 10 import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
14 11 import cn.iocoder.yudao.adminserver.modules.system.service.logger.SysLoginLogService;
15 12 import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
16 13 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
17   -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  14 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
  15 +import cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth.SysLoginUserCoreRedisDAO;
18 16 import cn.iocoder.yudao.framework.common.pojo.PageResult;
19 17 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
20   -import cn.iocoder.yudao.framework.security.config.SecurityProperties;
21   -import cn.iocoder.yudao.framework.security.core.LoginUser;
22 18 import com.google.common.collect.Lists;
23 19 import lombok.extern.slf4j.Slf4j;
24 20 import org.springframework.stereotype.Service;
25 21  
26 22 import javax.annotation.Resource;
27   -import java.time.Duration;
28   -import java.util.*;
  23 +import java.util.ArrayList;
  24 +import java.util.Collection;
  25 +import java.util.List;
  26 +import java.util.Map;
29 27 import java.util.stream.Collectors;
30 28  
31 29 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
32   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
33 30  
34 31 /**
35 32 * 在线用户 Session Service 实现类
... ... @@ -41,64 +38,14 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
41 38 public class SysUserSessionServiceImpl implements SysUserSessionService {
42 39  
43 40 @Resource
44   - private SecurityProperties securityProperties;
45   - @Resource
46   - private SysLoginUserRedisDAO loginUserRedisDAO;
47   - @Resource
48 41 private SysUserSessionMapper userSessionMapper;
49 42 @Resource
50 43 private SysUserService userService;
51 44 @Resource
52 45 private SysLoginLogService loginLogService;
53 46  
54   - @Override
55   - public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
56   - // 生成 Session 编号
57   - String sessionId = generateSessionId();
58   - // 写入 Redis 缓存
59   - loginUser.setUpdateTime(new Date());
60   - loginUserRedisDAO.set(sessionId, loginUser);
61   - // 写入 DB 中
62   - SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
63   - .userId(loginUser.getId()).userType(UserTypeEnum.ADMIN.getValue())
64   - .userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
65   - .sessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())))
66   - .build();
67   - userSessionMapper.insert(userSession);
68   - // 返回 Session 编号
69   - return sessionId;
70   - }
71   -
72   - @Override
73   - public void refreshUserSession(String sessionId, LoginUser loginUser) {
74   - // 写入 Redis 缓存
75   - loginUser.setUpdateTime(new Date());
76   - loginUserRedisDAO.set(sessionId, loginUser);
77   - // 更新 DB 中
78   - SysUserSessionDO updateObj = SysUserSessionDO.builder().id(sessionId).build();
79   - updateObj.setUsername(loginUser.getUsername());
80   - updateObj.setUpdateTime(new Date());
81   - updateObj.setSessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())));
82   - userSessionMapper.updateById(updateObj);
83   - }
84   -
85   - @Override
86   - public void deleteUserSession(String sessionId) {
87   - // 删除 Redis 缓存
88   - loginUserRedisDAO.delete(sessionId);
89   - // 删除 DB 记录
90   - userSessionMapper.deleteById(sessionId);
91   - }
92   -
93   - @Override
94   - public LoginUser getLoginUser(String sessionId) {
95   - return loginUserRedisDAO.get(sessionId);
96   - }
97   -
98   - @Override
99   - public Long getSessionTimeoutMillis() {
100   - return securityProperties.getSessionTimeout().toMillis();
101   - }
  47 + @Resource
  48 + private SysLoginUserCoreRedisDAO loginUserCoreRedisDAO;
102 49  
103 50 @Override
104 51 public PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO) {
... ... @@ -113,18 +60,20 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
113 60 return userSessionMapper.selectPage(reqVO, userIds);
114 61 }
115 62  
  63 + // TODO @芋艿:优化下该方法
116 64 @Override
117 65 public long clearSessionTimeout() {
118 66 // 获取db里已经超时的用户列表
119 67 List<SysUserSessionDO> sessionTimeoutDOS = userSessionMapper.selectListBySessionTimoutLt();
120 68 Map<String, SysUserSessionDO> timeoutSessionDOMap = sessionTimeoutDOS
121 69 .stream()
122   - .filter(sessionDO -> loginUserRedisDAO.get(sessionDO.getId()) == null)
  70 + .filter(sessionDO -> loginUserCoreRedisDAO.get(sessionDO.getId()) == null)
123 71 .collect(Collectors.toMap(SysUserSessionDO::getId, o -> o));
124 72 // 确认已经超时,按批次移出在线用户列表
125 73 if (CollUtil.isNotEmpty(timeoutSessionDOMap)) {
126   - Lists.partition(new ArrayList<>(timeoutSessionDOMap.keySet()), 100).forEach(userSessionMapper::deleteBatchIds);
127   - //记录用户超时退出日志
  74 + Lists.partition(new ArrayList<>(timeoutSessionDOMap.keySet()), 100)
  75 + .forEach(userSessionMapper::deleteBatchIds);
  76 + // 记录用户超时退出日志
128 77 createTimeoutLogoutLog(timeoutSessionDOMap.values());
129 78 }
130 79 return timeoutSessionDOMap.size();
... ... @@ -143,13 +92,4 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
143 92 }
144 93 }
145 94  
146   - /**
147   - * 生成 Session 编号,目前采用 UUID 算法
148   - *
149   - * @return Session 编号
150   - */
151   - private static String generateSessionId() {
152   - return IdUtil.fastSimpleUUID();
153   - }
154   -
155 95 }
... ...
yudao-admin-server/src/main/resources/application.yaml
... ... @@ -31,7 +31,7 @@ mybatis-plus:
31 31 logic-delete-value: 1 # 逻辑已删除值(默认为 1)
32 32 logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
33 33 mapper-locations: classpath*:mapper/*.xml
34   - type-aliases-package: ${yudao.info.base-package}.modules.*.dal.dataobject
  34 + type-aliases-package: ${yudao.info.base-package}.modules.*.dal.dataobject, ${yudao.core-service.base-package}.modules.*.dal.dataobject
35 35  
36 36 --- #################### 芋道相关配置 ####################
37 37  
... ... @@ -39,6 +39,8 @@ yudao:
39 39 info:
40 40 version: 1.0.0
41 41 base-package: cn.iocoder.yudao.adminserver
  42 + core-service:
  43 + base-package: cn.iocoder.yudao.coreservice
42 44 web:
43 45 api-prefix: /api
44 46 controller-package: ${yudao.info.base-package}
... ...
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/BaseRedisUnitTest.java
... ... @@ -24,7 +24,7 @@ public class BaseRedisUnitTest {
24 24 // Redis 配置类
25 25 RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
26 26 RedisAutoConfiguration.class, // Spring Redis 自动配置类
27   - YudaoTracerAutoConfiguration.class, // 自己的 Redis 配置类
  27 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
28 28 RedissonAutoConfiguration.class, // Redisson 自动高配置类
29 29 })
30 30 public static class Application {
... ...
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileServiceTest.java
... ... @@ -10,6 +10,7 @@ import cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.file.InfFileMapper;
10 10 import cn.iocoder.yudao.adminserver.modules.infra.service.file.impl.InfFileServiceImpl;
11 11 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
12 12 import org.junit.jupiter.api.Test;
  13 +import org.springframework.boot.test.mock.mockito.MockBean;
13 14 import org.springframework.context.annotation.Import;
14 15  
15 16 import javax.annotation.Resource;
... ... @@ -29,8 +30,9 @@ public class InfFileServiceTest extends BaseDbUnitTest {
29 30 @Resource
30 31 private InfFileServiceImpl fileService;
31 32  
32   - @Resource
  33 + @MockBean
33 34 private FileProperties fileProperties;
  35 +
34 36 @Resource
35 37 private InfFileMapper fileMapper;
36 38  
... ...
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthServiceImplTest.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.service.auth;
2 2  
3 3 import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.adminserver.modules.system.service.social.SysSocialService;
  5 +import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
4 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 7 import cn.iocoder.yudao.framework.security.core.LoginUser;
6 8 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO;
... ... @@ -59,7 +61,9 @@ public class SysAuthServiceImplTest extends BaseDbUnitTest {
59 61 @MockBean
60 62 private SysLoginLogService loginLogService;
61 63 @MockBean
62   - private SysUserSessionService userSessionService;
  64 + private SysUserSessionCoreService userSessionCoreService;
  65 + @MockBean
  66 + private SysSocialService socialService;
63 67  
64 68 @Test
65 69 public void testLoadUserByUsername_success() {
... ... @@ -237,7 +241,7 @@ public class SysAuthServiceImplTest extends BaseDbUnitTest {
237 241 // mock 获得 User 拥有的角色编号数组
238 242 when(permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()))).thenReturn(userRoleIds);
239 243 // mock 缓存登录用户到 Redis
240   - when(userSessionService.createUserSession(loginUser, userIp, userAgent)).thenReturn(sessionId);
  244 + when(userSessionCoreService.createUserSession(loginUser, userIp, userAgent)).thenReturn(sessionId);
241 245 // 调用, 并断言异常
242 246 String login = authService.login(reqVO, userIp, userAgent);
243 247 assertEquals(sessionId, login);
... ... @@ -255,11 +259,11 @@ public class SysAuthServiceImplTest extends BaseDbUnitTest {
255 259 String token = randomString();
256 260 LoginUser loginUser = randomPojo(LoginUser.class);
257 261 // mock
258   - when(userSessionService.getLoginUser(token)).thenReturn(loginUser);
  262 + when(userSessionCoreService.getLoginUser(token)).thenReturn(loginUser);
259 263 // 调用
260 264 authService.logout(token);
261 265 // 校验调用参数
262   - verify(userSessionService, times(1)).deleteUserSession(token);
  266 + verify(userSessionCoreService, times(1)).deleteUserSession(token);
263 267 verify(loginLogService, times(1)).createLoginLog(
264 268 argThat(o -> o.getLogType().equals(SysLoginLogTypeEnum.LOGOUT_SELF.getType())
265 269 && o.getResult().equals(SysLoginResultEnum.SUCCESS.getResult()))
... ...
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysUserSessionServiceImplTest.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.service.auth;
2 2  
3   -import static cn.hutool.core.util.RandomUtil.randomEle;
4   -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
5   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomDate;
6   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
7   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
8   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
9   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
10   -import static org.junit.jupiter.api.Assertions.assertEquals;
11   -import static org.junit.jupiter.api.Assertions.assertNotEquals;
12   -import static org.junit.jupiter.api.Assertions.assertNotNull;
13   -import static org.junit.jupiter.api.Assertions.assertNull;
14   -import static org.mockito.Mockito.when;
15   -
16   -import java.time.Duration;
17   -import java.util.Date;
18   -import java.util.List;
19   -import java.util.stream.Collectors;
20   -import java.util.stream.Stream;
21   -
22   -import javax.annotation.Resource;
23   -
24   -import org.junit.jupiter.api.Test;
25   -import org.springframework.boot.test.mock.mockito.MockBean;
26   -import org.springframework.context.annotation.Import;
27   -
28 3 import cn.hutool.core.date.DateUtil;
29 4 import cn.iocoder.yudao.adminserver.BaseDbAndRedisUnitTest;
30   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
31   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
32   -import cn.iocoder.yudao.framework.security.config.SecurityProperties;
33   -import cn.iocoder.yudao.framework.security.core.LoginUser;
34 5 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
35   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth.SysUserSessionDO;
36 6 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
37 7 import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.auth.SysUserSessionMapper;
38 8 import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.user.SysUserMapper;
39   -import cn.iocoder.yudao.adminserver.modules.system.dal.redis.auth.SysLoginUserRedisDAO;
40 9 import cn.iocoder.yudao.adminserver.modules.system.enums.common.SysSexEnum;
41 10 import cn.iocoder.yudao.adminserver.modules.system.service.auth.impl.SysUserSessionServiceImpl;
42   -import cn.iocoder.yudao.adminserver.modules.system.service.dept.impl.SysDeptServiceImpl;
43   -import cn.iocoder.yudao.adminserver.modules.system.service.logger.impl.SysLoginLogServiceImpl;
44   -import cn.iocoder.yudao.adminserver.modules.system.service.user.impl.SysUserServiceImpl;
45   -import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
46   -import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
  11 +import cn.iocoder.yudao.adminserver.modules.system.service.logger.SysLoginLogService;
  12 +import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
  13 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
  14 +import cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth.SysLoginUserCoreRedisDAO;
  15 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  16 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  17 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
47 18 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  19 +import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
  20 +import org.junit.jupiter.api.Test;
  21 +import org.springframework.boot.test.mock.mockito.MockBean;
  22 +import org.springframework.context.annotation.Import;
  23 +
  24 +import javax.annotation.Resource;
  25 +import java.util.Arrays;
  26 +import java.util.Collections;
  27 +import java.util.Date;
  28 +import java.util.List;
  29 +import java.util.stream.Collectors;
  30 +import java.util.stream.Stream;
  31 +
  32 +import static cn.hutool.core.util.RandomUtil.randomEle;
  33 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  34 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  35 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
  36 +import static java.util.Collections.singletonList;
  37 +import static org.junit.jupiter.api.Assertions.assertEquals;
  38 +import static org.mockito.ArgumentMatchers.eq;
  39 +import static org.mockito.Mockito.when;
48 40  
49 41 /**
50   - * SysUserSessionServiceImpl Tester.
  42 + * {@link SysUserSessionServiceImpl} 的单元测试
51 43 *
52 44 * @author Lyon
53   - * @version 1.0
54   - * @since <pre>3月 8, 2021</pre>
55 45 */
56   -@Import({SysUserSessionServiceImpl.class, SysLoginUserRedisDAO.class})
  46 +@Import({SysUserSessionServiceImpl.class})
57 47 public class SysUserSessionServiceImplTest extends BaseDbAndRedisUnitTest {
58 48  
59 49 @Resource
60   - private SysUserSessionServiceImpl sysUserSessionService;
61   - @Resource
62   - private SysUserSessionMapper sysUserSessionMapper;
63   - @Resource
64   - private SysLoginUserRedisDAO sysLoginUserRedisDAO;
  50 + private SysUserSessionServiceImpl userSessionService;
  51 +
65 52 @Resource
66   - private SysUserMapper sysUserMapper;
  53 + private SysUserSessionMapper userSessionMapper;
67 54  
68 55 @MockBean
69   - private SecurityProperties securityProperties;
  56 + private SysUserService userService;
70 57 @MockBean
71   - private SysDeptServiceImpl sysDeptService;
  58 + private SysLoginLogService loginLogService;
72 59 @MockBean
73   - private SysUserServiceImpl sysUserService;
74   - @MockBean
75   - private SysLoginLogServiceImpl sysLoginLogService;
76   -
77   - @Test
78   - public void testCreateUserSession_success() {
79   - // 准备参数
80   - String userIp = randomString();
81   - String userAgent = randomString();
82   - LoginUser loginUser = randomPojo(LoginUser.class);
83   - // mock
84   - when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
85   - // 调用
86   - String sessionId = sysUserSessionService.createUserSession(loginUser, userIp, userAgent);
87   - // 校验记录的属性是否正确
88   - SysUserSessionDO sysUserSessionDO = sysUserSessionMapper.selectById(sessionId);
89   - assertEquals(sysUserSessionDO.getId(), sessionId);
90   - assertEquals(sysUserSessionDO.getUserId(), loginUser.getId());
91   - assertEquals(sysUserSessionDO.getUserIp(), userIp);
92   - assertEquals(sysUserSessionDO.getUserAgent(), userAgent);
93   - assertEquals(sysUserSessionDO.getUsername(), loginUser.getUsername());
94   - LoginUser redisLoginUser = sysLoginUserRedisDAO.get(sessionId);
95   - AssertUtils.assertPojoEquals(redisLoginUser, loginUser, "username","password");
96   - }
97   -
98   - @Test
99   - public void testCreateRefreshUserSession_success() {
100   - // 准备参数
101   - String sessionId = randomString();
102   - String userIp = randomString();
103   - String userAgent = randomString();
104   - Long timeLong = randomLongId();
105   - String userName = randomString();
106   - Date date = randomDate();
107   - LoginUser loginUser = randomPojo(LoginUser.class);
108   - // mock
109   - when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
110   - loginUser.setUpdateTime(date);
111   - sysLoginUserRedisDAO.set(sessionId, loginUser);
112   - SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
113   - .userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).username(userName)
114   - .sessionTimeout(addTime(Duration.ofMillis(timeLong)))
115   - .build();
116   - sysUserSessionMapper.insert(userSession);
117   - SysUserSessionDO insertDO = sysUserSessionMapper.selectById(sessionId);
118   - // 调用
119   - sysUserSessionService.refreshUserSession(sessionId, loginUser);
120   - // 校验记录 redis
121   - LoginUser redisLoginUser = sysLoginUserRedisDAO.get(sessionId);
122   - assertNotEquals(redisLoginUser.getUpdateTime(), date);
123   - // 校验记录 SysUserSessionDO
124   - SysUserSessionDO updateDO = sysUserSessionMapper.selectById(sessionId);
125   - assertEquals(updateDO.getUsername(), loginUser.getUsername());
126   - assertNotEquals(updateDO.getUpdateTime(), insertDO.getUpdateTime());
127   - assertNotEquals(updateDO.getSessionTimeout(), addTime(Duration.ofMillis(timeLong)));
128   - }
129   -
130   - @Test
131   - public void testDeleteUserSession_success() {
132   - // 准备参数
133   - String sessionId = randomString();
134   - String userIp = randomString();
135   - String userAgent = randomString();
136   - Long timeLong = randomLongId();
137   - LoginUser loginUser = randomPojo(LoginUser.class);
138   - // mock 存入 Redis
139   - when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
140   - sysLoginUserRedisDAO.set(sessionId, loginUser);
141   - // mock 存入 db
142   - SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
143   - .userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
144   - .sessionTimeout(addTime(Duration.ofMillis(timeLong)))
145   - .build();
146   - sysUserSessionMapper.insert(userSession);
147   - // 校验数据存在
148   - assertNotNull(sysLoginUserRedisDAO.get(sessionId));
149   - assertNotNull(sysUserSessionMapper.selectById(sessionId));
150   - // 调用
151   - sysUserSessionService.deleteUserSession(sessionId);
152   - // 校验数据不存在了
153   - assertNull(sysLoginUserRedisDAO.get(sessionId));
154   - assertNull(sysUserSessionMapper.selectById(sessionId));
155   - }
  60 + private SysLoginUserCoreRedisDAO loginUserCoreRedisDAO;
156 61  
157 62 @Test
158 63 public void testGetUserSessionPage_success() {
159 64 // mock 数据
160   - String userIp = randomString();
161   - SysUserDO dbUser1 = randomPojo(SysUserDO.class, o -> {
162   - o.setUsername("testUsername1");
163   - o.setSex(randomEle(SysSexEnum.values()).getSex());
164   - o.setStatus(CommonStatusEnum.ENABLE.getStatus());
165   - });
166   - SysUserDO dbUser2 = randomPojo(SysUserDO.class, o -> {
167   - o.setUsername("testUsername2");
  65 + SysUserDO dbUser = randomPojo(SysUserDO.class, o -> {
168 66 o.setSex(randomEle(SysSexEnum.values()).getSex());
169 67 o.setStatus(CommonStatusEnum.ENABLE.getStatus());
170 68 });
  69 + when(userService.getUsersByUsername(eq(dbUser.getUsername()))).thenReturn(singletonList(dbUser));
  70 + // 插入可被查询到的数据
  71 + String userIp = randomString();
171 72 SysUserSessionDO dbSession = randomPojo(SysUserSessionDO.class, o -> {
172   - o.setUserId(dbUser1.getId());
  73 + o.setUserId(dbUser.getId());
  74 + o.setUserType(randomEle(UserTypeEnum.values()).getValue());
173 75 o.setUserIp(userIp);
174 76 });
175   - sysUserMapper.insert(dbUser1);
176   - sysUserMapper.insert(dbUser2);
177   - sysUserSessionMapper.insert(dbSession);
178   - sysUserSessionMapper.insert(ObjectUtils.clone(dbSession, o -> {
  77 + userSessionMapper.insert(dbSession);
  78 + // 测试 username 不匹配
  79 + userSessionMapper.insert(ObjectUtils.clone(dbSession, o -> {
179 80 o.setId(randomString());
180   - o.setUserId(dbUser2.getId());
181   - }));
182   - // 测试 userId 不匹配
183   - sysUserSessionMapper.insert(ObjectUtils.clone(dbSession, o -> {
184   - o.setId(randomString());
185   - o.setUserId(123456l);
  81 + o.setUserId(123456L);
186 82 }));
187 83 // 测试 userIp 不匹配
188   - sysUserSessionMapper.insert(ObjectUtils.clone(dbSession, o -> {
  84 + userSessionMapper.insert(ObjectUtils.clone(dbSession, o -> {
189 85 o.setId(randomString());
190 86 o.setUserIp("testUserIp");
191 87 }));
192 88 // 准备参数
193   - SysUserSessionPageReqVO reqVo = new SysUserSessionPageReqVO();
194   - reqVo.setUserIp(userIp);
  89 + SysUserSessionPageReqVO reqVO = new SysUserSessionPageReqVO();
  90 + reqVO.setUsername(dbUser.getUsername());
  91 + reqVO.setUserIp(userIp);
  92 +
195 93 // 调用
196   - PageResult<SysUserSessionDO> pageResult = sysUserSessionService.getUserSessionPage(reqVo);
  94 + PageResult<SysUserSessionDO> pageResult = userSessionService.getUserSessionPage(reqVO);
197 95 // 断言
198   - assertEquals(3, pageResult.getTotal());
199   - assertEquals(3, pageResult.getList().size());
  96 + assertEquals(1, pageResult.getTotal());
  97 + assertEquals(1, pageResult.getList().size());
200 98 assertPojoEquals(dbSession, pageResult.getList().get(0));
201 99 }
202 100  
  101 + // TODO 芋艿:单测写的有问题
203 102 @Test
204   - public void testClearSessionTimeout_success() throws Exception {
  103 + public void testClearSessionTimeout_success() {
205 104 // 准备超时数据 120 条, 在线用户 1 条
206 105 int expectedTimeoutCount = 120, expectedTotal = 1;
207 106  
... ... @@ -209,17 +108,23 @@ public class SysUserSessionServiceImplTest extends BaseDbAndRedisUnitTest {
209 108 List<SysUserSessionDO> prepareData = Stream
210 109 .iterate(0, i -> i)
211 110 .limit(expectedTimeoutCount)
212   - .map(i -> RandomUtils.randomPojo(SysUserSessionDO.class, o -> o.setSessionTimeout(DateUtil.offsetSecond(new Date(), -1))))
  111 + .map(i -> randomPojo(SysUserSessionDO.class, o -> {
  112 + o.setUserType(randomEle(UserTypeEnum.values()).getValue());
  113 + o.setSessionTimeout(DateUtil.offsetSecond(new Date(), -1));
  114 + }))
213 115 .collect(Collectors.toList());
214   - SysUserSessionDO sessionDO = RandomUtils.randomPojo(SysUserSessionDO.class, o -> o.setSessionTimeout(DateUtil.offsetMinute(new Date(), 30)));
  116 + SysUserSessionDO sessionDO = randomPojo(SysUserSessionDO.class, o -> {
  117 + o.setUserType(randomEle(UserTypeEnum.values()).getValue());
  118 + o.setSessionTimeout(DateUtil.offsetMinute(new Date(), 30));
  119 + });
215 120 prepareData.add(sessionDO);
216   - prepareData.forEach(sysUserSessionMapper::insert);
  121 + prepareData.forEach(userSessionMapper::insert);
217 122  
218   - //清空超时数据
219   - long actualTimeoutCount = sysUserSessionService.clearSessionTimeout();
220   - //校验
  123 + // 清空超时数据
  124 + long actualTimeoutCount = userSessionService.clearSessionTimeout();
  125 + // 校验
221 126 assertEquals(expectedTimeoutCount, actualTimeoutCount);
222   - List<SysUserSessionDO> userSessionDOS = sysUserSessionMapper.selectList();
  127 + List<SysUserSessionDO> userSessionDOS = userSessionMapper.selectList();
223 128 assertEquals(expectedTotal, userSessionDOS.size());
224 129 AssertUtils.assertPojoEquals(sessionDO, userSessionDOS.get(0), "updateTime");
225 130 }
... ...
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/SysLoginLogServiceImplTest.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.adminserver.modules.system.service.logger;
3 3 import cn.hutool.core.util.RandomUtil;
4 4 import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
5 5 import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
  6 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
6 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 8 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
8 9 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogExportReqVO;
... ... @@ -62,6 +63,7 @@ public class SysLoginLogServiceImplTest extends BaseDbUnitTest {
62 63 SysLoginLogDO loginLogDO = RandomUtils.randomPojo(SysLoginLogDO.class, logDO -> {
63 64 logDO.setLogType(RandomUtil.randomEle(SysLoginLogTypeEnum.values()).getType());
64 65 logDO.setTraceId(TracerUtils.getTraceId());
  66 + logDO.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue());
65 67  
66 68 logDO.setUserIp("192.168.199.16");
67 69 logDO.setUsername("wangkai");
... ... @@ -100,13 +102,13 @@ public class SysLoginLogServiceImplTest extends BaseDbUnitTest {
100 102  
101 103 @Test
102 104 public void testGetLoginLogList() {
103   -
104 105 // 构造测试数据
105 106  
106 107 // 登录成功的
107 108 SysLoginLogDO loginLogDO = RandomUtils.randomPojo(SysLoginLogDO.class, logDO -> {
108 109 logDO.setLogType(RandomUtil.randomEle(SysLoginLogTypeEnum.values()).getType());
109 110 logDO.setTraceId(TracerUtils.getTraceId());
  111 + logDO.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue());
110 112  
111 113 logDO.setUserIp("192.168.111.16");
112 114 logDO.setUsername("wangxiaokai");
... ...
yudao-admin-server/src/test/resources/application-unit-test.yaml
... ... @@ -36,34 +36,9 @@ mybatis:
36 36 # Lock4j 配置项(单元测试,禁用 Lock4j)
37 37  
38 38 # Resilience4j 配置项
39   -resilience4j:
40   - ratelimiter:
41   - instances:
42   - backendA:
43   - limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50
44   - limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500
45   - timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s
46   - register-health-indicator: true # 是否注册到健康监测
47 39  
48 40 --- #################### 监控相关配置 ####################
49 41  
50 42 --- #################### 芋道相关配置 ####################
51 43  
52 44 # 芋道配置项,设置当前项目所有自定义的配置
53   -yudao:
54   - security:
55   - token-header: Authorization
56   - token-secret: abcdefghijklmnopqrstuvwxyz
57   - token-timeout: 1d
58   - session-timeout: 30m
59   - mock-enable: true
60   - mock-secret: test
61   - swagger:
62   - enable: false # 单元测试,禁用 Swagger
63   - file:
64   - base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/file/get/
65   - xss:
66   - enable: false
67   - exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系
68   - - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求
69   - - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
... ...
yudao-admin-server/src/test/resources/sql/create_tables.sql
... ... @@ -179,6 +179,7 @@ CREATE TABLE IF NOT EXISTS &quot;sys_dict_type&quot; (
179 179 CREATE TABLE IF NOT EXISTS `sys_user_session` (
180 180 `id` varchar(32) NOT NULL,
181 181 `user_id` bigint DEFAULT NULL,
  182 + "user_type" tinyint NOT NULL,
182 183 `username` varchar(50) NOT NULL DEFAULT '',
183 184 `user_ip` varchar(50) DEFAULT NULL,
184 185 `user_agent` varchar(512) DEFAULT NULL,
... ... @@ -223,6 +224,8 @@ CREATE TABLE IF NOT EXISTS &quot;sys_notice&quot; (
223 224 CREATE TABLE IF NOT EXISTS `sys_login_log` (
224 225 `id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
225 226 `log_type` bigint(4) NOT NULL,
  227 + "user_id" bigint not null default '0',
  228 + "user_type" tinyint NOT NULL,
226 229 `trace_id` varchar(64) NOT NULL DEFAULT '',
227 230 `username` varchar(50) NOT NULL DEFAULT '',
228 231 `result` tinyint(4) NOT NULL,
... ...
yudao-core-service/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <artifactId>yudao</artifactId>
  7 + <groupId>cn.iocoder.boot</groupId>
  8 + <version>1.1.0-snapshot</version>
  9 + </parent>
  10 + <modelVersion>4.0.0</modelVersion>
  11 +
  12 + <artifactId>yudao-core-service</artifactId>
  13 + <packaging>jar</packaging>
  14 +
  15 + <name>yudao-admin-server</name>
  16 + <description>
  17 + 公共服务,通过 jar 包的方式,被 yudao-admin-server、yudao-user-service 使用。例如说:
  18 + 1. 日志相关:访问日志、登录日志、异常日志等等
  19 + 2. 认证相关:在线 Session
  20 + 3. 短信相关:短信模板、短信日志
  21 + 等等
  22 + </description>
  23 + <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
  24 +
  25 + <dependencies>
  26 + <!-- Web 相关 -->
  27 + <dependency>
  28 + <groupId>cn.iocoder.boot</groupId>
  29 + <artifactId>yudao-spring-boot-starter-web</artifactId>
  30 + </dependency>
  31 + <!-- spring boot 配置所需依赖 -->
  32 + <dependency>
  33 + <groupId>org.springframework.boot</groupId>
  34 + <artifactId>spring-boot-configuration-processor</artifactId>
  35 + <optional>true</optional>
  36 + </dependency>
  37 +
  38 + <dependency>
  39 + <groupId>cn.iocoder.boot</groupId>
  40 + <artifactId>yudao-spring-boot-starter-security</artifactId>
  41 + </dependency>
  42 +
  43 + <!-- DB 相关 -->
  44 + <dependency>
  45 + <groupId>cn.iocoder.boot</groupId>
  46 + <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
  47 + </dependency>
  48 +
  49 + <dependency>
  50 + <groupId>cn.iocoder.boot</groupId>
  51 + <artifactId>yudao-spring-boot-starter-redis</artifactId>
  52 + </dependency>
  53 +
  54 + <!-- Test 测试相关 -->
  55 + <dependency>
  56 + <groupId>cn.iocoder.boot</groupId>
  57 + <artifactId>yudao-spring-boot-starter-test</artifactId>
  58 + <scope>test</scope>
  59 + </dependency>
  60 + </dependencies>
  61 +
  62 +</project>
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/package-info.java 0 → 100644
  1 +/**
  2 + * infra 包下,我们放基础设施的运维与管理,支撑上层的通用与核心业务。
  3 + * 例如说:定时任务的管理、服务器的信息等等
  4 + *
  5 + * 缩写:inf
  6 + */
  7 +package cn.iocoder.yudao.coreservice.modules.infra;
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/package-info.java 0 → 100644
  1 +/**
  2 + * member 包下,我们放会员业务.
  3 + * 例如说:会员中心等等
  4 + *
  5 + * 缩写:mbr
  6 + */
  7 +package cn.iocoder.yudao.coreservice.modules.member;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/auth/SysUserSessionDO.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/auth/SysUserSessionDO.java
1   -package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth;
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
3 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 5 import cn.iocoder.yudao.framework.security.core.LoginUser;
5   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
6 6 import com.baomidou.mybatisplus.annotation.IdType;
7 7 import com.baomidou.mybatisplus.annotation.TableId;
8 8 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -35,7 +35,7 @@ public class SysUserSessionDO extends BaseDO {
35 35 /**
36 36 * 用户编号
37 37 *
38   - * 关联 {@link SysUserDO#getId()}
  38 + * 关联 SysUserDO.id 或者 MbrUserDO.id
39 39 */
40 40 private Long userId;
41 41 /**
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject;
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/auth/SysUserSessionCoreMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.auth;
  2 +
  3 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +@Mapper
  8 +public interface SysUserSessionCoreMapper extends BaseMapperX<SysUserSessionDO> {
  9 +
  10 +}
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.mysql;
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/redis/SysRedisKeyCoreConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.redis;
  2 +
  3 +import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
  4 +import cn.iocoder.yudao.framework.security.core.LoginUser;
  5 +
  6 +import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
  7 +
  8 +/**
  9 + * System Redis Key 枚举类
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +public interface SysRedisKeyCoreConstants {
  14 +
  15 + RedisKeyDefine LOGIN_USER = new RedisKeyDefine("登录用户的缓存",
  16 + "login_user:%s", // 参数为 sessionId
  17 + STRING, LoginUser.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
  18 +
  19 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysLoginUserRedisDAO.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/redis/auth/SysLoginUserCoreRedisDAO.java
1   -package cn.iocoder.yudao.adminserver.modules.system.dal.redis.auth;
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth;
2 2  
3   -import cn.iocoder.yudao.framework.security.core.LoginUser;
4   -import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
5 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  4 +import cn.iocoder.yudao.framework.security.config.SecurityProperties;
  5 +import cn.iocoder.yudao.framework.security.core.LoginUser;
6 6 import org.springframework.data.redis.core.StringRedisTemplate;
7 7 import org.springframework.stereotype.Repository;
8 8  
9 9 import javax.annotation.Resource;
10   -import java.time.Duration;
11 10  
12   -import static cn.iocoder.yudao.adminserver.modules.system.dal.redis.SysRedisKeyConstants.LOGIN_USER;
  11 +import static cn.iocoder.yudao.coreservice.modules.system.dal.redis.SysRedisKeyCoreConstants.LOGIN_USER;
13 12  
14 13 /**
15 14 * {@link LoginUser} 的 RedisDAO
... ... @@ -17,12 +16,13 @@ import static cn.iocoder.yudao.adminserver.modules.system.dal.redis.SysRedisKeyC
17 16 * @author 芋道源码
18 17 */
19 18 @Repository
20   -public class SysLoginUserRedisDAO {
  19 +public class SysLoginUserCoreRedisDAO {
21 20  
22 21 @Resource
23 22 private StringRedisTemplate stringRedisTemplate;
  23 +
24 24 @Resource
25   - private SysUserSessionService sysUserSessionService; // TODO 芋艿:得看看怎么拿出去
  25 + private SecurityProperties securityProperties;
26 26  
27 27 public LoginUser get(String sessionId) {
28 28 String redisKey = formatKey(sessionId);
... ... @@ -32,7 +32,7 @@ public class SysLoginUserRedisDAO {
32 32 public void set(String sessionId, LoginUser loginUser) {
33 33 String redisKey = formatKey(sessionId);
34 34 stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser),
35   - Duration.ofMillis(sysUserSessionService.getSessionTimeoutMillis()));
  35 + securityProperties.getSessionTimeout());
36 36 }
37 37  
38 38 public void delete(String sessionId) {
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/package-info.java 0 → 100644
  1 +/**
  2 + * system 包下,我们放通用业务,支撑上层的核心业务。
  3 + * 例如说:用户、部门、权限、数据字典等等
  4 + *
  5 + * 缩写:sys
  6 + */
  7 +package cn.iocoder.yudao.coreservice.modules.system;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/SysUserSessionService.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/auth/SysUserSessionCoreService.java
1   -package cn.iocoder.yudao.userserver.modules.system.service.auth;
  1 +package cn.iocoder.yudao.coreservice.modules.system.service.auth;
2 2  
3 3 import cn.iocoder.yudao.framework.security.core.LoginUser;
4 4  
5 5 /**
6   - * 在线用户 Session Service 接口
  6 + * 在线用户 Session Core Service 接口
7 7 *
8 8 * @author 芋道源码
9 9 */
10   -public interface SysUserSessionService {
  10 +public interface SysUserSessionCoreService {
11 11  
12 12 /**
13 13 * 创建在线用户 Session
... ... @@ -43,13 +43,6 @@ public interface SysUserSessionService {
43 43 LoginUser getLoginUser(String sessionId);
44 44  
45 45 /**
46   - * 获取当前登录用户信息
47   - * @param username 用户名称
48   - * @return 在线用户
49   - */
50   - String getSessionId(String username);
51   -
52   - /**
53 46 * 获得 Session 超时时间,单位:毫秒
54 47 *
55 48 * @return 超时时间
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/auth/impl/SysUserSessionCoreServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.service.auth.impl;
  2 +
  3 +import cn.hutool.core.util.IdUtil;
  4 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
  5 +import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.auth.SysUserSessionCoreMapper;
  6 +import cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth.SysLoginUserCoreRedisDAO;
  7 +import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
  8 +import cn.iocoder.yudao.framework.security.config.SecurityProperties;
  9 +import cn.iocoder.yudao.framework.security.core.LoginUser;
  10 +import org.springframework.stereotype.Service;
  11 +
  12 +import javax.annotation.Resource;
  13 +import java.time.Duration;
  14 +import java.util.Date;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
  17 +
  18 +/**
  19 + * 在线用户 Session Core Service 实现类
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Service
  24 +public class SysUserSessionCoreServiceImpl implements SysUserSessionCoreService {
  25 +
  26 + @Resource
  27 + private SysUserSessionCoreMapper userSessionCoreMapper;
  28 +
  29 + @Resource
  30 + private SysLoginUserCoreRedisDAO loginUserCoreRedisDAO;
  31 +
  32 + @Resource
  33 + private SecurityProperties securityProperties;
  34 +
  35 + @Override
  36 + public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
  37 + // 生成 Session 编号
  38 + String sessionId = generateSessionId();
  39 + // 写入 Redis 缓存
  40 + loginUser.setUpdateTime(new Date());
  41 + loginUserCoreRedisDAO.set(sessionId, loginUser);
  42 + // 写入 DB 中
  43 + SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
  44 + .userId(loginUser.getId()).userType(loginUser.getUserType())
  45 + .userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
  46 + .sessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())))
  47 + .build();
  48 + userSessionCoreMapper.insert(userSession);
  49 + // 返回 Session 编号
  50 + return sessionId;
  51 + }
  52 +
  53 + @Override
  54 + public void refreshUserSession(String sessionId, LoginUser loginUser) {
  55 + // 写入 Redis 缓存
  56 + loginUser.setUpdateTime(new Date());
  57 + loginUserCoreRedisDAO.set(sessionId, loginUser);
  58 + // 更新 DB 中
  59 + SysUserSessionDO updateObj = SysUserSessionDO.builder().id(sessionId).build();
  60 + updateObj.setUsername(loginUser.getUsername());
  61 + updateObj.setUpdateTime(new Date());
  62 + updateObj.setSessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())));
  63 + userSessionCoreMapper.updateById(updateObj);
  64 + }
  65 +
  66 + @Override
  67 + public void deleteUserSession(String sessionId) {
  68 + // 删除 Redis 缓存
  69 + loginUserCoreRedisDAO.delete(sessionId);
  70 + // 删除 DB 记录
  71 + userSessionCoreMapper.deleteById(sessionId);
  72 + }
  73 +
  74 + @Override
  75 + public LoginUser getLoginUser(String sessionId) {
  76 + return loginUserCoreRedisDAO.get(sessionId);
  77 + }
  78 +
  79 + @Override
  80 + public Long getSessionTimeoutMillis() {
  81 + return securityProperties.getSessionTimeout().toMillis();
  82 + }
  83 +
  84 + /**
  85 + * 生成 Session 编号,目前采用 UUID 算法
  86 + *
  87 + * @return Session 编号
  88 + */
  89 + private static String generateSessionId() {
  90 + return IdUtil.fastSimpleUUID();
  91 + }
  92 +
  93 +}
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.service;
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/tool/package-info.java 0 → 100644
  1 +/**
  2 + * tool 包下,我们放研发工具,提升研发效率与质量。
  3 + * 例如说:代码生成器、接口文档等等
  4 + *
  5 + * 缩写:tool
  6 + */
  7 +package cn.iocoder.yudao.coreservice.modules.tool;
... ...
yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/BaseDbAndRedisUnitTest.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice;
  2 +
  3 +import cn.iocoder.yudao.coreservice.config.RedisTestConfiguration;
  4 +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
  5 +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
  6 +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
  7 +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
  8 +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
  9 +import org.redisson.spring.starter.RedissonAutoConfiguration;
  10 +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
  11 +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  12 +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
  13 +import org.springframework.boot.test.context.SpringBootTest;
  14 +import org.springframework.context.annotation.Import;
  15 +import org.springframework.test.context.ActiveProfiles;
  16 +import org.springframework.test.context.jdbc.Sql;
  17 +
  18 +/**
  19 + * 依赖内存 DB + Redis 的单元测试
  20 + *
  21 + * 相比 {@link BaseDbUnitTest} 来说,额外增加了内存 Redis
  22 + *
  23 + * @author 芋道源码
  24 + */
  25 +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class)
  26 +@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
  27 +@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
  28 +public class BaseDbAndRedisUnitTest {
  29 +
  30 + @Import({
  31 + // DB 配置类
  32 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
  33 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类
  34 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
  35 + DruidDataSourceAutoConfigure.class, // Druid 自动配置类
  36 + // MyBatis 配置类
  37 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
  38 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
  39 + // Redis 配置类
  40 + RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
  41 + RedisAutoConfiguration.class, // Spring Redis 自动配置类
  42 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
  43 + RedissonAutoConfiguration.class, // Redisson 自动高配置类
  44 + })
  45 + public static class Application {
  46 + }
  47 +
  48 +}
... ...
yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/BaseDbUnitTest.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice;
  2 +
  3 +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
  4 +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
  5 +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
  6 +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
  7 +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  8 +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
  9 +import org.springframework.boot.test.context.SpringBootTest;
  10 +import org.springframework.context.annotation.Import;
  11 +import org.springframework.test.context.ActiveProfiles;
  12 +import org.springframework.test.context.jdbc.Sql;
  13 +
  14 +/**
  15 + * 依赖内存 DB 的单元测试
  16 + *
  17 + * 注意,Service 层同样适用。对于 Service 层的单元测试,我们针对自己模块的 Mapper 走的是 H2 内存数据库,针对别的模块的 Service 走的是 Mock 方法
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbUnitTest.Application.class)
  22 +@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
  23 +@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
  24 +public class BaseDbUnitTest {
  25 +
  26 + @Import({
  27 + // DB 配置类
  28 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
  29 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类
  30 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
  31 + DruidDataSourceAutoConfigure.class, // Druid 自动配置类
  32 + // MyBatis 配置类
  33 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
  34 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
  35 + })
  36 + public static class Application {
  37 + }
  38 +
  39 +}
... ...
yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/BaseRedisUnitTest.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice;
  2 +
  3 +import cn.iocoder.yudao.coreservice.config.RedisTestConfiguration;
  4 +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
  5 +import org.redisson.spring.starter.RedissonAutoConfiguration;
  6 +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
  7 +import org.springframework.boot.test.context.SpringBootTest;
  8 +import org.springframework.context.annotation.Import;
  9 +import org.springframework.test.context.ActiveProfiles;
  10 +
  11 +/**
  12 + * 依赖内存 Redis 的单元测试
  13 + *
  14 + * 相比 {@link BaseDbUnitTest} 来说,从内存 DB 改成了内存 Redis
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisUnitTest.Application.class)
  19 +@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
  20 +public class BaseRedisUnitTest {
  21 +
  22 + @Import({
  23 + // Redis 配置类
  24 + RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
  25 + RedisAutoConfiguration.class, // Spring Redis 自动配置类
  26 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
  27 + RedissonAutoConfiguration.class, // Redisson 自动高配置类
  28 + })
  29 + public static class Application {
  30 + }
  31 +
  32 +}
... ...
yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/config/RedisTestConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.config;
  2 +
  3 +import com.github.fppt.jedismock.RedisServer;
  4 +import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
  5 +import org.springframework.boot.context.properties.EnableConfigurationProperties;
  6 +import org.springframework.context.annotation.Bean;
  7 +import org.springframework.context.annotation.Configuration;
  8 +import org.springframework.context.annotation.Lazy;
  9 +
  10 +import java.io.IOException;
  11 +
  12 +@Configuration(proxyBeanMethods = false)
  13 +@Lazy(false) // 禁止延迟加载
  14 +@EnableConfigurationProperties(RedisProperties.class)
  15 +public class RedisTestConfiguration {
  16 +
  17 + /**
  18 + * 创建模拟的 Redis Server 服务器
  19 + */
  20 + @Bean
  21 + public RedisServer redisServer(RedisProperties properties) throws IOException {
  22 + RedisServer redisServer = new RedisServer(properties.getPort());
  23 + // TODO 芋艿:一次执行多个单元测试时,貌似创建多个 spring 容器,导致不进行 stop。这样,就导致端口被占用,无法启动。。。
  24 + try {
  25 + redisServer.start();
  26 + } catch (Exception ignore) {}
  27 + return redisServer;
  28 + }
  29 +
  30 +}
... ...
yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/system/service/auth/SysUserSessionCoreServiceTest.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.service.auth;
  2 +
  3 +import cn.iocoder.yudao.coreservice.BaseDbAndRedisUnitTest;
  4 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
  5 +import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.auth.SysUserSessionCoreMapper;
  6 +import cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth.SysLoginUserCoreRedisDAO;
  7 +import cn.iocoder.yudao.coreservice.modules.system.service.auth.impl.SysUserSessionCoreServiceImpl;
  8 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  9 +import cn.iocoder.yudao.framework.security.config.SecurityProperties;
  10 +import cn.iocoder.yudao.framework.security.core.LoginUser;
  11 +import org.junit.jupiter.api.Test;
  12 +import org.springframework.boot.test.mock.mockito.MockBean;
  13 +import org.springframework.context.annotation.Import;
  14 +
  15 +import javax.annotation.Resource;
  16 +import java.time.Duration;
  17 +import java.util.Date;
  18 +
  19 +import static cn.hutool.core.util.RandomUtil.randomEle;
  20 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
  21 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  22 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  23 +import static org.junit.jupiter.api.Assertions.*;
  24 +import static org.mockito.Mockito.when;
  25 +
  26 +@Import({SysUserSessionCoreServiceImpl.class, SysLoginUserCoreRedisDAO.class})
  27 +public class SysUserSessionCoreServiceTest extends BaseDbAndRedisUnitTest {
  28 +
  29 + @Resource
  30 + private SysUserSessionCoreServiceImpl userSessionCoreService;
  31 +
  32 + @Resource
  33 + private SysUserSessionCoreMapper userSessionCoreMapper;
  34 + @Resource
  35 + private SysLoginUserCoreRedisDAO loginUserCoreRedisDAO;
  36 +
  37 + @MockBean
  38 + private SecurityProperties securityProperties;
  39 +
  40 + @Test
  41 + public void testCreateUserSession_success() {
  42 + // 准备参数
  43 + String userIp = randomString();
  44 + String userAgent = randomString();
  45 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setUserType(randomEle(UserTypeEnum.values()).getValue()));
  46 + // mock 方法
  47 + when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
  48 +
  49 + // 调用
  50 + String sessionId = userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
  51 + // 校验 SysUserSessionDO 记录
  52 + SysUserSessionDO userSessionDO = userSessionCoreMapper.selectById(sessionId);
  53 + assertPojoEquals(loginUser, userSessionDO, "id", "updateTime");
  54 + assertEquals(sessionId, userSessionDO.getId());
  55 + assertEquals(userIp, userSessionDO.getUserIp());
  56 + assertEquals(userAgent, userSessionDO.getUserAgent());
  57 + // 校验 LoginUser 缓存
  58 + LoginUser redisLoginUser = loginUserCoreRedisDAO.get(sessionId);
  59 + assertPojoEquals(loginUser, redisLoginUser, "username", "password");
  60 + }
  61 +
  62 + @Test
  63 + public void testCreateRefreshUserSession_success() {
  64 + // 准备参数
  65 + String sessionId = randomString();
  66 + String userIp = randomString();
  67 + String userAgent = randomString();
  68 + long timeLong = randomLongId();
  69 + String userName = randomString();
  70 + Date date = randomDate();
  71 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setUserType(randomEle(UserTypeEnum.values()).getValue()));
  72 + // mock 方法
  73 + when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
  74 + // mock 数据
  75 + loginUser.setUpdateTime(date);
  76 + loginUserCoreRedisDAO.set(sessionId, loginUser);
  77 + SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
  78 + .userId(loginUser.getId()).userType(loginUser.getUserType())
  79 + .userIp(userIp).userAgent(userAgent).username(userName)
  80 + .sessionTimeout(addTime(Duration.ofMillis(timeLong)))
  81 + .build();
  82 + userSessionCoreMapper.insert(userSession);
  83 +
  84 + // 调用
  85 + userSessionCoreService.refreshUserSession(sessionId, loginUser);
  86 + // 校验 LoginUser 缓存
  87 + LoginUser redisLoginUser = loginUserCoreRedisDAO.get(sessionId);
  88 + assertNotEquals(redisLoginUser.getUpdateTime(), date);
  89 + // 校验 SysUserSessionDO 记录
  90 + SysUserSessionDO updateDO = userSessionCoreMapper.selectById(sessionId);
  91 + assertEquals(updateDO.getUsername(), loginUser.getUsername());
  92 + assertNotEquals(updateDO.getUpdateTime(), userSession.getUpdateTime());
  93 + assertNotEquals(updateDO.getSessionTimeout(), addTime(Duration.ofMillis(timeLong)));
  94 + }
  95 +
  96 + @Test
  97 + public void testDeleteUserSession_success() {
  98 + // 准备参数
  99 + String sessionId = randomString();
  100 + String userIp = randomString();
  101 + String userAgent = randomString();
  102 + Long timeLong = randomLongId();
  103 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setUserType(randomEle(UserTypeEnum.values()).getValue()));
  104 + // mock 存入 Redis
  105 + when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
  106 + // mock 数据
  107 + loginUserCoreRedisDAO.set(sessionId, loginUser);
  108 + SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
  109 + .userId(loginUser.getId()).userType(loginUser.getUserType())
  110 + .userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
  111 + .sessionTimeout(addTime(Duration.ofMillis(timeLong)))
  112 + .build();
  113 + userSessionCoreMapper.insert(userSession);
  114 +
  115 + // 调用
  116 + userSessionCoreService.deleteUserSession(sessionId);
  117 + // 校验数据不存在了
  118 + assertNull(loginUserCoreRedisDAO.get(sessionId));
  119 + assertNull(userSessionCoreMapper.selectById(sessionId));
  120 + }
  121 +
  122 +}
... ...
yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/system/service/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.service;
... ...
yudao-core-service/src/test/resources/application-unit-test.yaml 0 → 100644
  1 +spring:
  2 + main:
  3 + lazy-initialization: true # 开启懒加载,加快速度
  4 + banner-mode: off # 单元测试,禁用 Banner
  5 +
  6 +--- #################### 数据库相关配置 ####################
  7 +
  8 +spring:
  9 + # 数据源配置项
  10 + datasource:
  11 + name: ruoyi-vue-pro
  12 + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写
  13 + driver-class-name: org.h2.Driver
  14 + username: sa
  15 + password:
  16 + schema: classpath:sql/create_tables.sql # MySQL 转 H2 的语句,使用 https://www.jooq.org/translate/ 工具
  17 + druid:
  18 + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
  19 + initial-size: 1 # 单元测试,配置为 1,提升启动速度
  20 +
  21 + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
  22 + redis:
  23 + host: 127.0.0.1 # 地址
  24 + port: 16379 # 端口(单元测试,使用 16379 端口)
  25 + database: 0 # 数据库索引
  26 +
  27 +mybatis:
  28 + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
  29 +
  30 +--- #################### 定时任务相关配置 ####################
  31 +
  32 +--- #################### 配置中心相关配置 ####################
  33 +
  34 +--- #################### 服务保障相关配置 ####################
  35 +
  36 +# Lock4j 配置项(单元测试,禁用 Lock4j)
  37 +
  38 +# Resilience4j 配置项
  39 +
  40 +--- #################### 监控相关配置 ####################
  41 +
  42 +--- #################### 芋道相关配置 ####################
  43 +
  44 +# 芋道配置项,设置当前项目所有自定义的配置
... ...
yudao-core-service/src/test/resources/application.yaml 0 → 100644
  1 +spring:
  2 + application:
  3 + name: yudao-core-service
  4 +
  5 + # Jackson 配置项
  6 + jackson:
  7 + serialization:
  8 + write-dates-as-timestamps: true # 设置 Date 的格式,使用时间戳
  9 + write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
  10 + write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
  11 + fail-on-empty-beans: false # 允许序列化无属性的 Bean
  12 +
  13 +# MyBatis Plus 的配置项
  14 +mybatis-plus:
  15 + configuration:
  16 + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
  17 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志
  18 + global-config:
  19 + db-config:
  20 + id-type: AUTO # 自增 ID
  21 + logic-delete-value: 1 # 逻辑已删除值(默认为 1)
  22 + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
  23 + mapper-locations: classpath*:mapper/*.xml
  24 + type-aliases-package: ${yudao.core-service.base-package}.modules.*.dal.dataobject
  25 +
  26 +--- #################### 芋道相关配置 ####################
  27 +
  28 +yudao:
  29 + info:
  30 + version: 1.0.0
  31 + base-package: cn.iocoder.yudao.coreservice
  32 + core-service:
  33 + base-package: cn.iocoder.yudao.coreservice
  34 +
  35 +debug: false
... ...
yudao-core-service/src/test/resources/logback-spring.xml 0 → 100644
  1 +<configuration>
  2 + <!-- 引用 Spring Boot 的 logback 基础配置 -->
  3 + <include resource="org/springframework/boot/logging/logback/defaults.xml" />
  4 +</configuration>
... ...
yudao-core-service/src/test/resources/sql/clean.sql 0 → 100644
  1 +-- inf 开头的 DB
  2 +
  3 +-- sys 开头的 DB
  4 +DELETE FROM "sys_user_session";
... ...
yudao-core-service/src/test/resources/sql/create_tables.sql 0 → 100644
  1 +-- inf 开头的 DB
  2 +
  3 +-- sys 开头的 DB
  4 +
  5 +CREATE TABLE IF NOT EXISTS `sys_user_session` (
  6 + `id` varchar(32) NOT NULL,
  7 + `user_id` bigint DEFAULT NULL,
  8 + "user_type" tinyint NOT NULL,
  9 + `username` varchar(50) NOT NULL DEFAULT '',
  10 + `user_ip` varchar(50) DEFAULT NULL,
  11 + `user_agent` varchar(512) DEFAULT NULL,
  12 + `session_timeout` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + "creator" varchar(64) DEFAULT '',
  14 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  15 + `updater` varchar(64) DEFAULT '' ,
  16 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  17 + "deleted" bit NOT NULL DEFAULT FALSE,
  18 + PRIMARY KEY (`id`)
  19 +) COMMENT '用户在线 Session';
  20 +
... ...
yudao-dependencies/pom.xml
... ... @@ -74,6 +74,11 @@
74 74 <!-- 业务组件 -->
75 75 <dependency>
76 76 <groupId>cn.iocoder.boot</groupId>
  77 + <artifactId>yudao-core-service</artifactId>
  78 + <version>${revision}</version>
  79 + </dependency>
  80 + <dependency>
  81 + <groupId>cn.iocoder.boot</groupId>
77 82 <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
78 83 <version>${revision}</version>
79 84 </dependency>
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
... ... @@ -15,7 +15,7 @@ import org.springframework.context.annotation.Configuration;
15 15 * @author 芋道源码
16 16 */
17 17 @Configuration
18   -@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class,
  18 +@MapperScan(value = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"}, annotationClass = Mapper.class,
19 19 lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试
20 20 public class YudaoMybatisAutoConfiguration {
21 21  
... ...
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
1 1 package cn.iocoder.yudao.framework.security.core;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 5 import com.fasterxml.jackson.annotation.JsonIgnore;
5 6 import lombok.Data;
6 7 import org.springframework.security.core.GrantedAuthority;
... ... @@ -24,6 +25,12 @@ public class LoginUser implements UserDetails {
24 25 */
25 26 private Long id;
26 27 /**
  28 + * 用户类型
  29 + *
  30 + * 关联 {@link UserTypeEnum}
  31 + */
  32 + private Integer userType;
  33 + /**
27 34 * 部门编号
28 35 */
29 36 private Long deptId;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/package-info.java deleted
1   -package cn.iocoder.yudao.userserver.modules;
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysUserSessionServiceImpl.java deleted
1   -package cn.iocoder.yudao.userserver.modules.system.service.auth.impl;
2   -
3   -import cn.iocoder.yudao.framework.security.core.LoginUser;
4   -import cn.iocoder.yudao.userserver.modules.system.service.auth.SysUserSessionService;
5   -import lombok.extern.slf4j.Slf4j;
6   -import org.springframework.stereotype.Service;
7   -
8   -/**
9   - * 在线用户 Session Service 实现类
10   - *
11   - * @author 芋道源码
12   - */
13   -@Service
14   -@Slf4j
15   -public class SysUserSessionServiceImpl implements SysUserSessionService {
16   -
17   - @Override
18   - public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
19   - return null;
20   - }
21   -
22   - @Override
23   - public void refreshUserSession(String sessionId, LoginUser loginUser) {
24   -
25   - }
26   -
27   - @Override
28   - public void deleteUserSession(String sessionId) {
29   -
30   - }
31   -
32   - @Override
33   - public LoginUser getLoginUser(String sessionId) {
34   - return null;
35   - }
36   -
37   - @Override
38   - public String getSessionId(String username) {
39   - return null;
40   - }
41   -
42   - @Override
43   - public Long getSessionTimeoutMillis() {
44   - return null;
45   - }
46   -
47   -}