UserServiceImpl.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package com.example.demo.user.service.impl;
  2. import cn.hutool.core.util.IdUtil;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  5. import com.example.demo.common.utils.Md5Util;
  6. import com.example.demo.common.utils.RedisClient;
  7. import com.example.demo.common.utils.TokenUtils;
  8. import com.example.demo.user.domain.User;
  9. import com.example.demo.user.dto.LoginDto;
  10. import com.example.demo.user.dto.PerfectDto;
  11. import com.example.demo.user.dto.PhoneDto;
  12. import com.example.demo.user.dto.RegisterDto;
  13. import com.example.demo.user.service.UserService;
  14. import com.example.demo.user.dao.UserMapper;
  15. import com.example.demo.user.vo.ResultVo;
  16. import lombok.extern.slf4j.Slf4j;
  17. import org.redisson.api.RLock;
  18. import org.redisson.api.RedissonClient;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.data.redis.core.RedisTemplate;
  21. import org.springframework.stereotype.Service;
  22. import java.util.UUID;
  23. import java.util.concurrent.TimeUnit;
  24. /**
  25. * @author 徐乐
  26. * @description 针对表【user(用户基础信息表)】的数据库操作Service实现
  27. * @createDate 2025-06-04 17:31:35
  28. */
  29. @Slf4j
  30. @Service
  31. public class UserServiceImpl extends ServiceImpl<UserMapper, User>
  32. implements UserService{
  33. @Autowired
  34. private UserMapper userMapper;
  35. @Autowired
  36. private RedissonClient redissonClient;
  37. @Autowired
  38. private RedisTemplate<String,String> redisTemplate;
  39. @Autowired
  40. private RedisClient redisClient;
  41. @Override
  42. public ResultVo register(RegisterDto dto) {
  43. // 获取验证码
  44. Object code = getVerificationCode(dto.getPhone());
  45. if (code == null) {
  46. return ResultVo.error(201, "验证码已过期");
  47. }
  48. String codeStr = String.valueOf(code);
  49. String userCode = dto.getCode();
  50. if (!codeStr.equals(userCode)) {
  51. return ResultVo.error(202, "验证码错误");
  52. }
  53. // 删除已使用的验证码
  54. deleteVerificationCode(dto.getPhone());
  55. QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
  56. userQueryWrapper.eq("phone", dto.getPhone());
  57. log.info("加锁");
  58. RLock lock = redissonClient.getLock(dto.getPhone());
  59. try {
  60. log.info("获取锁");
  61. boolean lockSuccess = lock.tryLock(3, TimeUnit.SECONDS);
  62. if (!lockSuccess) {
  63. throw new RuntimeException("操作频繁,请稍后再试");
  64. }
  65. User user = userMapper.selectOne(userQueryWrapper);
  66. if (user != null) {
  67. return ResultVo.error("用户已存在");
  68. }
  69. log.info("注册");
  70. User u = new User();
  71. u.setId(IdUtil.getSnowflake().nextId());
  72. //生成盐值
  73. String uuid = UUID.randomUUID().toString().replaceAll("-", "");
  74. u.setSalt(uuid);
  75. //获取密码
  76. String password = dto.getPassword();
  77. //加密
  78. String md5Password = Md5Util.MD5(uuid + password);
  79. u.setPassword(md5Password);
  80. u.setPhone(dto.getPhone());
  81. u.setEmail(u.getPhone()+"@example.com");
  82. userMapper.insert(u);
  83. return ResultVo.success("注册成功");
  84. } catch (Exception e) {
  85. e.printStackTrace();
  86. throw new RuntimeException("注册过程中出现异常,请稍后再试");
  87. } finally {
  88. if (lock.isLocked() && lock.isHeldByCurrentThread()) {
  89. log.info("释放锁");
  90. lock.unlock();
  91. }
  92. }
  93. }
  94. /**
  95. * 统一获取验证码方法
  96. * @param phone 手机号
  97. * @return 验证码
  98. */
  99. private Object getVerificationCode(String phone) {
  100. String key = "CODE:" + phone;
  101. return redisClient.get(key);
  102. }
  103. /**
  104. * 统一删除验证码方法
  105. * @param phone 手机号
  106. */
  107. private void deleteVerificationCode(String phone) {
  108. String key = "CODE:" + phone;
  109. redisClient.del(key);
  110. }
  111. @Override
  112. public ResultVo login(LoginDto dto) {
  113. QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
  114. userQueryWrapper.eq("phone",dto.getPhone());
  115. User user = userMapper.selectOne(userQueryWrapper);
  116. if (user==null){
  117. return ResultVo.error("用户不存在");
  118. }
  119. //获取盐值
  120. String salt = user.getSalt();
  121. //获取密码
  122. String password = dto.getPassword();
  123. //加密
  124. String encryptedPassword = Md5Util.MD5(salt + password);
  125. if (encryptedPassword.equals(user.getPassword())){
  126. String token = TokenUtils.createJwtToken(user.getId().toString());
  127. // 使用用户ID作为键名的一部分
  128. redisTemplate.opsForValue().set("userToken:" + user.getId(), token);
  129. redisTemplate.expire("userToken:" + user.getId(), 24, TimeUnit.HOURS); // 设置24小时过期
  130. return ResultVo.success(token);
  131. }
  132. return ResultVo.error("用户名或密码有误");
  133. }
  134. @Override
  135. public ResultVo phoneLogin(PhoneDto dto) {
  136. // 参数校验
  137. if (dto.getPhone() == null ||!dto.getPhone().matches("1[3-9]\\d{9}")) {
  138. return ResultVo.error(400, "手机号格式错误");
  139. }
  140. // 获取验证码
  141. Integer code = (Integer) getVerificationCode(dto.getPhone());
  142. if (code == null) {
  143. // logger.info("手机号 {} 验证码已过期", dto.getPhone());
  144. return ResultVo.error(201, "验证码已过期");
  145. }
  146. // 验证验证码
  147. String codeStr = String.valueOf(code);
  148. String userCode = dto.getCode();
  149. if (userCode == null ||!userCode.matches("\\d{6}")) {
  150. // logger.info("手机号 {} 输入的验证码格式错误", dto.getPhone());
  151. return ResultVo.error(203, "验证码格式错误");
  152. }
  153. if (!codeStr.equals(userCode)) {
  154. // logger.info("手机号 {} 验证码错误,Redis: {}, 用户输入: {}",
  155. // dto.getPhone(), codeStr, userCode);
  156. return ResultVo.error(202, "验证码错误");
  157. }
  158. // 验证通过后删除验证码
  159. deleteVerificationCode(dto.getPhone());
  160. // 先判断账号是否存在
  161. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  162. queryWrapper.lambda().eq(User::getPhone, dto.getPhone());
  163. User user = userMapper.selectOne(queryWrapper);
  164. // if (user == null) {
  165. // user.setUsername("随机账户"+String.valueOf(IdUtil.getSnowflake().nextId()));
  166. // user.setId(IdUtil.getSnowflake().nextId());
  167. // userMapper.insert(user);
  168. // redisClient.set("uid", user.getId());
  169. // redisClient.expire("uid", 60*60);
  170. // Long id = user.getId();
  171. // String token = AppJwtUtil.getToken(id);
  172. // redisClient.set("token", token);
  173. // Map<String, String> map = new HashMap<>();
  174. // map.put("token",token);
  175. // return ResultVo.success(map);
  176. // }
  177. // redisClient.set("uid", user.getId());
  178. // redisClient.expire("uid", 60*60);
  179. String token = TokenUtils.createJwtToken(user.getId().toString());
  180. // 使用用户ID作为键名的一部分
  181. redisTemplate.opsForValue().set("userToken:" + user.getId(), token);
  182. redisTemplate.expire("userToken:" + user.getId(), 24, TimeUnit.HOURS); // 设置24小时过期
  183. return ResultVo.success(token);
  184. }
  185. @Override
  186. public ResultVo forget(RegisterDto dto) {
  187. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  188. queryWrapper.eq("phone",dto.getPhone());
  189. User user = userMapper.selectOne(queryWrapper);
  190. if (user==null){
  191. return ResultVo.error("用户不存在");
  192. }
  193. // 获取验证码
  194. Object code = getVerificationCode(dto.getPhone());
  195. if (code == null) {
  196. return ResultVo.error(201, "验证码已过期");
  197. }
  198. String codeStr = String.valueOf(code);
  199. String userCode = dto.getCode();
  200. if (!codeStr.equals(userCode)) {
  201. return ResultVo.error(202, "验证码错误");
  202. }
  203. // 删除已使用的验证码
  204. deleteVerificationCode(dto.getPhone());
  205. //生成盐值
  206. String uuid = UUID.randomUUID().toString().replaceAll("-", "");
  207. user.setSalt(uuid);
  208. //获取密码
  209. String password = dto.getPassword();
  210. //加密
  211. String md5Password = Md5Util.MD5(uuid + password);
  212. user.setPassword(md5Password);
  213. userMapper.updateById(user);
  214. return ResultVo.success("找回成功");
  215. }
  216. @Override
  217. public ResultVo logout(String token) {
  218. if (token == null || token.isEmpty()) {
  219. return ResultVo.error("无效的token");
  220. }
  221. try {
  222. // 解析token获取用户ID
  223. Long userId = TokenUtils.getUserId(token);
  224. if (userId == null) {
  225. return ResultVo.error("无效的token");
  226. }
  227. // 从Redis删除token
  228. redisTemplate.delete("userToken:" + userId);
  229. // 可以设置token黑名单,防止已注销的token被再次使用
  230. String blacklistKey = "token:blacklist:" + token;
  231. redisTemplate.opsForValue().set(blacklistKey, "1");
  232. redisTemplate.expire(blacklistKey, 24, TimeUnit.HOURS); // 设置黑名单24小时过期
  233. log.info("用户{}已成功退出登录", userId);
  234. return ResultVo.success("退出成功");
  235. } catch (Exception e) {
  236. log.error("注销失败", e);
  237. return ResultVo.error("注销失败,请稍后再试");
  238. }
  239. }
  240. @Override
  241. public ResultVo perfect(String token,PerfectDto dto) {
  242. Long userId = TokenUtils.getUserId(token);
  243. if (userId==null){
  244. return ResultVo.error("用户不存在");
  245. }
  246. User user = userMapper.selectById(userId);
  247. user.setUsername(dto.getUsername());
  248. user.setEmail(dto.getEmail());
  249. user.setAvatar(dto.getAvatar());
  250. userMapper.updateById(user);
  251. return ResultVo.success("完善用户信息成功");
  252. }
  253. }