UserLoginServiceImpl.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package com.zhentao.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.zhentao.enums.ApiServerException;
  6. import com.zhentao.exception.AsynException;
  7. import com.zhentao.tool.TokenUtils;
  8. import com.zhentao.user.domain.UserLogin;
  9. import com.zhentao.user.dto.*;
  10. import com.zhentao.user.service.UserLoginService;
  11. import com.zhentao.user.mapper.UserLoginMapper;
  12. import com.zhentao.vo.Result;
  13. import org.redisson.api.RLock;
  14. import org.redisson.api.RedissonClient;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.data.redis.core.StringRedisTemplate;
  17. import org.springframework.stereotype.Service;
  18. import org.springframework.util.DigestUtils;
  19. import java.util.UUID;
  20. import java.util.concurrent.TimeUnit;
  21. /**
  22. * @author 86183
  23. * @description 针对表【user_login(用户)】的数据库操作Service实现
  24. * @createDate 2025-06-03 18:38:51
  25. */
  26. @Service
  27. public class UserLoginServiceImpl extends ServiceImpl<UserLoginMapper, UserLogin>
  28. implements UserLoginService{
  29. @Autowired
  30. private UserLoginMapper userLoginMapper;
  31. @Autowired
  32. private RedissonClient redissonClient;
  33. @Autowired
  34. private StringRedisTemplate stringRedisTemplate;
  35. //注册
  36. @Override
  37. public Result register(UserRegister userRegister) {
  38. //打印用户注册的信息
  39. System.err.println(userRegister);
  40. //使用redisson客户端获取分布式锁,确保并发情况下用户注册的安全性
  41. RLock lock = redissonClient.getLock(userRegister.getPhone() + userRegister.getPassword());
  42. try {
  43. boolean b = lock.tryLock(10, 20, TimeUnit.SECONDS);
  44. if(b){
  45. //用来判断验证码是否正确
  46. String s = stringRedisTemplate.opsForValue().get(userRegister.getPhone());
  47. System.err.println("redis取出来的验证码"+s);
  48. //验证码不匹配就抛出异常
  49. if(!s.equals(userRegister.getCode())){
  50. throw new AsynException(ApiServerException.NOTE_ERROR);
  51. }
  52. //根据手机号查询信息
  53. QueryWrapper<UserLogin> queryWrapper=new QueryWrapper<>();
  54. queryWrapper.eq("user_mobile",userRegister.getPhone());
  55. UserLogin one = this.getOne(queryWrapper);
  56. if(one==null){
  57. //新用户注册的流程
  58. UserLogin userLogin=new UserLogin();
  59. userLogin.setUserMobile(userRegister.getPhone());
  60. userLogin.setUserUsername(userRegister.getUsername());
  61. //随机字符串
  62. String uuid = String.valueOf(UUID.randomUUID());
  63. userLogin.setSalt(uuid);
  64. //md5加密
  65. String s1 = DigestUtils.md5DigestAsHex((uuid + userRegister.getPassword()).getBytes());
  66. userLogin.setUserPassword(s1);
  67. //生成唯一Id
  68. long l = IdUtil.getSnowflake(1, 1).nextId();
  69. //进行注册
  70. boolean save = this.save(userLogin);
  71. if(save){
  72. return Result.OK(save,"注册成功");
  73. }else{
  74. return Result.ERR(save,"注册失败");
  75. }
  76. }else{
  77. //老用户更新信息流程
  78. one.setUserUsername(userRegister.getUsername());
  79. //随机字符串
  80. String uuid = String.valueOf(UUID.randomUUID());
  81. one.setSalt(uuid);
  82. //md5加密
  83. String s1 = DigestUtils.md5DigestAsHex((uuid + userRegister.getPassword()).getBytes());
  84. one.setUserPassword(s1);
  85. //进行更新
  86. boolean b1 = this.updateById(one);
  87. if(b1){
  88. return Result.OK(b1,"注册成功");
  89. }else{
  90. return Result.ERR(b1,"注册失败");
  91. }
  92. }
  93. }
  94. }catch (InterruptedException e){
  95. Thread.currentThread().interrupt();
  96. }finally {
  97. //释放锁
  98. lock.unlock();
  99. }
  100. return null;
  101. }
  102. //验证码
  103. @Override
  104. public Result note(NoteDto noteDto) {
  105. //随机生成六位数
  106. int randomSixDigit=100000 + (int)(Math.random() * 900000);
  107. System.err.println("手机号:"+noteDto.getPhone());
  108. System.err.println("验证码:"+randomSixDigit);
  109. stringRedisTemplate.opsForValue().set(noteDto.getPhone(),randomSixDigit+"");
  110. return Result.OK(randomSixDigit,"发送成功");
  111. }
  112. //登录
  113. /**
  114. * 用户登录方法
  115. * 使用Redis分布式锁来防止并发登录
  116. * @param userLoginDto 用户登录信息,包含手机号和验证码
  117. * @return 登录结果,包括token和提示信息
  118. */
  119. @Override
  120. public Result login(UserLoginDto userLoginDto) {
  121. // 获取Redis锁,锁的键为用户手机号,防止并发登录
  122. RLock lock = redissonClient.getLock(userLoginDto.getPhone() + "phone");
  123. try {
  124. // 尝试获取锁,等待时间10秒,锁的过期时间为20秒
  125. boolean b = lock.tryLock(10, 20, TimeUnit.SECONDS);
  126. if (b) {
  127. // 打印用户登录信息,用于调试
  128. System.err.println(userLoginDto);
  129. // 从Redis中获取验证码
  130. String s = stringRedisTemplate.opsForValue().get(userLoginDto.getPhone());
  131. // 打印从Redis中获取的验证码,用于调试
  132. System.err.println("redis取出来的验证码" + s);
  133. // 验证码不匹配则抛出异常
  134. if (!s.equals(userLoginDto.getCode())) {
  135. throw new AsynException(ApiServerException.NOTE_ERROR);
  136. }
  137. try {
  138. // 查询数据库中是否存在该用户
  139. QueryWrapper<UserLogin> queryWrapper = new QueryWrapper<>();
  140. queryWrapper.eq("user_mobile", userLoginDto.getPhone());
  141. UserLogin one = this.getOne(queryWrapper);
  142. // 生成JWT token
  143. String token = TokenUtils.generateToken(one.getId() + "");
  144. // 返回登录成功结果,包含token
  145. return Result.OK(token, "登录成功");
  146. } catch (NullPointerException e) {
  147. // 用户不存在时返回错误结果
  148. return Result.ERR("登录失败", "用户不存在");
  149. }
  150. }
  151. } catch (InterruptedException e) {
  152. // 中断当前线程,重新抛出自定义异常
  153. Thread.currentThread().interrupt();
  154. throw new AsynException(ApiServerException.NOTE_ERROR);
  155. } finally {
  156. // 释放锁
  157. lock.unlock();
  158. }
  159. return null;
  160. }
  161. //账号密码登录
  162. /**
  163. * 使用用户名和密码进行用户登录的方法
  164. * 该方法实现了用户认证和JWT令牌的生成
  165. *
  166. * @param userPassDto 包含用户名和密码的DTO对象
  167. * @return 登录结果,包括登录状态和JWT令牌
  168. */
  169. @Override
  170. public Result UserPassLogin(UserPassDto userPassDto) {
  171. System.err.println(userPassDto);
  172. // 获取Redisson客户端的锁对象,用于处理并发登录请求
  173. RLock lock = redissonClient.getLock("user"+userPassDto.getUsername());
  174. try {
  175. // 尝试获取锁,设置等待和持有时间
  176. boolean b = lock.tryLock(10, 20, TimeUnit.SECONDS);
  177. if (b){
  178. // 查询用户信息,根据用户名
  179. QueryWrapper<UserLogin> queryWrapper = new QueryWrapper<>();
  180. queryWrapper.eq("user_username",userPassDto.getUsername());
  181. UserLogin one = this.getOne(queryWrapper);
  182. // 如果用户不存在,抛出异常
  183. if (one==null){
  184. throw new AsynException(ApiServerException.NULL_USERNAME);
  185. }
  186. // 获取用户盐值,用于密码加密
  187. String salt = one.getSalt();
  188. // 加密用户输入的密码,并与数据库中的密码进行比较
  189. String s = DigestUtils.md5DigestAsHex((salt + userPassDto.getPassword()).getBytes());
  190. if (!s.equals(one.getUserPassword())){
  191. throw new AsynException(ApiServerException.NULL_PASSWORD);
  192. }
  193. // 生成JWT令牌
  194. String jwtToken = TokenUtils.generateToken(one.getId()+"");
  195. // 返回登录成功结果和JWT令牌
  196. return Result.OK("登录成功",jwtToken);
  197. }else {
  198. // 如果获取锁超时,返回错误信息
  199. return Result.ERR("获取锁超时",null);
  200. }
  201. }catch (InterruptedException e){
  202. // 如果线程被中断,恢复中断状态,并返回错误信息
  203. System.err.println("所异常");
  204. Thread.currentThread().interrupt();
  205. return Result.ERR("线程被中断",null);
  206. }finally {
  207. // 释放锁
  208. lock.unlock();
  209. }
  210. }
  211. //忘记密码
  212. @Override
  213. public Result ForgetPass(ForgetPassDto forgetPassDto) {
  214. RLock lock = redissonClient.getLock(forgetPassDto.getPhone() + "Phone");
  215. try {
  216. boolean b = lock.tryLock(10, 20, TimeUnit.SECONDS);
  217. if (b) {
  218. QueryWrapper<UserLogin> queryWrapper = new QueryWrapper<>();
  219. queryWrapper.eq("user_mobile", forgetPassDto.getPhone());
  220. UserLogin one = this.getOne(queryWrapper);
  221. if (one == null) {
  222. return Result.ERR("用户不存在", null);
  223. }
  224. // 获取Redis中的验证码
  225. String s = stringRedisTemplate.opsForValue().get(forgetPassDto.getPhone());
  226. // 验证码不匹配则抛出异常
  227. if (!s.equals(forgetPassDto.getCode())) {
  228. throw new AsynException(ApiServerException.NOTE_ERROR);
  229. }
  230. // 获取用户信息,根据手机号
  231. String salt = one.getSalt();
  232. String s1 = DigestUtils.md5DigestAsHex((salt + forgetPassDto.getPassword()).getBytes());
  233. one.setUserPassword(s1);
  234. boolean b1 = this.updateById(one);
  235. if (b1){
  236. return Result.OK("修改成功", null);
  237. }else {
  238. return Result.ERR("修改失败", null);
  239. }
  240. }
  241. } catch (InterruptedException e) {
  242. throw new RuntimeException(e);
  243. }
  244. return null;
  245. }
  246. }