Files
pkAssistant/src/main/java/vvpkassistant/User/service/UserServiceImpl.java
2025-08-14 21:06:31 +08:00

381 lines
15 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package vvpkassistant.User.service;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.zxing.WriterException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import vvpkassistant.Data.WxChatParam;
import vvpkassistant.Tools.BcryptUtils;
import vvpkassistant.Tools.CacheHolder;
import vvpkassistant.Tools.QRCodeUtil;
import vvpkassistant.Tools.VVTools;
import vvpkassistant.User.mapper.UserDao;
import vvpkassistant.User.model.*;
import vvpkassistant.User.model.DTO.LoginInfoDTO;
import vvpkassistant.User.model.DTO.ScanInfoDTO;
import vvpkassistant.User.model.DTO.UserModelDTO;
import vvpkassistant.User.model.enumeration.LoginStatusEnum;
import vvpkassistant.common.ErrorCode;
import vvpkassistant.exception.BusinessException;
import vvpkassistant.mail.model.MailModel;
import vvpkassistant.mail.service.MailService;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/*
* @author: ziin
* @date: 2025/8/4 16:19
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements UserService {
@Resource
private UserDao userDao;
@Resource
private WxChatParam wxChatParam;
@Autowired
private MailService mailService;
private final Cache<String, LoginInfoDTO> qrcodeCache = Caffeine.newBuilder()
.expireAfterWrite(2, TimeUnit.MINUTES)
.build();
@Override
public UserModelVO loginWithMail(UserModelDTO model) {
if (model.getUserNameOrEmail().isEmpty()){
throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名或邮箱不能为空");
}
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(UserModel::getEmail,model.getUserNameOrEmail())
.or()
.eq(UserModel::getUserName,model.getUserNameOrEmail())
.in(UserModel::getStatus, 0,2);
UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
if (userModel == null) {
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
}
String password = userModel.getPassword();
UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
if (BcryptUtils.matchPassword(password, model.getPassword())) {
StpUtil.login(userModel.getId());
userModelVO.setToken(StpUtil.getTokenValue());
userModelVO.setChatInfo(wxChatParam);
return userModelVO;
}else {
throw new BusinessException(ErrorCode.PASSWORD_ERROR);
}
}
@Override
public UserModelVO updateUserInfo(UserModelDTO userModelDTO) {
UserModel userInfo = userDao.selectById(userModelDTO.getId());
if (userInfo == null) {
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
}
// 用户没有密码的情况下设置密码
if (userInfo.getPassword() == null && userModelDTO.getNewPassword() != null) {
if (!userModelDTO.getNewPassword().isEmpty()){
if (userModelDTO.getNewPassword().length()<6){
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
}
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
}
}
if (userModelDTO.getEmail() != null) {
mailService.sendVerificationMail(userModelDTO.getEmail(), userModelDTO.getId());
}
// 用户有密码的情况下重新设置密码
if (userInfo.getPassword() != null && userModelDTO.getOldPassword() != null) {
if (BcryptUtils.matchPassword(userInfo.getPassword(),userModelDTO.getOldPassword())) {
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
}else {
throw new BusinessException(ErrorCode.PASSWORD_ERROR,"旧密码不正确");
}
}
UserModel userModel = BeanUtil.copyProperties(userModelDTO, UserModel.class);
int i = userDao.updateById(userModel);
// 返回结果
UserModel afterUserInfo = userDao.selectById(userModel.getId());
UserModelVO userModelVO = BeanUtil.copyProperties(afterUserInfo, UserModelVO.class);
userModelVO.setNewAccount(false);
if (i == 1){
return userModelVO;
}else {
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
}
}
@Override
public UserModelVO addUserWithMail(UserModelDTO userModelDTO) {
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
LambdaQueryWrapper<UserModel> usernameWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(UserModel::getEmail,userModelDTO.getEmail());
UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
UserModel usernameModel = userDao.selectOne(usernameWrapper
.eq(UserModel::getUserName, userModelDTO.getUserName()));
if (userModel != null) {
throw new BusinessException(ErrorCode.MAIL_ALREADY_EXIST);
}
if (usernameModel != null) {
throw new BusinessException(ErrorCode.USERNAME_ALREADY_EXIST);
}
if (userModelDTO.getPassword().length() < 6 ){
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
}
if (userModelDTO.getUserName().isEmpty()){
throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名不能为空");
}
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
userModelDTO.setCreateTime(VVTools.currentTimeStamp());
//设置状态为待验证
userModelDTO.setStatus(2);
//设置积分为0
userModelDTO.setPoints(0);
UserModel userModelEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
userModelEntity.setMailVerification(1);
if ( userDao.insert(userModelEntity) != 1){
throw new BusinessException(ErrorCode.ADD_FAILED,"用户注册失败");
}
mailService.sendMail(userModelDTO.getEmail(),userModelEntity.getId());
// 判断用户是否为邀请用户
if (userModelDTO.getInviterId() != null) {
UserModel oldUser = userDao.selectById(userModelDTO.getInviterId());
oldUser.setPoints(oldUser.getPoints() + 10);
userDao.updateById(oldUser);
}
UserModelVO userModelVO = BeanUtil.copyProperties(userModelEntity, UserModelVO.class);
StpUtil.login(userModelVO.getId());
userModelVO.setToken(StpUtil.getTokenValue());
userModelVO.setHavaPassword(true);
userModelVO.setNewAccount(true);
userModelVO.setChatInfo(wxChatParam);
log.info("用户{}注册,邮箱{},手机号{}",userModelVO.getId(),userModelVO.getEmail(),userModelVO.getPhoneNumber());
return userModelVO;
}
@Override
public Boolean activateAccount(String token) {
Integer userId = SaTempUtil.parseToken(token, Integer.class);
UserModel userModel = userDao.selectById(userId);
if (userModel == null) {
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
}
if (userModel.getStatus() == 0){
throw new BusinessException(ErrorCode.USER_HAS_ACTIVATED);
}
userModel.setStatus(0);
userModel.setMailVerification(0);
if (userDao.updateById(userModel) == 1){
return true;
}else {
throw new BusinessException(ErrorCode.UPDATE_FAILED,"激活失败");
}
}
@Override
public Boolean verificationMail(String token) {
Integer userId = SaTempUtil.parseToken(token, Integer.class);
UserModel userModel = userDao.selectById(userId);
userModel.setMailVerification(0);
if (userDao.updateById(userModel) == 1){
return true;
}
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"邮箱验证失败");
}
@Override
public QrcodeVO generatedQrcode() {
String uuid = UUID.randomUUID().toString();
QrcodeEntity qrcodeEntity = new QrcodeEntity();
qrcodeEntity.setUuid(uuid);
qrcodeEntity.setType("qrcdoe");
String base64QR = null;
try {
base64QR = QRCodeUtil.generateQRCode(JSONUtil.toJsonStr(qrcodeEntity), 200, 200);
} catch (WriterException | IOException e) {
log.error(e.getMessage());
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"二维码生成失败");
}
LoginInfoDTO loginInfoDTO = new LoginInfoDTO();
loginInfoDTO.setStatus(LoginStatusEnum.UNSCANNED.name());
loginInfoDTO.setUuid(uuid);
// 二维码uuid绑定存入缓存
qrcodeCache.put(uuid,loginInfoDTO);
// 返回生成的二维码信息
QrcodeVO vo = QrcodeVO.builder().uuid(uuid).qrcode("data:image/png;base64," + base64QR).build();
log.info("-------生成二维码成功:{}-------", uuid);
return vo;
}
@Override
public Object checkQrcode(String uuid) {
LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(uuid);
if (loginInfoDTO == null) {
throw new BusinessException(ErrorCode.QRCODE_EXPIRED);
}
if (Objects.equals(loginInfoDTO.getStatus(), LoginStatusEnum.SCANNED.name())) {
return loginInfoDTO;
}
if (LoginStatusEnum.CONFIRMED.name().equals(loginInfoDTO.getStatus())) {
UserModel userModel = userDao.selectById(loginInfoDTO.getId());
StpUtil.login(userModel.getId());
UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
userModelVO.setToken(StpUtil.getTokenValue());
userModelVO.setChatInfo(wxChatParam);
return userModelVO;
}
return null;
}
@Override
public LoginInfoDTO scanQrcode(ScanInfoDTO scanInfoDTO) {
LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(scanInfoDTO.getUuid());
if (loginInfoDTO != null) {
loginInfoDTO.setStatus(LoginStatusEnum.SCANNED.name());
qrcodeCache.put(scanInfoDTO.getUuid(),loginInfoDTO);
}
log.info("-------扫码成功uuid:{}-------", scanInfoDTO.getUuid());
return loginInfoDTO;
}
@Override
public void confirm(ScanInfoDTO scanInfoDTO) {
LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(scanInfoDTO.getUuid());
if (loginInfoDTO != null) {
loginInfoDTO.setStatus(LoginStatusEnum.CONFIRMED.name());
loginInfoDTO.setId(scanInfoDTO.getId());
qrcodeCache.put(scanInfoDTO.getUuid(),loginInfoDTO);
}
log.info("-------确认登录成功uuid:{}-------", scanInfoDTO.getUuid());
}
@Override
public void logOut(Integer id) {
StpUtil.logout(id);
}
@Override
public boolean setPassWord(UserModelDTO userModelDTO) {
UserModel userModel = userDao.selectById(userModelDTO.getId());
if (userModel == null) {
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
}
if (userModel.getPassword()!= null){
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"已设置过密码");
}
if (userModelDTO.getPassword().length()< 6 ){
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
}
if (!Objects.equals(userModelDTO.getPassword(), userModelDTO.getConfirmPassword())) {
log.error("密码{},确认密码{}",userModelDTO.getPassword(),userModelDTO.getConfirmPassword());
throw new BusinessException(ErrorCode.PARAMS_ERROR,"两次密码输入不一致");
}else{
UserModel saveEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
saveEntity.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
return userDao.updateById(saveEntity) == 1 ;
}
}
@Override
public Object sendForgetPassWordMail(MailModel mailModel) {
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
UserModel userModel = userDao.selectOne(lambdaQueryWrapper
.eq(UserModel::getEmail, mailModel.getMailAddress())
.eq(UserModel::getStatus, 0)
.eq(UserModel::getMailVerification, 0));
if (userModel == null) {
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
}
mailService.sendForgetPassWordMail(mailModel.getMailAddress(),userModel.getId());
return true;
}
@Override
public Object resetPassWord(UserModelDTO userModelDTO) {
Integer i = SaTempUtil.parseToken(userModelDTO.getToken(), Integer.class);
UserModel userModel = userDao.selectById(i);
if (userModel == null) {
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
}
if (userModelDTO.getPassword().equals(userModelDTO.getConfirmPassword())) {
UserModel updateEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
updateEntity.setPassword(BcryptUtils.encryptPassword(updateEntity.getPassword()));
return userDao.updateById(updateEntity) == 1;
}
return false;
}
@Override
public Boolean updateUserMail(MailModel mailModel) {
String mail = CacheHolder.VERIFICATION_MAIL.getIfPresent(mailModel.getCode());
if (mail != null && mail.isEmpty()) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"验证码过期或验证码错误");
}
LambdaQueryWrapper<UserModel> duplicateMailUserWrapper = new LambdaQueryWrapper<>();
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
UserModel duplicateMailUser = userDao.selectOne(duplicateMailUserWrapper
.eq(UserModel::getEmail, mailModel.getMailAddress()));
if (duplicateMailUser != null) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"邮箱地址已被使用");
}
UserModel userModel = userDao.selectOne(lambdaQueryWrapper
.eq(UserModel::getEmail, mail)
.eq(UserModel::getMailVerification, 0 ));
if (userModel == null) {
throw new BusinessException(ErrorCode.USER_MAIL_NOT_VERIFICATION);
}
userModel.setEmail(mailModel.getMailAddress());
mailService.sendVerificationMail(mailModel.getMailAddress(),userModel.getId());
userModel.setMailVerification(1);
return userDao.updateById(userModel) == 1;
}
@Override
public Boolean checkUserName(UserModelDTO userModelDTO) {
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
UserModel userModel = userDao.selectOne(lambdaQueryWrapper
.eq(UserModel::getUserName, userModelDTO.getUserName()));
return userModel == null;
}
}