|
@@ -0,0 +1,266 @@
|
|
|
+package com.zhentao.user.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.util.IdUtil;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.zhentao.enums.ApiServerException;
|
|
|
+import com.zhentao.exception.AsynException;
|
|
|
+import com.zhentao.tool.TokenUtils;
|
|
|
+import com.zhentao.user.domain.UserLogin;
|
|
|
+import com.zhentao.user.dto.*;
|
|
|
+import com.zhentao.user.service.UserLoginService;
|
|
|
+import com.zhentao.user.mapper.UserLoginMapper;
|
|
|
+import com.zhentao.vo.Result;
|
|
|
+import org.redisson.api.RLock;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.DigestUtils;
|
|
|
+
|
|
|
+import java.util.UUID;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+* @author 86183
|
|
|
+* @description 针对表【user_login(用户)】的数据库操作Service实现
|
|
|
+* @createDate 2025-06-03 18:38:51
|
|
|
+*/
|
|
|
+@Service
|
|
|
+public class UserLoginServiceImpl extends ServiceImpl<UserLoginMapper, UserLogin>
|
|
|
+ implements UserLoginService{
|
|
|
+ @Autowired
|
|
|
+ private UserLoginMapper userLoginMapper;
|
|
|
+ @Autowired
|
|
|
+ private RedissonClient redissonClient;
|
|
|
+ @Autowired
|
|
|
+ private StringRedisTemplate stringRedisTemplate;
|
|
|
+
|
|
|
+ //注册
|
|
|
+ @Override
|
|
|
+ public Result register(UserRegister userRegister) {
|
|
|
+ //打印用户注册的信息
|
|
|
+ System.err.println(userRegister);
|
|
|
+ //使用redisson客户端获取分布式锁,确保并发情况下用户注册的安全性
|
|
|
+ RLock lock = redissonClient.getLock(userRegister.getPhone() + userRegister.getPassword());
|
|
|
+ try {
|
|
|
+ boolean b = lock.tryLock(10, 20, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ if(b){
|
|
|
+ //用来判断验证码是否正确
|
|
|
+ String s = stringRedisTemplate.opsForValue().get(userRegister.getPhone());
|
|
|
+ System.err.println("redis取出来的验证码"+s);
|
|
|
+
|
|
|
+ //验证码不匹配就抛出异常
|
|
|
+ if(!s.equals(userRegister.getCode())){
|
|
|
+ throw new AsynException(ApiServerException.NOTE_ERROR);
|
|
|
+ }
|
|
|
+ //根据手机号查询信息
|
|
|
+ QueryWrapper<UserLogin> queryWrapper=new QueryWrapper<>();
|
|
|
+ queryWrapper.eq("user_mobile",userRegister.getPhone());
|
|
|
+ UserLogin one = this.getOne(queryWrapper);
|
|
|
+
|
|
|
+ if(one==null){
|
|
|
+ //新用户注册的流程
|
|
|
+ UserLogin userLogin=new UserLogin();
|
|
|
+ userLogin.setUserMobile(userRegister.getPhone());
|
|
|
+ userLogin.setUserUsername(userRegister.getUsername());
|
|
|
+ //随机字符串
|
|
|
+ String uuid = String.valueOf(UUID.randomUUID());
|
|
|
+ userLogin.setSalt(uuid);
|
|
|
+
|
|
|
+ //md5加密
|
|
|
+ String s1 = DigestUtils.md5DigestAsHex((uuid + userRegister.getPassword()).getBytes());
|
|
|
+ userLogin.setUserPassword(s1);
|
|
|
+
|
|
|
+ //生成唯一Id
|
|
|
+ long l = IdUtil.getSnowflake(1, 1).nextId();
|
|
|
+ //进行注册
|
|
|
+ boolean save = this.save(userLogin);
|
|
|
+ if(save){
|
|
|
+ return Result.OK(save,"注册成功");
|
|
|
+ }else{
|
|
|
+ return Result.ERR(save,"注册失败");
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ //老用户更新信息流程
|
|
|
+ one.setUserUsername(userRegister.getUsername());
|
|
|
+ //随机字符串
|
|
|
+ String uuid = String.valueOf(UUID.randomUUID());
|
|
|
+ one.setSalt(uuid);
|
|
|
+ //md5加密
|
|
|
+ String s1 = DigestUtils.md5DigestAsHex((uuid + userRegister.getPassword()).getBytes());
|
|
|
+ one.setUserPassword(s1);
|
|
|
+
|
|
|
+ //进行更新
|
|
|
+ boolean b1 = this.updateById(one);
|
|
|
+ if(b1){
|
|
|
+ return Result.OK(b1,"注册成功");
|
|
|
+ }else{
|
|
|
+ return Result.ERR(b1,"注册失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }catch (InterruptedException e){
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ }finally {
|
|
|
+ //释放锁
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //验证码
|
|
|
+ @Override
|
|
|
+ public Result note(NoteDto noteDto) {
|
|
|
+ //随机生成六位数
|
|
|
+ int randomSixDigit=100000 + (int)(Math.random() * 900000);
|
|
|
+ System.err.println("手机号:"+noteDto.getPhone());
|
|
|
+ System.err.println("验证码:"+randomSixDigit);
|
|
|
+ stringRedisTemplate.opsForValue().set(noteDto.getPhone(),randomSixDigit+"");
|
|
|
+
|
|
|
+ return Result.OK(randomSixDigit,"发送成功");
|
|
|
+ }
|
|
|
+ //登录
|
|
|
+ /**
|
|
|
+ * 用户登录方法
|
|
|
+ * 使用Redis分布式锁来防止并发登录
|
|
|
+ * @param userLoginDto 用户登录信息,包含手机号和验证码
|
|
|
+ * @return 登录结果,包括token和提示信息
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Result login(UserLoginDto userLoginDto) {
|
|
|
+ // 获取Redis锁,锁的键为用户手机号,防止并发登录
|
|
|
+ RLock lock = redissonClient.getLock(userLoginDto.getPhone() + "phone");
|
|
|
+ try {
|
|
|
+ // 尝试获取锁,等待时间10秒,锁的过期时间为20秒
|
|
|
+ boolean b = lock.tryLock(10, 20, TimeUnit.SECONDS);
|
|
|
+ if (b) {
|
|
|
+ // 打印用户登录信息,用于调试
|
|
|
+ System.err.println(userLoginDto);
|
|
|
+ // 从Redis中获取验证码
|
|
|
+ String s = stringRedisTemplate.opsForValue().get(userLoginDto.getPhone());
|
|
|
+ // 打印从Redis中获取的验证码,用于调试
|
|
|
+ System.err.println("redis取出来的验证码" + s);
|
|
|
+ // 验证码不匹配则抛出异常
|
|
|
+ if (!s.equals(userLoginDto.getCode())) {
|
|
|
+ throw new AsynException(ApiServerException.NOTE_ERROR);
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ // 查询数据库中是否存在该用户
|
|
|
+ QueryWrapper<UserLogin> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.eq("user_mobile", userLoginDto.getPhone());
|
|
|
+ UserLogin one = this.getOne(queryWrapper);
|
|
|
+ // 生成JWT token
|
|
|
+ String token = TokenUtils.generateToken(one.getId() + "");
|
|
|
+ stringRedisTemplate.opsForValue().set(one.getId()+"",token);
|
|
|
+ // 返回登录成功结果,包含tokens
|
|
|
+ return Result.OK(token, "登录成功");
|
|
|
+ } catch (NullPointerException e) {
|
|
|
+ // 用户不存在时返回错误结果
|
|
|
+ return Result.ERR("登录失败", "用户不存在");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ // 中断当前线程,重新抛出自定义异常
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ throw new AsynException(ApiServerException.NOTE_ERROR);
|
|
|
+ } finally {
|
|
|
+ // 释放锁
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ //账号密码登录
|
|
|
+ /**
|
|
|
+ * 使用用户名和密码进行用户登录的方法
|
|
|
+ * 该方法实现了用户认证和JWT令牌的生成
|
|
|
+ *
|
|
|
+ * @param userPassDto 包含用户名和密码的DTO对象
|
|
|
+ * @return 登录结果,包括登录状态和JWT令牌
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Result UserPassLogin(UserPassDto userPassDto) {
|
|
|
+ System.err.println(userPassDto);
|
|
|
+ // 获取Redisson客户端的锁对象,用于处理并发登录请求
|
|
|
+ RLock lock = redissonClient.getLock("user"+userPassDto.getUsername());
|
|
|
+ try {
|
|
|
+ // 尝试获取锁,设置等待和持有时间
|
|
|
+ boolean b = lock.tryLock(10, 20, TimeUnit.SECONDS);
|
|
|
+ if (b){
|
|
|
+ // 查询用户信息,根据用户名
|
|
|
+ QueryWrapper<UserLogin> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.eq("user_username",userPassDto.getUsername());
|
|
|
+ UserLogin one = this.getOne(queryWrapper);
|
|
|
+ // 如果用户不存在,抛出异常
|
|
|
+ if (one==null){
|
|
|
+ throw new AsynException(ApiServerException.NULL_USERNAME);
|
|
|
+ }
|
|
|
+ // 获取用户盐值,用于密码加密
|
|
|
+ String salt = one.getSalt();
|
|
|
+ // 加密用户输入的密码,并与数据库中的密码进行比较
|
|
|
+ String s = DigestUtils.md5DigestAsHex((salt + userPassDto.getPassword()).getBytes());
|
|
|
+ if (!s.equals(one.getUserPassword())){
|
|
|
+ throw new AsynException(ApiServerException.NULL_PASSWORD);
|
|
|
+ }
|
|
|
+ // 生成JWT令牌
|
|
|
+ String jwtToken = TokenUtils.generateToken(one.getId()+"");
|
|
|
+ // 返回登录成功结果和JWT令牌
|
|
|
+ return Result.OK("登录成功",jwtToken);
|
|
|
+ }else {
|
|
|
+ // 如果获取锁超时,返回错误信息
|
|
|
+ return Result.ERR("获取锁超时",null);
|
|
|
+ }
|
|
|
+ }catch (InterruptedException e){
|
|
|
+ // 如果线程被中断,恢复中断状态,并返回错误信息
|
|
|
+ System.err.println("所异常");
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ return Result.ERR("线程被中断",null);
|
|
|
+ }finally {
|
|
|
+ // 释放锁
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //忘记密码
|
|
|
+ @Override
|
|
|
+ public Result ForgetPass(ForgetPassDto forgetPassDto) {
|
|
|
+ RLock lock = redissonClient.getLock(forgetPassDto.getPhone() + "Phone");
|
|
|
+ try {
|
|
|
+ boolean b = lock.tryLock(10, 20, TimeUnit.SECONDS);
|
|
|
+ if (b) {
|
|
|
+ QueryWrapper<UserLogin> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.eq("user_mobile", forgetPassDto.getPhone());
|
|
|
+ UserLogin one = this.getOne(queryWrapper);
|
|
|
+ if (one == null) {
|
|
|
+ return Result.ERR("用户不存在", null);
|
|
|
+ }
|
|
|
+ // 获取Redis中的验证码
|
|
|
+ String s = stringRedisTemplate.opsForValue().get(forgetPassDto.getPhone());
|
|
|
+ // 验证码不匹配则抛出异常
|
|
|
+ if (!s.equals(forgetPassDto.getCode())) {
|
|
|
+ throw new AsynException(ApiServerException.NOTE_ERROR);
|
|
|
+ }
|
|
|
+ // 获取用户信息,根据手机号
|
|
|
+ String salt = one.getSalt();
|
|
|
+ String s1 = DigestUtils.md5DigestAsHex((salt + forgetPassDto.getPassword()).getBytes());
|
|
|
+ one.setUserPassword(s1);
|
|
|
+ boolean b1 = this.updateById(one);
|
|
|
+ if (b1){
|
|
|
+ return Result.OK("修改成功", null);
|
|
|
+ }else {
|
|
|
+ return Result.ERR("修改失败", null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|