UserServiceImpl.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. package com.zsElectric.boot.system.service.impl;
  2. import cn.hutool.core.collection.CollectionUtil;
  3. import cn.hutool.core.lang.Assert;
  4. import cn.hutool.core.util.StrUtil;
  5. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6. import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  7. import com.baomidou.mybatisplus.core.metadata.IPage;
  8. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  9. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  10. import com.zsElectric.boot.common.constant.RedisConstants;
  11. import com.zsElectric.boot.common.constant.SystemConstants;
  12. import com.zsElectric.boot.core.exception.BusinessException;
  13. import com.zsElectric.boot.common.model.Option;
  14. import com.zsElectric.boot.platform.sms.enums.SmsTypeEnum;
  15. import com.zsElectric.boot.platform.sms.service.SmsService;
  16. import com.zsElectric.boot.security.model.UserAuthCredentials;
  17. import com.zsElectric.boot.security.service.PermissionService;
  18. import com.zsElectric.boot.security.token.TokenManager;
  19. import com.zsElectric.boot.security.util.SecurityUtils;
  20. import com.zsElectric.boot.platform.mail.service.MailService;
  21. import com.zsElectric.boot.system.converter.UserConverter;
  22. import com.zsElectric.boot.system.enums.DictCodeEnum;
  23. import com.zsElectric.boot.system.mapper.UserMapper;
  24. import com.zsElectric.boot.system.model.bo.UserBO;
  25. import com.zsElectric.boot.system.model.dto.CurrentUserDTO;
  26. import com.zsElectric.boot.system.model.dto.UserExportDTO;
  27. import com.zsElectric.boot.system.model.entity.DictItem;
  28. import com.zsElectric.boot.system.model.entity.User;
  29. import com.zsElectric.boot.system.model.entity.UserRole;
  30. import com.zsElectric.boot.system.model.form.*;
  31. import com.zsElectric.boot.system.model.form.*;
  32. import com.zsElectric.boot.system.model.query.UserPageQuery;
  33. import com.zsElectric.boot.system.model.vo.UserPageVO;
  34. import com.zsElectric.boot.system.model.vo.UserProfileVO;
  35. import com.zsElectric.boot.system.service.*;
  36. import com.zsElectric.boot.system.service.DictItemService;
  37. import com.zsElectric.boot.system.service.RoleService;
  38. import com.zsElectric.boot.system.service.UserRoleService;
  39. import com.zsElectric.boot.system.service.UserService;
  40. import lombok.RequiredArgsConstructor;
  41. import lombok.extern.slf4j.Slf4j;
  42. import org.springframework.data.redis.core.StringRedisTemplate;
  43. import org.springframework.security.crypto.password.PasswordEncoder;
  44. import org.springframework.stereotype.Service;
  45. import org.springframework.transaction.annotation.Transactional;
  46. import java.math.BigDecimal;
  47. import java.time.LocalDateTime;
  48. import java.util.*;
  49. import java.util.concurrent.TimeUnit;
  50. import java.util.stream.Collectors;
  51. /**
  52. * 用户业务实现类
  53. *
  54. * @author Ray.Hao
  55. * @since 2022/1/14
  56. */
  57. @Service
  58. @RequiredArgsConstructor
  59. @Slf4j
  60. public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
  61. private final PasswordEncoder passwordEncoder;
  62. private final UserRoleService userRoleService;
  63. private final RoleService roleService;
  64. private final PermissionService permissionService;
  65. private final SmsService smsService;
  66. private final MailService mailService;
  67. private final StringRedisTemplate redisTemplate;
  68. private final TokenManager tokenManager;
  69. private final DictItemService dictItemService;
  70. private final UserConverter userConverter;
  71. private final com.zsElectric.boot.business.service.UserInfoService userInfoService;
  72. /**
  73. * 获取用户分页列表
  74. *
  75. * @param queryParams 查询参数
  76. * @return {@link IPage<UserPageVO>} 用户分页列表
  77. */
  78. @Override
  79. public IPage<UserPageVO> getUserPage(UserPageQuery queryParams) {
  80. // 参数构建
  81. int pageNum = queryParams.getPageNum();
  82. int pageSize = queryParams.getPageSize();
  83. Page<UserBO> page = new Page<>(pageNum, pageSize);
  84. boolean isRoot = SecurityUtils.isRoot();
  85. queryParams.setIsRoot(isRoot);
  86. // 查询数据
  87. Page<UserBO> userPage = this.baseMapper.getUserPage(page, queryParams);
  88. // 实体转换
  89. return userConverter.toPageVo(userPage);
  90. }
  91. /**
  92. * 获取用户表单数据
  93. *
  94. * @param userId 用户ID
  95. * @return {@link UserForm} 用户表单数据
  96. */
  97. @Override
  98. public UserForm getUserFormData(Long userId) {
  99. return this.baseMapper.getUserFormData(userId);
  100. }
  101. /**
  102. * 新增用户
  103. *
  104. * @param userForm 用户表单对象
  105. * @return true|false
  106. */
  107. @Override
  108. public boolean saveUser(UserForm userForm) {
  109. String username = userForm.getUsername();
  110. long count = this.count(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
  111. Assert.isTrue(count == 0, "用户名已存在");
  112. // 实体转换 form->entity
  113. User entity = userConverter.toEntity(userForm);
  114. // 设置默认加密密码
  115. String defaultEncryptPwd = passwordEncoder.encode(SystemConstants.DEFAULT_PASSWORD);
  116. entity.setPassword(defaultEncryptPwd);
  117. entity.setCreateBy(SecurityUtils.getUserId());
  118. // 新增用户
  119. boolean result = this.save(entity);
  120. if (result) {
  121. // 保存用户角色
  122. userRoleService.saveUserRoles(entity.getId(), userForm.getRoleIds());
  123. }
  124. return result;
  125. }
  126. /**
  127. * 更新用户
  128. *
  129. * @param userId 用户ID
  130. * @param userForm 用户表单对象
  131. * @return true|false
  132. */
  133. @Override
  134. @Transactional
  135. public boolean updateUser(Long userId, UserForm userForm) {
  136. String username = userForm.getUsername();
  137. long count = this.count(new LambdaQueryWrapper<User>()
  138. .eq(User::getUsername, username)
  139. .ne(User::getId, userId)
  140. );
  141. Assert.isTrue(count == 0, "用户名已存在");
  142. // form -> entity
  143. User entity = userConverter.toEntity(userForm);
  144. entity.setUpdateBy(SecurityUtils.getUserId());
  145. // 修改用户
  146. boolean result = this.updateById(entity);
  147. if (result) {
  148. // 保存用户角色
  149. userRoleService.saveUserRoles(entity.getId(), userForm.getRoleIds());
  150. }
  151. return result;
  152. }
  153. /**
  154. * 删除用户
  155. *
  156. * @param idsStr 用户ID,多个以英文逗号(,)分割
  157. * @return true|false
  158. */
  159. @Override
  160. public boolean deleteUsers(String idsStr) {
  161. Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的用户数据为空");
  162. // 逻辑删除
  163. List<Long> ids = Arrays.stream(idsStr.split(","))
  164. .map(Long::parseLong)
  165. .collect(Collectors.toList());
  166. return this.removeByIds(ids);
  167. }
  168. /**
  169. * 根据用户名获取认证凭证信息
  170. *
  171. * @param username 用户名
  172. * @return 用户认证凭证信息 {@link UserAuthCredentials}
  173. */
  174. @Override
  175. public UserAuthCredentials getAuthCredentialsByUsername(String username) {
  176. UserAuthCredentials userAuthCredentials = this.baseMapper.getAuthCredentialsByUsername(username);
  177. if (userAuthCredentials != null) {
  178. Set<String> roles = userAuthCredentials.getRoles();
  179. // 获取最大范围的数据权限
  180. Integer dataScope = roleService.getMaximumDataScope(roles);
  181. userAuthCredentials.setDataScope(dataScope);
  182. }
  183. return userAuthCredentials;
  184. }
  185. /**
  186. * 根据OpenID获取用户认证信息
  187. *
  188. * @param openId 微信OpenID
  189. * @return 用户认证信息
  190. */
  191. @Override
  192. public UserAuthCredentials getAuthCredentialsByOpenId(String openId) {
  193. if (StrUtil.isBlank(openId)) {
  194. return null;
  195. }
  196. UserAuthCredentials userAuthCredentials = this.baseMapper.getAuthCredentialsByOpenId(openId);
  197. if (userAuthCredentials != null) {
  198. Set<String> roles = userAuthCredentials.getRoles();
  199. // 获取最大范围的数据权限
  200. Integer dataScope = roleService.getMaximumDataScope(roles);
  201. userAuthCredentials.setDataScope(dataScope);
  202. }
  203. return userAuthCredentials;
  204. }
  205. /**
  206. * 根据手机号获取用户认证信息
  207. *
  208. * @param mobile 手机号
  209. * @return 用户认证信息
  210. */
  211. @Override
  212. public UserAuthCredentials getAuthCredentialsByMobile(String mobile) {
  213. if (StrUtil.isBlank(mobile)) {
  214. return null;
  215. }
  216. UserAuthCredentials userAuthCredentials = this.baseMapper.getAuthCredentialsByMobile(mobile);
  217. if (userAuthCredentials != null) {
  218. Set<String> roles = userAuthCredentials.getRoles();
  219. // 获取最大范围的数据权限
  220. Integer dataScope = roleService.getMaximumDataScope(roles);
  221. userAuthCredentials.setDataScope(dataScope);
  222. }
  223. return userAuthCredentials;
  224. }
  225. /**
  226. * 注册或绑定微信用户
  227. *
  228. * @param openId 微信OpenID
  229. * @return 是否成功
  230. */
  231. @Override
  232. @Transactional(rollbackFor = Exception.class)
  233. public boolean registerOrBindWechatUser(String openId) {
  234. if (StrUtil.isBlank(openId)) {
  235. return false;
  236. }
  237. // 查询是否已存在该openId的用户
  238. User existUser = this.getOne(
  239. new LambdaQueryWrapper<User>()
  240. .eq(User::getOpenid, openId)
  241. );
  242. if (existUser != null) {
  243. // 用户已存在,不需要注册
  244. return true;
  245. }
  246. // 创建新用户
  247. User newUser = new User();
  248. newUser.setNickname("微信用户"); // 默认昵称
  249. newUser.setUsername(openId); // TODO 后续替换为手机号
  250. newUser.setOpenid(openId);
  251. newUser.setGender(0); // 保密
  252. newUser.setUpdateBy(SecurityUtils.getUserId());
  253. newUser.setPassword(SystemConstants.DEFAULT_PASSWORD);
  254. newUser.setCreateTime(LocalDateTime.now());
  255. newUser.setUpdateTime(LocalDateTime.now());
  256. this.save(newUser);
  257. // 为了默认系统管理员角色,这里按需调整,实际情况绑定已存在的系统用户,另一种情况是给默认游客角色,然后由系统管理员设置用户的角色
  258. UserRole userRole = new UserRole();
  259. userRole.setUserId(newUser.getId());
  260. userRole.setRoleId(1L); // TODO 系统管理员
  261. userRoleService.save(userRole);
  262. return true;
  263. }
  264. /**
  265. * 根据手机号和OpenID注册用户
  266. *
  267. * @param mobile 手机号
  268. * @param openId 微信OpenID
  269. * @return 是否成功
  270. */
  271. @Override
  272. @Transactional(rollbackFor = Exception.class)
  273. public boolean registerUserByMobileAndOpenId(String mobile, String openId) {
  274. // 修改验证逻辑:允许 openId 为 null,支持仅通过手机号注册
  275. if (StrUtil.isBlank(mobile)) {
  276. log.warn("注册用户失败:手机号为空");
  277. return false;
  278. }
  279. // 先查询 c_user_info 表中是否已存在手机号对应的用户
  280. com.zsElectric.boot.business.model.entity.UserInfo existingUserInfo = userInfoService.getOne(
  281. new LambdaQueryWrapper<com.zsElectric.boot.business.model.entity.UserInfo>()
  282. .eq(com.zsElectric.boot.business.model.entity.UserInfo::getPhone, mobile)
  283. );
  284. if (existingUserInfo != null) {
  285. log.info("手机号 {} 对应的UserInfo已存在,ID: {}", mobile, existingUserInfo.getId());
  286. // 如果存在用户但没绑定openId,且提供了openId,则绑定openId
  287. if (StrUtil.isNotBlank(openId) && StrUtil.isBlank(existingUserInfo.getOpenid())) {
  288. log.info("为UserInfo {} 绑定 OpenID", existingUserInfo.getId());
  289. existingUserInfo.setOpenid(openId);
  290. existingUserInfo.setUpdateTime(LocalDateTime.now());
  291. return userInfoService.updateById(existingUserInfo);
  292. }
  293. // 如果提供了不同的openId,则更新
  294. else if (StrUtil.isNotBlank(openId) && !openId.equals(existingUserInfo.getOpenid())) {
  295. log.info("更新UserInfo {} 的 OpenID", existingUserInfo.getId());
  296. existingUserInfo.setOpenid(openId);
  297. existingUserInfo.setUpdateTime(LocalDateTime.now());
  298. return userInfoService.updateById(existingUserInfo);
  299. }
  300. // 如果已经绑定了相同的openId或未提供openId,则不需要任何操作
  301. return true;
  302. }
  303. // 不存在用户,创建新的 UserInfo
  304. log.info("创建新UserInfo,手机号: {}, OpenID: {}", mobile, openId);
  305. com.zsElectric.boot.business.model.entity.UserInfo newUserInfo = new com.zsElectric.boot.business.model.entity.UserInfo();
  306. newUserInfo.setPhone(mobile);
  307. newUserInfo.setOpenid(openId); // openId 可以为 null
  308. newUserInfo.setNickName("微信用户_" + mobile.substring(mobile.length() - 4)); // 使用手机号后4位作为昵称
  309. newUserInfo.setCreateTime(LocalDateTime.now());
  310. newUserInfo.setUpdateTime(LocalDateTime.now());
  311. boolean saved = userInfoService.save(newUserInfo);
  312. if (!saved) {
  313. log.error("保存UserInfo失败,手机号: {}", mobile);
  314. return false;
  315. }
  316. log.info("UserInfo创建成功,ID: {}, 手机号: {}", newUserInfo.getId(), mobile);
  317. // 注意:UserInfo 不需要分配角色,因为它是业务用户表,不是系统用户表
  318. // 如果需要系统登录权限,应该额外创建 User 记录并分配角色
  319. return true;
  320. }
  321. /**
  322. * 绑定用户微信OpenID
  323. *
  324. * @param userId 用户ID
  325. * @param openId 微信OpenID
  326. * @return 是否成功
  327. */
  328. @Override
  329. @Transactional(rollbackFor = Exception.class)
  330. public boolean bindUserOpenId(Long userId, String openId) {
  331. if (userId == null || StrUtil.isBlank(openId)) {
  332. return false;
  333. }
  334. // 检查是否已有其他用户绑定了此openId
  335. User existingUser = this.getOne(
  336. new LambdaQueryWrapper<User>()
  337. .eq(User::getOpenid, openId)
  338. .ne(User::getId, userId)
  339. );
  340. if (existingUser != null) {
  341. log.warn("OpenID {} 已被用户 {} 绑定,无法为用户 {} 绑定", openId, existingUser.getId(), userId);
  342. return false;
  343. }
  344. // 更新用户openId
  345. boolean updated = this.update(
  346. new LambdaUpdateWrapper<User>()
  347. .eq(User::getId, userId)
  348. .set(User::getOpenid, openId)
  349. .set(User::getUpdateTime, LocalDateTime.now())
  350. );
  351. return updated ;
  352. }
  353. /**
  354. * 获取导出用户列表
  355. *
  356. * @param queryParams 查询参数
  357. * @return {@link List<UserExportDTO>} 导出用户列表
  358. */
  359. @Override
  360. public List<UserExportDTO> listExportUsers(UserPageQuery queryParams) {
  361. boolean isRoot = SecurityUtils.isRoot();
  362. queryParams.setIsRoot(isRoot);
  363. List<UserExportDTO> exportUsers = this.baseMapper.listExportUsers(queryParams);
  364. if (CollectionUtil.isNotEmpty(exportUsers)) {
  365. //获取性别的字典项
  366. Map<String, String> genderMap = dictItemService.list(
  367. new LambdaQueryWrapper<DictItem>().eq(DictItem::getDictCode,
  368. DictCodeEnum.GENDER.getValue())
  369. ).stream()
  370. .collect(Collectors.toMap(DictItem::getValue, DictItem::getLabel)
  371. );
  372. exportUsers.forEach(item -> {
  373. String gender = item.getGender();
  374. if (StrUtil.isBlank(gender)) {
  375. return;
  376. }
  377. // 判断map是否为空
  378. if (genderMap.isEmpty()) {
  379. return;
  380. }
  381. item.setGender(genderMap.get(gender));
  382. });
  383. }
  384. return exportUsers;
  385. }
  386. /**
  387. * 获取登录用户信息
  388. *
  389. * @return {@link CurrentUserDTO} 用户信息
  390. */
  391. @Override
  392. public CurrentUserDTO getCurrentUserInfo() {
  393. String username = SecurityUtils.getUsername();
  394. // 获取登录用户基础信息
  395. User user = this.getOne(new LambdaQueryWrapper<User>()
  396. .eq(User::getUsername, username)
  397. .select(
  398. User::getId,
  399. User::getUsername,
  400. User::getNickname,
  401. User::getAvatar
  402. )
  403. );
  404. // entity->VO
  405. CurrentUserDTO userInfoVO = userConverter.toCurrentUserDto(user);
  406. // 用户角色集合
  407. Set<String> roles = SecurityUtils.getRoles();
  408. userInfoVO.setRoles(roles);
  409. // 用户权限集合
  410. if (CollectionUtil.isNotEmpty(roles)) {
  411. Set<String> perms = permissionService.getRolePermsFormCache(roles);
  412. userInfoVO.setPerms(perms);
  413. }
  414. return userInfoVO;
  415. }
  416. /**
  417. * 获取个人中心用户信息
  418. *
  419. * @param userId 用户ID
  420. * @return {@link UserProfileVO} 个人中心用户信息
  421. */
  422. @Override
  423. public UserProfileVO getUserProfile(Long userId) {
  424. UserBO entity = this.baseMapper.getUserProfile(userId);
  425. return userConverter.toProfileVo(entity);
  426. }
  427. /**
  428. * 修改个人中心用户信息
  429. *
  430. * @param formData 表单数据
  431. * @return true|false
  432. */
  433. @Override
  434. public boolean updateUserProfile(UserProfileForm formData) {
  435. Long userId = SecurityUtils.getUserId();
  436. User entity = userConverter.toEntity(formData);
  437. entity.setId(userId);
  438. return this.updateById(entity);
  439. }
  440. /**
  441. * 修改用户密码
  442. *
  443. * @param userId 用户ID
  444. * @param data 密码修改表单数据
  445. * @return true|false
  446. */
  447. @Override
  448. public boolean changePassword(Long userId, PasswordUpdateForm data) {
  449. User user = this.getById(userId);
  450. if (user == null) {
  451. throw new BusinessException("用户不存在");
  452. }
  453. String oldPassword = data.getOldPassword();
  454. // 校验原密码
  455. if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
  456. throw new BusinessException("原密码错误");
  457. }
  458. // 新旧密码不能相同
  459. if (passwordEncoder.matches(data.getNewPassword(), user.getPassword())) {
  460. throw new BusinessException("新密码不能与原密码相同");
  461. }
  462. // 判断新密码和确认密码是否一致
  463. if (passwordEncoder.matches(data.getNewPassword(), data.getConfirmPassword())) {
  464. throw new BusinessException("新密码和确认密码不一致");
  465. }
  466. String newPassword = data.getNewPassword();
  467. boolean result = this.update(new LambdaUpdateWrapper<User>()
  468. .eq(User::getId, userId)
  469. .set(User::getPassword, passwordEncoder.encode(newPassword))
  470. );
  471. if (result) {
  472. // 加入黑名单,重新登录
  473. String accessToken = SecurityUtils.getTokenFromRequest();
  474. tokenManager.invalidateToken(accessToken);
  475. }
  476. return result;
  477. }
  478. /**
  479. * 重置密码
  480. *
  481. * @param userId 用户ID
  482. * @param password 密码重置表单数据
  483. * @return true|false
  484. */
  485. @Override
  486. public boolean resetPassword(Long userId, String password) {
  487. return this.update(new LambdaUpdateWrapper<User>()
  488. .eq(User::getId, userId)
  489. .set(User::getPassword, passwordEncoder.encode(password))
  490. );
  491. }
  492. /**
  493. * 发送短信验证码(绑定或更换手机号)
  494. *
  495. * @param mobile 手机号
  496. * @return true|false
  497. */
  498. @Override
  499. public boolean sendMobileCode(String mobile) {
  500. // String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
  501. // TODO 为了方便测试,验证码固定为 1234,实际开发中在配置了厂商短信服务后,可以使用上面的随机验证码
  502. String code = "1234";
  503. Map<String, String> templateParams = new HashMap<>();
  504. templateParams.put("code", code);
  505. boolean result = smsService.sendSms(mobile, SmsTypeEnum.CHANGE_MOBILE, templateParams);
  506. if (result) {
  507. // 缓存验证码,5分钟有效,用于更换手机号校验
  508. String redisCacheKey = StrUtil.format(RedisConstants.Captcha.MOBILE_CODE, mobile);
  509. redisTemplate.opsForValue().set(redisCacheKey, code, 5, TimeUnit.MINUTES);
  510. }
  511. return result;
  512. }
  513. /**
  514. * 绑定或更换手机号
  515. *
  516. * @param form 表单数据
  517. * @return true|false
  518. */
  519. @Override
  520. public boolean bindOrChangeMobile(MobileUpdateForm form) {
  521. Long currentUserId = SecurityUtils.getUserId();
  522. User currentUser = this.getById(currentUserId);
  523. if (currentUser == null) {
  524. throw new BusinessException("用户不存在");
  525. }
  526. // 校验验证码
  527. String inputVerifyCode = form.getCode();
  528. String mobile = form.getMobile();
  529. String cacheKey = StrUtil.format(RedisConstants.Captcha.MOBILE_CODE, mobile);
  530. String cachedVerifyCode = redisTemplate.opsForValue().get(cacheKey);
  531. if (StrUtil.isBlank(cachedVerifyCode)) {
  532. throw new BusinessException("验证码已过期");
  533. }
  534. if (!inputVerifyCode.equals(cachedVerifyCode)) {
  535. throw new BusinessException("验证码错误");
  536. }
  537. // 验证完成删除验证码
  538. redisTemplate.delete(cacheKey);
  539. // 更新手机号码
  540. return this.update(
  541. new LambdaUpdateWrapper<User>()
  542. .eq(User::getId, currentUserId)
  543. .set(User::getMobile, mobile)
  544. );
  545. }
  546. /**
  547. * 发送邮箱验证码(绑定或更换邮箱)
  548. *
  549. * @param email 邮箱
  550. */
  551. @Override
  552. public void sendEmailCode(String email) {
  553. // String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
  554. // TODO 为了方便测试,验证码固定为 1234,实际开发中在配置了邮箱服务后,可以使用上面的随机验证码
  555. String code = "1234";
  556. mailService.sendMail(email, "邮箱验证码", "您的验证码为:" + code + ",请在5分钟内使用");
  557. // 缓存验证码,5分钟有效,用于更换邮箱校验
  558. String redisCacheKey = StrUtil.format(RedisConstants.Captcha.EMAIL_CODE, email);
  559. redisTemplate.opsForValue().set(redisCacheKey, code, 5, TimeUnit.MINUTES);
  560. }
  561. /**
  562. * 修改当前用户邮箱
  563. *
  564. * @param form 表单数据
  565. * @return true|false
  566. */
  567. @Override
  568. public boolean bindOrChangeEmail(EmailUpdateForm form) {
  569. Long currentUserId = SecurityUtils.getUserId();
  570. User currentUser = this.getById(currentUserId);
  571. if (currentUser == null) {
  572. throw new BusinessException("用户不存在");
  573. }
  574. // 获取前端输入的验证码
  575. String inputVerifyCode = form.getCode();
  576. // 获取缓存的验证码
  577. String email = form.getEmail();
  578. String redisCacheKey = StrUtil.format(RedisConstants.Captcha.EMAIL_CODE, email);
  579. String cachedVerifyCode = redisTemplate.opsForValue().get(redisCacheKey);
  580. if (StrUtil.isBlank(cachedVerifyCode)) {
  581. throw new BusinessException("验证码已过期");
  582. }
  583. if (!inputVerifyCode.equals(cachedVerifyCode)) {
  584. throw new BusinessException("验证码错误");
  585. }
  586. // 验证完成删除验证码
  587. redisTemplate.delete(redisCacheKey);
  588. // 更新邮箱地址
  589. return this.update(
  590. new LambdaUpdateWrapper<User>()
  591. .eq(User::getId, currentUserId)
  592. .set(User::getEmail, email)
  593. );
  594. }
  595. /**
  596. * 获取用户选项列表
  597. *
  598. * @return {@link List<Option<String>>} 用户选项列表
  599. */
  600. @Override
  601. public List<Option<String>> listUserOptions() {
  602. List<User> list = this.list(new LambdaQueryWrapper<User>()
  603. .eq(User::getStatus, 1)
  604. );
  605. return userConverter.toOptions(list);
  606. }
  607. }