UserService.java 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. package com.webchat.user.service;
  2. import com.alibaba.nacos.common.utils.CollectionUtils;
  3. import com.fasterxml.jackson.core.type.TypeReference;
  4. import com.webchat.common.bean.APIPageResponseBean;
  5. import com.webchat.common.constants.WebConstant;
  6. import com.webchat.common.enums.APIErrorCommonEnum;
  7. import com.webchat.common.enums.RedisKeyEnum;
  8. import com.webchat.common.enums.RoleCodeEnum;
  9. import com.webchat.common.enums.UserStatusEnum;
  10. import com.webchat.common.exception.BusinessException;
  11. import com.webchat.common.helper.SessionHelper;
  12. import com.webchat.common.service.RedisService;
  13. import com.webchat.common.util.*;
  14. import com.webchat.domain.vo.request.CreateGroupRequestVO;
  15. import com.webchat.domain.vo.request.CreatePublicAccountRequestVO;
  16. import com.webchat.domain.vo.request.CreateRobotRequestVO;
  17. import com.webchat.domain.vo.request.UpdateUserInfoRequestVO;
  18. import com.webchat.domain.vo.response.GroupResponseInfoVO;
  19. import com.webchat.domain.vo.response.UserBaseResponseInfoVO;
  20. import com.webchat.domain.vo.response.UserBaseResponseVO;
  21. import com.webchat.domain.vo.response.UserSafeResponseInfoVO;
  22. import com.webchat.user.repository.dao.IGroupUserDAO;
  23. import com.webchat.user.repository.dao.IUserDAO;
  24. import com.webchat.user.repository.entity.GroupUserEntity;
  25. import com.webchat.user.repository.entity.UserEntity;
  26. import com.webchat.user.service.relation.AccountRelationFactory;
  27. import com.webchat.user.service.relation.User2FileSenderAccountRelationService;
  28. import com.webchat.user.service.relation.User2GroupAccountRelationService;
  29. import jakarta.persistence.criteria.Predicate;
  30. import jakarta.servlet.http.HttpServletRequest;
  31. import jakarta.servlet.http.HttpServletResponse;
  32. import org.apache.commons.lang3.ObjectUtils;
  33. import org.apache.commons.lang3.StringUtils;
  34. import org.springframework.beans.BeanUtils;
  35. import org.springframework.beans.factory.annotation.Autowired;
  36. import org.springframework.data.domain.Page;
  37. import org.springframework.data.domain.PageRequest;
  38. import org.springframework.data.domain.Pageable;
  39. import org.springframework.data.domain.Sort;
  40. import org.springframework.data.jpa.domain.Specification;
  41. import org.springframework.data.redis.core.DefaultTypedTuple;
  42. import org.springframework.data.redis.core.ZSetOperations;
  43. import org.springframework.stereotype.Service;
  44. import org.springframework.transaction.annotation.Transactional;
  45. import org.springframework.util.Assert;
  46. import java.util.*;
  47. import java.util.regex.Pattern;
  48. import java.util.stream.Collectors;
  49. @Service
  50. public class UserService {
  51. @Autowired
  52. private HttpServletRequest request;
  53. @Autowired
  54. private HttpServletResponse response;
  55. @Autowired
  56. private IUserDAO userDAO;
  57. @Autowired
  58. private RedisService redisService;
  59. @Autowired
  60. private IGroupUserDAO groupUserDAO;
  61. @Autowired
  62. private PublicAccountService publicAccountService;
  63. /***
  64. * USER ID 前缀
  65. */
  66. private static final String USER_ID_PREFIX = "U";
  67. private static final String ROBOT_ID_PREFIX = "R";
  68. private static final String GROUP_ID_PREFIX = "G";
  69. private static final String PUBLIC_ACCOUNT_ID_PREFIX = "P";
  70. public UserBaseResponseVO getUserBaseByMobile(String mobile) {
  71. UserEntity user = userDAO.findByMobile(mobile);
  72. if (user != null) {
  73. UserBaseResponseVO userBaseResponseVO = new UserBaseResponseVO();
  74. BeanUtils.copyProperties(user, userBaseResponseVO);
  75. return userBaseResponseVO;
  76. }
  77. return null;
  78. }
  79. /**
  80. * 批量走redis查询用户详情
  81. *
  82. * @param userIds
  83. * @return
  84. */
  85. public Map<String, UserBaseResponseInfoVO> batchGet(Set<String> userIds) {
  86. return this.batchGetUserInfoFromCache(new ArrayList<>(userIds));
  87. }
  88. /**
  89. *
  90. *
  91. * @param account
  92. * @return
  93. */
  94. public UserBaseResponseInfoVO queryAccount(String account) {
  95. if (StringUtils.isBlank(account)) {
  96. return null;
  97. }
  98. String cacheKey = RedisKeyEnum.USER_INFO_BY_MOBILE_CACHE.getKey(account);
  99. String cache = redisService.get(cacheKey);
  100. if (StringUtils.isNotBlank(cache)) {
  101. if (ObjectUtils.equals(WebConstant.CACHE_NONE, cache)) {
  102. return null;
  103. }
  104. return JsonUtil.fromJson(cache, UserBaseResponseInfoVO.class);
  105. }
  106. // 刷新BY手机号用户详情缓存
  107. return this.refreshUserCacheByMobile(account);
  108. }
  109. /**
  110. * 刷新用户详情缓存,基于手机号查询
  111. *
  112. * @param account
  113. * @return
  114. */
  115. private UserBaseResponseInfoVO refreshUserCacheByMobile(String account) {
  116. String cacheKey = RedisKeyEnum.USER_INFO_BY_MOBILE_CACHE.getKey(account);
  117. UserEntity userEntity = userDAO.findByMobile(account);
  118. if (userEntity == null) {
  119. redisService.set(cacheKey, WebConstant.CACHE_NONE, 5 * 60);
  120. return null;
  121. }
  122. UserBaseResponseInfoVO vo = convertBaseVo(userEntity);
  123. redisService.set(cacheKey, JsonUtil.toJsonString(vo), RedisKeyEnum.USER_INFO_BY_MOBILE_CACHE.getExpireTime());
  124. return vo;
  125. }
  126. public APIPageResponseBean<UserBaseResponseInfoVO> page(String userId, Integer roleCode, String userName, String mobile,
  127. int pageNo, int pageSize) {
  128. Pageable pageable = PageRequest.of(pageNo - 1, pageSize, Sort.by(Sort.Direction.DESC, "id"));
  129. Specification<UserEntity> specification = createAccountQuerySpecification(userId, roleCode, userName, mobile);
  130. Page<UserEntity> userEntityPage = userDAO.findAll(specification, pageable);
  131. List<UserEntity> userEntities = userEntityPage.getContent();
  132. List<UserBaseResponseInfoVO> userBaseVoList = new ArrayList<>();
  133. if (CollectionUtils.isNotEmpty(userEntities)) {
  134. userBaseVoList = userEntities.stream().map(UserService::convertBaseVo).collect(Collectors.toList());
  135. }
  136. return APIPageResponseBean.success(pageNo, pageSize, userEntityPage.getTotalElements(), userBaseVoList);
  137. }
  138. private Specification createAccountQuerySpecification(String userId, Integer roleCode, String userName, String mobile) {
  139. return ((root, criteriaQuery, criteriaBuilder) -> {
  140. List<Predicate> predicates = new ArrayList<>();
  141. if (roleCode != null) {
  142. predicates.add(criteriaBuilder.equal(root.get("roleCode").as(Integer.class), roleCode));
  143. }
  144. if (StringUtils.isNotBlank(userId)) {
  145. predicates.add(criteriaBuilder.equal(root.get("userId").as(String.class), userId));
  146. }
  147. if (StringUtils.isNotBlank(userName)) {
  148. predicates.add(criteriaBuilder.like(root.get("userName").as(String.class), "%" + userName + "%"));
  149. }
  150. if (StringUtils.isNotBlank(mobile)) {
  151. predicates.add(criteriaBuilder.equal(root.get("mobile").as(String.class), mobile));
  152. }
  153. Predicate[] pre = new Predicate[predicates.size()];
  154. criteriaQuery.where(predicates.toArray(pre));
  155. return criteriaQuery.getRestriction();
  156. });
  157. }
  158. /**
  159. * 用户注册 - 注册成功自动登录
  160. * @param photo
  161. * @param userName
  162. * @param mobile
  163. * @param password
  164. * @return
  165. */
  166. // 这里其实不需要事务,因为想分享事务管理器的用法和场景,刻意添加了事务注解
  167. @Transactional
  168. public boolean registry(String photo, String userName, String mobile, String password) {
  169. // 参数校验
  170. this.validateRegistryParam(userName, mobile);
  171. // 注册信息入库
  172. String uid = this.registryUser2DB(userName, photo, mobile, password);
  173. // 默认添加文件传输助手
  174. SpringContextUtil.getBean(User2FileSenderAccountRelationService.class).subscribe(uid, WebConstant.FILE_SEND_ID);
  175. // 注册成功,事务结束后刷新用户缓存信息
  176. TransactionSyncManagerUtil.registerSynchronization(() -> {
  177. // 刷新用户缓存
  178. this.refreshAndGetUserEntityFromCache(uid);
  179. });
  180. return true;
  181. }
  182. private void validateRegistryParam(String userName, String mobile) {
  183. if (hasUserInfo(mobile)) {
  184. throw new BusinessException("用户已存在");
  185. }
  186. if (!Pattern.matches("^[0-9a-zA-Z_]{1,}$", mobile)) {
  187. throw new BusinessException("账号格式不合法");
  188. }
  189. if (StringUtils.isBlank(userName) || userName.length() < 2 || userName.length() > 12) {
  190. throw new BusinessException("用户名不合法:2~12位字符");
  191. }
  192. if (userNameIsExist(userName)) {
  193. throw new BusinessException("用户名已经被占用,换一个吧");
  194. }
  195. }
  196. public UserBaseResponseInfoVO queryByMobile(String mobile) {
  197. UserEntity userEntity = userDAO.findByMobile(mobile);
  198. return this.convertBaseVo(userEntity);
  199. }
  200. public APIPageResponseBean<List<UserSafeResponseInfoVO>> getUserList(Integer roleCode, int pageNo, int pageSize) {
  201. Pageable pageable = PageRequest.of(pageNo - 1, pageSize, Sort.by(Sort.Direction.DESC, "id"));
  202. Page<UserEntity> userEntities;
  203. if (roleCode == null) {
  204. userEntities = userDAO.findAll(pageable);
  205. } else {
  206. userEntities = userDAO.findAllByRoleCode(roleCode, pageable);
  207. }
  208. List<UserSafeResponseInfoVO> userSafeResponseInfoVOS = new ArrayList<>();
  209. if (userEntities != null && CollectionUtils.isNotEmpty(userEntities.getContent())) {
  210. userEntities.getContent().stream().forEach(u -> {
  211. UserSafeResponseInfoVO userSafeResponseInfoVO = this.convertSafeVo(u);
  212. userSafeResponseInfoVOS.add(userSafeResponseInfoVO);
  213. });
  214. }
  215. return APIPageResponseBean.success(pageNo, pageSize, userEntities.getTotalElements(), userSafeResponseInfoVOS);
  216. }
  217. /**
  218. * 创建机器人
  219. *
  220. * 复用用户信息表,账号角色为 ROBOT
  221. */
  222. @Transactional
  223. public void createRobot(CreateRobotRequestVO requestPram) {
  224. String robotNumber = requestPram.getRobotNumber();
  225. String robotName = requestPram.getRobotName();
  226. String robotRole = requestPram.getRobotRole();
  227. String createUserId = requestPram.getCreateUserId();
  228. String robotPhoto = requestPram.getRobotPhoto();
  229. UserEntity userEntity = userDAO.findByMobile(robotName);
  230. Assert.isTrue(userEntity == null, "机器人账号已存在!");
  231. /**
  232. * 防快速点击
  233. */
  234. String key = RedisKeyEnum.CREATE_ROBOT_LIMIT.getKey(createUserId);
  235. boolean lockResult = redisService.installDistributedLock(key, WebConstant.CACHE_NONE, RedisKeyEnum.CREATE_ROBOT_LIMIT.getExpireTime());
  236. Assert.isTrue(lockResult, "创建中请稍等!请勿频繁点击");
  237. /**
  238. * 创建机器人
  239. */
  240. robotRole = StringUtils.isBlank(robotRole) ? "全能助手" : robotRole;
  241. this.registryRobot2DB(requestPram.getId(), robotNumber, robotName, robotRole, robotPhoto, createUserId);
  242. }
  243. /**
  244. * 创建公众号
  245. *
  246. * 复用用户信息表,账号角色为 PUBLIC_ACCOUNT
  247. */
  248. @Transactional
  249. public void createPublicAccount(CreatePublicAccountRequestVO requestVO) {
  250. String account = requestVO.getAccount();
  251. String accountName = requestVO.getAccountName();
  252. String signature = requestVO.getSignature();
  253. String photo = requestVO.getAccountPhoto();
  254. String createUserId = requestVO.getCreateUserId();
  255. /**
  256. * 防快速点击
  257. */
  258. String key = RedisKeyEnum.CREATE_PUBLIC_ACCOUNT_LIMIT.getKey();
  259. boolean lockResult = redisService.installDistributedLock(key, WebConstant.CACHE_NONE, RedisKeyEnum.CREATE_ROBOT_LIMIT.getExpireTime());
  260. Assert.isTrue(lockResult, "创建中请稍等!请勿频繁点击");
  261. // 创建机器人
  262. this.registryPublicAccount2DB(account, accountName, photo, signature, createUserId);
  263. }
  264. /**
  265. * 查询用户加入的所有群聊
  266. *
  267. * @param userId
  268. * @return
  269. */
  270. public List<GroupResponseInfoVO> listUserAttendGroupsFromCache(String userId) {
  271. if (StringUtils.isBlank(userId)) {
  272. return Collections.emptyList();
  273. }
  274. List<String> groupIds = this.getGroupUserIdsFromCacheByUserId(userId);
  275. if (CollectionUtils.isEmpty(groupIds)) {
  276. return Collections.emptyList();
  277. }
  278. List<UserBaseResponseInfoVO> groups = this.batchGetUserListInfoFromCache(groupIds);
  279. return groups.stream().map(g -> {
  280. GroupResponseInfoVO groupResponseInfoVO = new GroupResponseInfoVO();
  281. groupResponseInfoVO.setId(g.getId());
  282. groupResponseInfoVO.setGroupId(g.getUserId());
  283. groupResponseInfoVO.setGroupName(g.getUserName());
  284. // 这里性能可能存在问题,最好不要在遍历中查询,当前为了省事,先这么干了
  285. groupResponseInfoVO.setUserCount(getGroupUserIdsFromCache(g.getUserId()).size());
  286. return groupResponseInfoVO;
  287. }).collect(Collectors.toList());
  288. }
  289. /**
  290. * 查询群组下所有用户信息列表
  291. *
  292. * @param groupId
  293. * @return
  294. */
  295. public List<UserBaseResponseInfoVO> getGroupUsersFromCache(String groupId, String userId) {
  296. List<String> groupIds = getGroupUserIdsFromCache(groupId);
  297. if (CollectionUtils.isEmpty(groupIds)) {
  298. return Collections.emptyList();
  299. }
  300. Assert.isTrue(groupIds.contains(userId), "无群组查看权限!");
  301. // 缓存中批量查询用户信息
  302. return this.batchGetUserListInfoFromCache(groupIds);
  303. }
  304. /**
  305. * 查询群组下所有用户ID列表
  306. *
  307. * @param groupId
  308. * @return
  309. */
  310. public List<String> getGroupUserIdsFromCache(String groupId) {
  311. String key = RedisKeyEnum.GROUP_USER_ID_LIST_CACHE.getKey(groupId);
  312. // redis中取群组下所有用户ID列表
  313. Set<String> userIds = redisService.zreverseRange(key, 0, Integer.MAX_VALUE);
  314. if (CollectionUtils.isEmpty(userIds)) {
  315. userIds = refreshGroupUserIdListCache(groupId);
  316. }
  317. return new ArrayList<>(userIds);
  318. }
  319. /**
  320. * 查询用户加入的所有群组
  321. *
  322. *
  323. * @param userId
  324. * @return
  325. */
  326. public List<String> getGroupUserIdsFromCacheByUserId(String userId) {
  327. String key = RedisKeyEnum.USER_ATTEND_GROUP_ID_LIST_CACHE.getKey(userId);
  328. // redis中取群组下所有用户ID列表
  329. String cache = redisService.get(key);
  330. if (StringUtils.isNotBlank(cache)) {
  331. return JsonUtil.fromJson(cache, new TypeReference<List<String>>() {});
  332. }
  333. return this.refreshUserAttendGroupIdListCache(userId);
  334. }
  335. /**
  336. * 删除用加入的群组列表缓存
  337. *
  338. * @param userIds
  339. */
  340. private void removeGroupUserIdsFromCacheByUserId(Set<String> userIds) {
  341. for (String userId : userIds) {
  342. String key = RedisKeyEnum.USER_ATTEND_GROUP_ID_LIST_CACHE.getKey(userId);
  343. redisService.remove(key);
  344. }
  345. }
  346. private List<String> refreshUserAttendGroupIdListCache(String userId) {
  347. String key = RedisKeyEnum.USER_ATTEND_GROUP_ID_LIST_CACHE.getKey(userId);
  348. List<GroupUserEntity> groupUserEntities = groupUserDAO.findAllByUserIdAndStatusOrderByIdDesc(userId, UserStatusEnum.ENABLE.getStatus());
  349. List<String> groupIds = new ArrayList<>();
  350. if (CollectionUtils.isNotEmpty(groupUserEntities)) {
  351. groupIds = groupUserEntities.stream().map(GroupUserEntity::getGroupId).collect(Collectors.toList());
  352. }
  353. redisService.set(key, JsonUtil.toJsonString(groupIds), RedisKeyEnum.USER_ATTEND_GROUP_ID_LIST_CACHE.getExpireTime());
  354. return groupIds;
  355. }
  356. /**
  357. * 刷新群组下用户列表缓存
  358. */
  359. private Set<String> refreshGroupUserIdListCache(String groupId) {
  360. String key = RedisKeyEnum.GROUP_USER_ID_LIST_CACHE.getKey(groupId);
  361. List<GroupUserEntity> groupUserEntities =
  362. groupUserDAO.findAllByGroupIdAndStatusOrderByIdDesc(groupId, UserStatusEnum.ENABLE.getStatus());
  363. // 先清空
  364. redisService.remove(key);
  365. if (CollectionUtils.isEmpty(groupUserEntities)) {
  366. return Collections.emptySet();
  367. }
  368. Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
  369. for (GroupUserEntity groupUser : groupUserEntities) {
  370. String value = groupUser.getUserId().toString();
  371. double score = groupUser.getId();
  372. ZSetOperations.TypedTuple<String> tuple = new DefaultTypedTuple<>(value, score);
  373. typedTupleSet.add(tuple);
  374. }
  375. redisService.zadd(key, typedTupleSet, RedisKeyEnum.GROUP_USER_ID_LIST_CACHE.getExpireTime());
  376. return groupUserEntities.stream().map(GroupUserEntity::getUserId).collect(Collectors.toSet());
  377. }
  378. /**
  379. * 添加用户到群组
  380. *
  381. * @param groupId
  382. * @param userIdSet
  383. * @param createUserId
  384. */
  385. private void addUsers2Group(String groupId, Set<String> userIdSet, String createUserId) {
  386. if (CollectionUtils.isEmpty(userIdSet)) {
  387. return;
  388. }
  389. Date now = new Date();
  390. List<GroupUserEntity> groupUserEntities = userIdSet.stream().map(
  391. uid -> {
  392. GroupUserEntity groupUserEntity = new GroupUserEntity();
  393. groupUserEntity.setGroupId(groupId);
  394. groupUserEntity.setUserId(uid);
  395. groupUserEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
  396. groupUserEntity.setCreateBy(createUserId);
  397. groupUserEntity.setCreateDate(now);
  398. return groupUserEntity;
  399. }
  400. ).collect(Collectors.toList());
  401. // 批量添加用户到群组
  402. groupUserDAO.saveAll(groupUserEntities);
  403. }
  404. /**
  405. * 注册用户到数据库
  406. *
  407. * @param userName
  408. * @param photo
  409. * @param mobile
  410. * @param password
  411. */
  412. private String registryUser2DB(String userName, String photo, String mobile, String password) {
  413. UserEntity userEntity = new UserEntity();
  414. String userId = IDGenerateUtil.createId(USER_ID_PREFIX);
  415. userEntity.setUserId(userId);
  416. userEntity.setUserName(StringUtil.handleSpecialHtmlTag(userName));
  417. userEntity.setPhoto(photo);
  418. userEntity.setMobile(mobile);
  419. userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
  420. userEntity.setPassword(md5Pwd(password));
  421. userEntity.setRoleCode(RoleCodeEnum.USER.getCode());
  422. userEntity.setCreateBy(userId);
  423. userEntity.setSignature("暂无签名~");
  424. // 注册用户
  425. return userDAO.save(userEntity).getUserId();
  426. }
  427. /**
  428. * 创建群组到数据库
  429. *
  430. * @param groupName
  431. * @param createUserId
  432. */
  433. public String registerGroup2DB(String groupName, String groupPhoto, String createUserId) {
  434. UserEntity userEntity = new UserEntity();
  435. String groupId = IDGenerateUtil.createId(GROUP_ID_PREFIX);
  436. userEntity.setUserId(groupId);
  437. userEntity.setUserName(StringUtil.handleSpecialHtmlTag(groupName));
  438. userEntity.setPhoto(groupPhoto);
  439. userEntity.setMobile("-");
  440. userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
  441. // 密码设置为用户ID, 本身也不支持登录
  442. userEntity.setPassword(md5Pwd(groupId));
  443. userEntity.setRoleCode(RoleCodeEnum.GROUP.getCode());
  444. userEntity.setCreateBy(createUserId);
  445. // 创建群组
  446. userDAO.save(userEntity);
  447. // 注册成功,事务结束后刷新群组缓存
  448. TransactionSyncManagerUtil.registerSynchronization(() ->
  449. this.refreshAndGetUserEntityFromCache(groupId));
  450. return groupId;
  451. }
  452. /**
  453. * 创建机器人到数据库
  454. *
  455. * @param robotName
  456. * @param createUserId
  457. */
  458. private String registryRobot2DB(Long id, String robotNumber, String robotName, String role, String robotPhoto, String createUserId) {
  459. UserEntity userEntity;
  460. if (id != null) {
  461. userEntity = userDAO.findById(id).orElse(null);
  462. } else {
  463. userEntity = new UserEntity();
  464. String robotId = IDGenerateUtil.createId(ROBOT_ID_PREFIX);
  465. userEntity.setUserId(robotId);
  466. // 密码设置为用户ID, 本身也不支持登录
  467. userEntity.setPassword(md5Pwd(robotId));
  468. userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
  469. userEntity.setRoleCode(RoleCodeEnum.ROBOT.getCode());
  470. userEntity.setCreateBy(createUserId);
  471. }
  472. userEntity.setUserName(robotName);
  473. userEntity.setPhoto(robotPhoto);
  474. userEntity.setMobile(robotNumber);
  475. userEntity.setSignature(role);
  476. // 注册用户
  477. userEntity = userDAO.save(userEntity);
  478. String robotId = userEntity.getUserId();
  479. // 注册成功,事务结束后刷新用户缓存信息
  480. TransactionSyncManagerUtil.registerSynchronization(() -> {
  481. // 刷新用户缓存
  482. this.refreshAndGetUserEntityFromCache(robotId);
  483. });
  484. return robotId;
  485. }
  486. /**
  487. * 创建公众号
  488. * @return
  489. */
  490. private String registryPublicAccount2DB(String account, String accountName, String accountPhoto,
  491. String accountSignature, String createUserId) {
  492. UserEntity userEntity = userDAO.findByMobile(account);
  493. Assert.isTrue(userEntity == null, "公众号已经存在");
  494. userEntity = new UserEntity();
  495. String userId = IDGenerateUtil.createId(PUBLIC_ACCOUNT_ID_PREFIX);
  496. userEntity.setUserId(userId);
  497. userEntity.setUserName(StringUtil.handleSpecialHtmlTag(accountName));
  498. userEntity.setPhoto(accountPhoto);
  499. userEntity.setMobile(account);
  500. userEntity.setSignature(accountSignature);
  501. userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
  502. // 密码设置为用户ID, 本身也不支持登录
  503. userEntity.setPassword(md5Pwd(account));
  504. userEntity.setRoleCode(RoleCodeEnum.PUBLIC_ACCOUNT.getCode());
  505. userEntity.setCreateBy(createUserId);
  506. // 注册用户
  507. userDAO.save(userEntity);
  508. // 注册成功,事务结束后刷新用户缓存信息
  509. TransactionSyncManagerUtil.registerSynchronization(() -> {
  510. // 刷新用户缓存
  511. this.refreshAndGetUserEntityFromCache(account);
  512. // 刷新公众号文章列表
  513. publicAccountService.refreshPublicAccountListCache();
  514. });
  515. return userId;
  516. }
  517. /**
  518. * 判断用户是否存在
  519. * @param mobile
  520. * @return
  521. */
  522. private boolean hasUserInfo(String mobile) {
  523. return userDAO.findByMobile(mobile) != null;
  524. }
  525. private boolean userNameIsExist(String userName) {
  526. return userDAO.findByUserName(userName) != null;
  527. }
  528. /**
  529. * 获取当前登录用户信息
  530. * @return
  531. */
  532. public UserBaseResponseInfoVO getCurrentUserInfo() {
  533. return getLoginUserBaseInfoFromCache();
  534. }
  535. public UserBaseResponseInfoVO getLoginUserBaseInfoFromCache() {
  536. String userId = this.getLoginCurrentUserId();
  537. return getUserBaseInfoByUserIdFromCache(userId);
  538. }
  539. /**
  540. * 查询用户详情
  541. *
  542. * @param userId
  543. * @return
  544. */
  545. public UserBaseResponseInfoVO getUserInfoByUserId(String userId) {
  546. return getUserBaseInfoByUserId(userId);
  547. }
  548. /**
  549. * 查询指定订阅用户
  550. *
  551. * @param relationType 关系类型
  552. * @param account
  553. * @return
  554. */
  555. public Set<String> getAllSubscriberByAccount(Integer relationType, String account) {
  556. return AccountRelationFactory.getServiceByType(relationType).getAllSubscriber(account);
  557. }
  558. /**
  559. * 用户信息编辑
  560. *
  561. * @param updateUserInfoRequest
  562. * @return
  563. */
  564. public boolean updateUserInfo(UpdateUserInfoRequestVO updateUserInfoRequest) {
  565. // 更新数据库
  566. UserEntity userEntity = userDAO.findByUserId(updateUserInfoRequest.getUserId());
  567. Assert.notNull(userEntity, "用户信息更新失败: 用户不存在!");
  568. // 支持单独修改头像或者昵称
  569. if (StringUtils.isNotBlank(updateUserInfoRequest.getUserName())) {
  570. userEntity.setUserName(updateUserInfoRequest.getUserName());
  571. }
  572. if (StringUtils.isNotBlank(updateUserInfoRequest.getPhoto())) {
  573. userEntity.setPhoto(updateUserInfoRequest.getPhoto());
  574. }
  575. userDAO.save(userEntity);
  576. // 刷新用户信息缓存
  577. this.refreshUserDetailCache(userEntity);
  578. return true;
  579. }
  580. public UserBaseResponseInfoVO getUserBaseInfoByUserId(String userId) {
  581. if (StringUtils.isBlank(userId)) {
  582. return null;
  583. }
  584. return getUserBaseInfoByUserIdFromCache(userId);
  585. }
  586. private UserBaseResponseInfoVO getUserBaseInfoByUserIdFromCache(String userId) {
  587. if (userId == null) {
  588. return null;
  589. }
  590. UserEntity entity = this.refreshAndGetUserEntityFromCache(userId);
  591. UserBaseResponseInfoVO userBaseResponseInfoVO = this.convertBaseVo(entity);
  592. if (userBaseResponseInfoVO == null) {
  593. return null;
  594. }
  595. return userBaseResponseInfoVO;
  596. }
  597. /**
  598. * 强制刷新用户信息缓存
  599. * @param userId
  600. */
  601. private void refreshUserDetailCache(String userId) {
  602. this.refreshAndGetUserEntityFromCache(userId, true);
  603. }
  604. private UserEntity refreshAndGetUserEntityFromCache(String userId, boolean ... refreshCache) {
  605. String key = RedisKeyEnum.USER_INFO_CACHE.getKey(userId);
  606. String val = redisService.get(key);
  607. boolean refresh = refreshCache != null && refreshCache.length > 0 && refreshCache[0];
  608. if (!refresh && StringUtils.isNotBlank(val)) {
  609. return JsonUtil.fromJson(val, UserEntity.class);
  610. }
  611. UserEntity userEntity = userDAO.findByUserId(userId);
  612. if (userEntity != null) {
  613. this.refreshUserDetailCache(userEntity);
  614. }
  615. return userEntity;
  616. }
  617. /**
  618. * 刷新用户详情redis缓存
  619. *
  620. * @param userEntity
  621. */
  622. private void refreshUserDetailCache(UserEntity userEntity) {
  623. if (userEntity == null) {
  624. return;
  625. }
  626. String key = RedisKeyEnum.USER_INFO_CACHE.getKey(userEntity.getUserId());
  627. redisService.set(key, JsonUtil.toJsonString(userEntity), RedisKeyEnum.USER_INFO_CACHE.getExpireTime());
  628. }
  629. /***
  630. * 取当前用户ID,且未登录时直接抛出未登录异常
  631. * @return
  632. */
  633. public String getLoginCurrentUserIdOrElseThrowUnLoginExp() {
  634. String userId = getLoginCurrentUserId();
  635. if (StringUtils.isNotBlank(userId)) {
  636. return userId;
  637. }
  638. throw new BusinessException(APIErrorCommonEnum.USER_UN_LOGIN);
  639. }
  640. /***
  641. * 更新用户角色
  642. * @param userId
  643. * @param roleCode
  644. */
  645. public void updateUserRole(String userId, Integer roleCode) {
  646. UserEntity userEntity = userDAO.findByUserId(userId);
  647. Assert.isTrue(userEntity != null, "更新失败,用户不存在!");
  648. userEntity.setRoleCode(roleCode);
  649. userDAO.save(userEntity);
  650. /***
  651. * 刷新用户信息缓存
  652. */
  653. this.refreshUserDetailCache(userId);
  654. }
  655. /**
  656. * 获取当前登录的用户ID
  657. * @return
  658. */
  659. public String getLoginCurrentUserId() {
  660. return SessionHelper.getCurrentUserId();
  661. }
  662. private String md5Pwd(String password) {
  663. return MD5Utils.md5(password.concat(WebConstant.MD5_SALT));
  664. }
  665. /**
  666. * 批量查询用户缓存
  667. *
  668. * @param userIdList
  669. * @return
  670. */
  671. public Map<String, UserBaseResponseInfoVO> batchGetUserInfoFromCache(List<String> userIdList) {
  672. Map<String, UserBaseResponseInfoVO> userBaseResponseInfoVOMap = new HashMap<>();
  673. if (CollectionUtils.isEmpty(userIdList)) {
  674. return userBaseResponseInfoVOMap;
  675. }
  676. List<String> cacheKeys = userIdList.stream().map(k ->
  677. RedisKeyEnum.USER_INFO_CACHE.getKey(String.valueOf(k))).collect(Collectors.toList());
  678. Map<String, String> multiResultMap = redisService.mgetAndParseMap(cacheKeys);
  679. for (int i = 0; i < userIdList.size(); i++) {
  680. String userId = userIdList.get(i);
  681. String cacheKey = cacheKeys.get(i);
  682. String cache = multiResultMap.get(cacheKey);
  683. UserBaseResponseInfoVO userBaseResponseInfoVO;
  684. if (StringUtils.isNotBlank(cache)) {
  685. userBaseResponseInfoVO = JsonUtil.fromJson(cache, UserBaseResponseInfoVO.class);
  686. } else {
  687. userBaseResponseInfoVO = getUserBaseInfoByUserId(userId);
  688. }
  689. userBaseResponseInfoVOMap.put(userId, userBaseResponseInfoVO);
  690. }
  691. return userBaseResponseInfoVOMap;
  692. }
  693. public List<UserBaseResponseInfoVO> batchGetUserListInfoFromCache(Set<String> userIdSet) {
  694. return this.batchGetUserListInfoFromCache(new ArrayList<>(userIdSet));
  695. }
  696. public List<UserBaseResponseInfoVO> batchGetUserListInfoFromCache(List<String> userIdList) {
  697. if (CollectionUtils.isEmpty(userIdList)) {
  698. return Collections.emptyList();
  699. }
  700. List<String> cacheKeys = userIdList.stream().map(k ->
  701. RedisKeyEnum.USER_INFO_CACHE.getKey(String.valueOf(k))).collect(Collectors.toList());
  702. Map<String, String> multiResultMap = redisService.mgetAndParseMap(cacheKeys);
  703. List<UserBaseResponseInfoVO> userBaseResponseInfoVOList = new ArrayList<>();
  704. for (int i = 0; i < userIdList.size(); i++) {
  705. String userId = userIdList.get(i);
  706. String cacheKey = cacheKeys.get(i);
  707. String cache = multiResultMap.get(cacheKey);
  708. UserBaseResponseInfoVO userBaseResponseInfoVO;
  709. if (StringUtils.isNotBlank(cache)) {
  710. userBaseResponseInfoVO = JsonUtil.fromJson(cache, UserBaseResponseInfoVO.class);
  711. } else {
  712. userBaseResponseInfoVO = getUserBaseInfoByUserId(userId);
  713. }
  714. if (userBaseResponseInfoVO != null) {
  715. userBaseResponseInfoVOList.add(userBaseResponseInfoVO);
  716. }
  717. }
  718. return userBaseResponseInfoVOList;
  719. }
  720. /**
  721. * 创建系统账号
  722. * @return
  723. */
  724. public UserBaseResponseInfoVO getSystemUserInfo() {
  725. UserBaseResponseInfoVO userBaseResponseInfoVO = new UserBaseResponseInfoVO();
  726. userBaseResponseInfoVO.setUserId(WebConstant.SYSTEM_USER_ID);
  727. userBaseResponseInfoVO.setUserName("系统");
  728. userBaseResponseInfoVO.setPhoto("");
  729. return userBaseResponseInfoVO;
  730. }
  731. public static UserBaseResponseInfoVO convertBaseVo(UserEntity entity) {
  732. if (entity == null) {
  733. return null;
  734. }
  735. UserBaseResponseInfoVO vo = new UserBaseResponseInfoVO();
  736. BeanUtils.copyProperties(entity, vo);
  737. vo.setMobile(CommonUtils.mobileEncrypt(entity.getMobile()));
  738. return vo;
  739. }
  740. public static UserSafeResponseInfoVO convertSafeVo(UserEntity entity) {
  741. if (entity == null) {
  742. return null;
  743. }
  744. UserSafeResponseInfoVO vo = new UserSafeResponseInfoVO();
  745. BeanUtils.copyProperties(entity, vo);
  746. if (entity.getCreateDate() != null) {
  747. vo.setRegistryTime(entity.getCreateDate().getTime());
  748. vo.setRegistryTimeStr(DateUtils.getDate2String(entity.getCreateDate()));
  749. }
  750. return vo;
  751. }
  752. }