SysUserServiceImpl.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. package com.backendsys.modules.system.service.impl;
  2. import cn.hutool.core.convert.Convert;
  3. import cn.hutool.core.util.StrUtil;
  4. import com.backendsys.exception.CustException;
  5. import com.backendsys.modules.common.config.redis.utils.RedisUtil;
  6. import com.backendsys.modules.common.config.security.utils.SecurityUtil;
  7. import com.backendsys.modules.common.config.security.utils.TokenUtil;
  8. import com.backendsys.modules.common.utils.MybatisUtil;
  9. import com.backendsys.modules.sse.entity.SseResponse;
  10. import com.backendsys.modules.sse.entity.SseResponseEnum;
  11. import com.backendsys.modules.sse.utils.SseUtil;
  12. import com.backendsys.modules.system.dao.*;
  13. import com.backendsys.modules.system.entity.*;
  14. import com.backendsys.modules.system.service.SysUserIntegralService;
  15. import com.backendsys.modules.system.service.SysUserRoleMenuService;
  16. import com.backendsys.modules.system.service.SysUserService;
  17. import com.backendsys.utils.MD5Util;
  18. import com.backendsys.utils.response.PageEntity;
  19. import com.backendsys.utils.response.PageInfoResult;
  20. import com.backendsys.utils.v2.PageUtils;
  21. import com.baomidou.mybatisplus.core.conditions.Wrapper;
  22. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  23. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  24. import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
  25. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  26. import org.redisson.api.RLock;
  27. import org.redisson.api.RedissonClient;
  28. import org.springframework.beans.BeanUtils;
  29. import org.springframework.beans.factory.annotation.Autowired;
  30. import org.springframework.beans.factory.annotation.Value;
  31. import org.springframework.context.annotation.Lazy;
  32. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  33. import org.springframework.stereotype.Service;
  34. import org.springframework.transaction.annotation.Transactional;
  35. import java.security.NoSuchAlgorithmException;
  36. import java.util.*;
  37. import java.util.concurrent.TimeUnit;
  38. import java.util.stream.Collectors;
  39. @Service
  40. public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserService {
  41. @Value("${REDIS_LOGIN_TOKEN_PREFIX}")
  42. private String REDIS_LOGIN_TOKEN_PREFIX;
  43. @Value("${spring.application.name}")
  44. private String APPLICATION_NAME;
  45. @Autowired
  46. private SseUtil sseUtil;
  47. @Lazy
  48. @Autowired
  49. RedissonClient redissonClient;
  50. @Autowired
  51. private RedisUtil redisUtil;
  52. @Autowired
  53. private TokenUtil tokenUtil;
  54. @Autowired
  55. private SecurityUtil securityUtil;
  56. @Autowired
  57. private SysUserDao sysUserDao;
  58. @Autowired
  59. private SysUserInfoDao sysUserInfoDao;
  60. @Autowired
  61. private SysUserRoleDao sysUserRoleDao;
  62. @Autowired
  63. private SysUserRoleMenuService sysUserRoleMenuService;
  64. @Autowired
  65. private SysUserRoleRelationDao sysUserRoleRelationDao;
  66. @Autowired
  67. private SysUserRolePermissionRelationDao sysUserRolePermissionRelationDao;
  68. @Autowired
  69. private SysUserIntegralService sysUserIntegralService;
  70. /**
  71. * 获取系统用户列表
  72. */
  73. @Override
  74. public PageEntity selectUserList(SysUserDTO sysUserDTO) {
  75. PageUtils.startPage(); // 分页
  76. List<SysUserInfo> list = sysUserInfoDao.selectUserList(sysUserDTO);
  77. return new PageInfoResult(list).toEntity();
  78. }
  79. /**
  80. * 获取系统用户列表 (在线的)
  81. */
  82. @Override
  83. public PageEntity selectUserOnlineList(SysUserDTO sysUserDTO) {
  84. PageUtils.startPage(); // 分页
  85. // 获得 用户最后登录的 tokenUUID
  86. Collection<String> redisKeys = redisUtil.keys(REDIS_LOGIN_TOKEN_PREFIX + "*");
  87. List<String> last_login_uuids = redisKeys.stream().map(e -> String.valueOf(e).replace(REDIS_LOGIN_TOKEN_PREFIX, "")).collect(Collectors.toList());
  88. List<SysUserInfo> list = sysUserInfoDao.selectUserByLastLoginUuids(last_login_uuids);
  89. return new PageInfoResult(list).toEntity();
  90. }
  91. /**
  92. * 获取系统用户详情
  93. */
  94. @Override
  95. public SysUserInfo selectUserInfo(SysUserInfo entity) {
  96. Long user_id = entity.getUser_id();
  97. // 获得 用户账号信息
  98. SysUser sysUser = sysUserDao.selectOne(new QueryWrapper<SysUser>().eq("id", user_id));
  99. if (sysUser == null) throw new CustException("用户不存在");
  100. // 获得 用户基本信息
  101. LambdaQueryWrapper<SysUserInfo> wrapperUserInfo = new LambdaQueryWrapper<>();
  102. // 条件:用户ID (必选)
  103. wrapperUserInfo.eq(SysUserInfo::getUser_id, user_id);
  104. // 条件:邀请码
  105. if (StrUtil.isNotEmpty(entity.getInvite_code())) {
  106. wrapperUserInfo.eq(SysUserInfo::getInvite_code, entity.getInvite_code());
  107. }
  108. SysUserInfo sysUserInfo = sysUserInfoDao.selectOne(wrapperUserInfo);
  109. if (sysUserInfo == null) throw new CustException("用户不存在");
  110. // 用户账号信息 赋值到 用户基本信息
  111. BeanUtils.copyProperties(sysUser, sysUserInfo);
  112. // 获得 用户角色
  113. List<Map<String, Object>> roles = sysUserRoleDao.selectRoleByUserId(user_id);
  114. sysUserInfo.setRoles(roles);
  115. // 获得 用户角色Id
  116. List<Long> role_ids = roles.stream().map(m -> Convert.toLong(m.get("role_id"))).collect(Collectors.toList());
  117. sysUserInfo.setRole_id(role_ids);
  118. // 获得 用户角色权限Id (根据角色)
  119. List<String> permission_ids = sysUserRolePermissionRelationDao.selectUserRolePermissionIdsByRoleIds(role_ids);
  120. sysUserInfo.setPermission_ids(permission_ids);
  121. // 获得用户角色菜单 (根据权限)
  122. List<Map<String, Object>> sysUserRoleMenuList = sysUserRoleMenuService.selectUserRoleMenuList(permission_ids, 1);
  123. sysUserInfo.setMenus(sysUserRoleMenuList);
  124. // 获得用户积分 (需要权限)
  125. Integer integral = sysUserIntegralService.selectIntegralByUserId(user_id);
  126. sysUserInfo.setIntegral(integral);
  127. return sysUserInfo;
  128. }
  129. /**
  130. * 获取系统用户详情(简约)
  131. */
  132. @Override
  133. public SysUserInfoSimple selectUserInfoSimple(Long user_id) {
  134. // 获得 用户账号信息
  135. SysUser sysUser = sysUserDao.selectOne(new QueryWrapper<SysUser>().eq("id", user_id));
  136. if (sysUser == null) throw new CustException("用户不存在");
  137. // 获得 用户基本信息
  138. SysUserInfo sysUserInfo = sysUserInfoDao.selectOne(new QueryWrapper<SysUserInfo>().eq("user_id", user_id));
  139. if (sysUserInfo == null) throw new CustException("用户不存在");
  140. // 获得 用户角色
  141. List<Map<String, Object>> roles = sysUserRoleDao.selectRoleByUserId(user_id);
  142. sysUserInfo.setRoles(roles);
  143. // 获得 用户角色Id
  144. List<Long> role_ids = roles.stream().map(m -> Convert.toLong(m.get("role_id"))).collect(Collectors.toList());
  145. sysUserInfo.setRole_id(role_ids);
  146. // 获得用户积分 (需要权限)
  147. Integer integral = sysUserIntegralService.selectIntegralByUserId(user_id);
  148. sysUserInfo.setIntegral(integral);
  149. // 用户账号信息 赋值到 用户基本信息
  150. BeanUtils.copyProperties(sysUser, sysUserInfo);
  151. // 用户基本信息 赋值到 用户基本信息(简约)
  152. SysUserInfoSimple sysUserInfoSimple = new SysUserInfoSimple();
  153. BeanUtils.copyProperties(sysUserInfo, sysUserInfoSimple);
  154. return sysUserInfoSimple;
  155. }
  156. /**
  157. * 获取系统用户权限
  158. */
  159. @Override
  160. public Map<String, Object> selectUserPermission(Long user_id) {
  161. // 获得当前角色关系(集合)
  162. List<Long> userRoleIds = sysUserRoleRelationDao.selectUserRoleIds(user_id);
  163. // 获得当前角色关系(集合) 所对应的权限(集合)
  164. List<String> rolePermissionIds = new ArrayList<>();
  165. if (userRoleIds.size() > 0) {
  166. rolePermissionIds = sysUserRolePermissionRelationDao.selectUserRolePermissionIdsByRoleIds(userRoleIds);
  167. rolePermissionIds = rolePermissionIds.stream().distinct().collect(Collectors.toList());
  168. }
  169. Map<String, Object> resp = new LinkedHashMap<>();
  170. resp.put("user_id", user_id);
  171. resp.put("permission_ids", rolePermissionIds);
  172. return resp;
  173. }
  174. /**
  175. * 获取系统用户菜单
  176. */
  177. @Override
  178. public Map<String, Object> selectUserMenu(Long user_id) {
  179. // 获取系统用户权限
  180. Map<String, Object> permissionResp = selectUserPermission(user_id);
  181. List<String> permission_ids = (List<String>) permissionResp.get("permission_ids");
  182. // 获取系统用户菜单 (根据权限)
  183. List<Map<String, Object>> menuList = sysUserRoleMenuService.selectUserRoleMenuList(permission_ids, 1);
  184. Map<String, Object> resp = new LinkedHashMap<>();
  185. resp.put("user_id", user_id);
  186. resp.put("menus", menuList);
  187. return resp;
  188. }
  189. /**
  190. * 创建系统用户
  191. */
  192. @Override
  193. @Transactional(rollbackFor = Exception.class)
  194. public Map<String, Object> insertUser(SysUserDTO sysUserDTO) {
  195. RLock lock = redissonClient.getLock("insertUser");
  196. try { lock.tryLock(3, TimeUnit.SECONDS);
  197. String phone = sysUserDTO.getPhone();
  198. Integer phoneAreaCode = sysUserDTO.getPhone_area_code();
  199. String username = sysUserDTO.getUsername();
  200. // [查询] 判断用户名是否存在
  201. if (username != null) {
  202. SysUser sysUser1 = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
  203. if (sysUser1 != null) throw new CustException("用户名 (" + username + ") 已存在");
  204. }
  205. // [查询] 判断手机号是否存在
  206. if (phone != null) {
  207. LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
  208. queryWrapper.eq(SysUser::getPhone, phone);
  209. queryWrapper.eq(SysUser::getPhone_area_code, phoneAreaCode);
  210. SysUser sysUser2 = sysUserDao.selectOne(queryWrapper);
  211. if (sysUser2 != null) throw new CustException("手机号码 (+" + phoneAreaCode + " " + phone + ") 已存在");
  212. }
  213. // 密码二次加密
  214. String password = sysUserDTO.getPassword();
  215. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  216. String encodedPassword = encoder.encode(password);
  217. sysUserDTO.setPassword(encodedPassword);
  218. // 创建用户
  219. sysUserDao.insertUser(sysUserDTO);
  220. // 初始化用户积分
  221. sysUserIntegralService.init(sysUserDTO.getId());
  222. return Map.of("user_id", sysUserDTO.getId());
  223. } catch (InterruptedException e) { throw new RuntimeException(e);
  224. } finally { lock.unlock(); }
  225. }
  226. /**
  227. * 编辑系统用户信息
  228. */
  229. @Override
  230. @Transactional(rollbackFor = Exception.class)
  231. public Map<String, Object> updateUserInfo(SysUserDTO sysUserDTO) {
  232. RLock lock = redissonClient.getLock("updateUserInfo");
  233. try { lock.tryLock(3, TimeUnit.SECONDS);
  234. // 判断记录是否存在
  235. MybatisUtil.checkExists(sysUserDao, "id", sysUserDTO.getUser_id(), "用户不存在");
  236. // 判断手机号码是否存在
  237. if (sysUserDTO.getPhone() != null) {
  238. SysUser sysUser = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhone, sysUserDTO.getPhone()));
  239. if (sysUser != null) throw new CustException("手机号码已存在");
  240. }
  241. // 当 status 状态为 -1(禁用) 时,同时清除登录状态
  242. Integer status = sysUserDTO.getStatus();
  243. if (status != null && status == -1) {
  244. // 删除旧的登录缓存
  245. tokenUtil.deleteRedisLoginToken(sysUserDTO.getLast_login_uuid());
  246. sysUserDTO.setLast_login_uuid("");
  247. }
  248. System.out.println("sysUserDTO = " + sysUserDTO);
  249. sysUserDao.updateUserInfo(sysUserDTO);
  250. return Map.of("user_id", sysUserDTO.getUser_id());
  251. } catch (InterruptedException e) { throw new RuntimeException(e);
  252. } finally { lock.unlock(); }
  253. }
  254. /**
  255. * 编辑系统用户角色绑定
  256. */
  257. @Override
  258. @Transactional(rollbackFor = Exception.class)
  259. public Map<String, Object> updateUserRoleRelation(SysUserRoleRelation sysUserRoleRelation) {
  260. RLock lock = redissonClient.getLock("updateUserRoleRelation");
  261. try { lock.tryLock(3, TimeUnit.SECONDS);
  262. List<Long> role_ids = sysUserRoleRelation.getRole_ids();
  263. Long user_id = sysUserRoleRelation.getUser_id();
  264. // 1.删除全部用户与角色的关系 (sys_user_role_relation)
  265. LambdaQueryWrapper<SysUserRoleRelation> wrapperRoleRelation = new LambdaQueryWrapper<>();
  266. wrapperRoleRelation.eq(SysUserRoleRelation::getUser_id, user_id);
  267. sysUserRoleRelationDao.delete(wrapperRoleRelation);
  268. // 2.重新添加参数中的角色与权限的关系 (sys_user_role_relation)
  269. sysUserRoleRelationDao.insertBatch(user_id, role_ids);
  270. return Map.of("user_id", sysUserRoleRelation.getUser_id());
  271. } catch (InterruptedException e) { throw new RuntimeException(e);
  272. } finally { lock.unlock(); }
  273. }
  274. /**
  275. * 编辑系统用户密码
  276. */
  277. @Override
  278. @Transactional(rollbackFor = Exception.class)
  279. public Map<String, Object> updateUserPassword(SysUserDTO sysUserDTO) {
  280. RLock lock = redissonClient.getLock("updateUserPassword");
  281. try { lock.tryLock(3, TimeUnit.SECONDS);
  282. // 查询用户
  283. SysUser sysUser = sysUserDao.selectOne(new QueryWrapper<SysUser>().eq("id", sysUserDTO.getUser_id()));
  284. if (sysUser == null) throw new CustException("原密码不正确");
  285. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  286. // [判断] 原密码是否正确
  287. String old_password_request = sysUserDTO.getOld_password();
  288. String old_password = sysUser.getPassword();
  289. if (!encoder.matches(old_password_request, old_password)) {
  290. throw new CustException("原密码不正确");
  291. }
  292. SysUser entity = new SysUser();
  293. entity.setId(sysUserDTO.getUser_id());
  294. // // MD5加密
  295. // String md5Password = MD5Util.encrypt(sysUserDTO.getPassword());
  296. // 加盐加密 (前端会传已加密过的密码)
  297. String encodedPassword = encoder.encode(sysUserDTO.getPassword());
  298. entity.setPassword(encodedPassword);
  299. System.out.println(entity);
  300. // [编辑] 用户密码
  301. sysUserDao.updateById(entity);
  302. // [SSE] 发送退出登录的消息
  303. String dataStr = (new SseResponse(SseResponseEnum.LOGOUT)).toJsonStr();
  304. sseUtil.send(sysUserDTO.getUser_id(), dataStr);
  305. return Map.of("user_id", sysUserDTO.getUser_id());
  306. } catch (InterruptedException e) {
  307. throw new RuntimeException(e);
  308. } finally { lock.unlock(); }
  309. }
  310. /**
  311. * 重置系统用户密码
  312. */
  313. @Override
  314. @Transactional(rollbackFor = Exception.class)
  315. public Map<String, Object> resetUserPassword(SysUserDTO sysUserDTO) {
  316. RLock lock = redissonClient.getLock("resetUserPassword");
  317. try { lock.tryLock(3, TimeUnit.SECONDS);
  318. // 生成一个六位的随机数密码
  319. String uuid = UUID.randomUUID().toString().replace("-", "");
  320. String password = uuid.substring(0, 6);
  321. // MD5加密
  322. String md5Password = MD5Util.encrypt(password);
  323. // 加盐加密
  324. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  325. String encodedPassword = encoder.encode(md5Password);
  326. sysUserDTO.setPassword(encodedPassword);
  327. //
  328. SysUser entity = new SysUser();
  329. entity.setId(sysUserDTO.getUser_id());
  330. entity.setPassword(encodedPassword);
  331. System.out.println(entity);
  332. // [编辑] 用户密码
  333. sysUserDao.updateById(entity);
  334. // 要先判断连接存不存在?
  335. // [SSE] 发送退出登录的消息
  336. try {
  337. String dataStr = (new SseResponse(SseResponseEnum.LOGOUT)).toJsonStr();
  338. sseUtil.send(sysUserDTO.getUser_id(), dataStr);
  339. } catch (Exception e) {
  340. System.out.println(e.getMessage());
  341. }
  342. Map<String, Object> response = new LinkedHashMap<>();
  343. response.put("user_id", sysUserDTO.getUser_id());
  344. response.put("plain_password", password);
  345. return response;
  346. } catch (InterruptedException | NoSuchAlgorithmException e) {
  347. throw new RuntimeException(e);
  348. } finally { lock.unlock(); }
  349. }
  350. /**
  351. * 删除系统用户 (以及部分关联表)
  352. */
  353. @Override
  354. @Transactional(rollbackFor = Exception.class)
  355. public Map<String, Object> deleteUser(SysUserDTO sysUserDTO) {
  356. RLock lock = redissonClient.getLock("deleteUser");
  357. try { lock.tryLock(3, TimeUnit.SECONDS);
  358. // 单个删除
  359. Long user_id = sysUserDTO.getUser_id();
  360. if (user_id != null) {
  361. sysUserDao.deleteById(user_id);
  362. sysUserInfoDao.delete(new QueryWrapper<SysUserInfo>().eq("user_id", user_id));
  363. sysUserRoleRelationDao.delete(new QueryWrapper<SysUserRoleRelation>().eq("user_id", user_id));
  364. return Map.of("user_id", user_id);
  365. }
  366. // 批量删除
  367. List<Long> user_ids = sysUserDTO.getUser_ids();
  368. if (user_ids != null && user_ids.size() > 0) {
  369. sysUserDao.delete(new QueryWrapper<SysUser>().in("id", user_ids));
  370. sysUserInfoDao.delete(new QueryWrapper<SysUserInfo>().in("user_id", user_ids));
  371. sysUserRoleRelationDao.delete(new QueryWrapper<SysUserRoleRelation>().in("user_id", user_ids));
  372. return Map.of("user_ids", user_ids);
  373. }
  374. return null;
  375. } catch (InterruptedException e) { throw new RuntimeException(e);
  376. } finally { lock.unlock(); }
  377. }
  378. /**
  379. * 踢出系统用户
  380. */
  381. @Override
  382. public Map<String, Object> kickUser(Long user_id) {
  383. RLock lock = redissonClient.getLock("kickUser");
  384. try { lock.tryLock(3, TimeUnit.SECONDS);
  385. // 查询用户信息
  386. Wrapper queryWrapper = new QueryWrapper<SysUserInfo>().lambda().eq(SysUserInfo::getUser_id, user_id);
  387. SysUserInfo sysUserInfo = sysUserInfoDao.selectOne(queryWrapper);
  388. if (sysUserInfo != null) {
  389. // 删除旧的登录缓存
  390. tokenUtil.deleteRedisLoginToken(sysUserInfo.getLast_login_uuid());
  391. // 更新用户信息 (查询最后登录uuid,并清除)
  392. Wrapper updateWrapper = new UpdateWrapper<SysUserInfo>().lambda().set(SysUserInfo::getLast_login_uuid, "").eq(SysUserInfo::getUser_id, user_id);
  393. sysUserInfoDao.update(null, updateWrapper);
  394. // [SSE] 发送退出登录的消息
  395. String dataStr = (new SseResponse(SseResponseEnum.LOGOUT)).toJsonStr();
  396. sseUtil.send(sysUserInfo.getUser_id(), dataStr);
  397. }
  398. return Map.of("user_id", user_id);
  399. } catch (InterruptedException e) { throw new RuntimeException(e);
  400. } finally { lock.unlock(); }
  401. }
  402. /**
  403. * 审核用户
  404. */
  405. @Override
  406. public Map<String, Object> auditUser(SysUserDTO sysUserDTO) {
  407. RLock lock = redissonClient.getLock("auditUser");
  408. try { lock.tryLock(3, TimeUnit.SECONDS);
  409. Long user_id = sysUserDTO.getUser_id();
  410. SysUserInfo entity = new SysUserInfo();
  411. entity.setAudit_status(sysUserDTO.getAudit_status());
  412. entity.setAudit_note(sysUserDTO.getAudit_note());
  413. sysUserInfoDao.update(entity, new LambdaQueryWrapper<SysUserInfo>().eq(SysUserInfo::getUser_id, user_id));
  414. return Map.of("user_id", user_id);
  415. } catch (InterruptedException e) { throw new RuntimeException(e);
  416. } finally { lock.unlock(); }
  417. }
  418. }