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 org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.util.List; import java.util.Optional; 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 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 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(); userLogin.setId(l); //进行注册 System.err.println(userLogin); 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 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 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 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; } //获取用户信息 @Override public UserLogin getUserById(Long id) { UserLogin userLogin = userLoginMapper.selectById(id); return userLogin; } @Override public List searchFriends(String keyword) { if(!StringUtils.hasLength(keyword)) return null; //根据昵称、账号进行模糊查询 List list=this.query() .like("user_username",keyword) .or() .like("nick_name",keyword) .list(); return list; } @Override public Optional findById(Long userId) { return Optional.ofNullable(userLoginMapper.selectById(userId)); } }