381 lines
15 KiB
Java
381 lines
15 KiB
Java
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;
|
||
}
|
||
|
||
}
|