| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- package com.ruoyi.app.user;
- import com.ruoyi.common.constant.CacheConstants;
- import com.ruoyi.common.core.redis.RedisCache;
- import com.ruoyi.common.exception.ServiceException;
- import com.ruoyi.common.utils.MessageUtils;
- import com.ruoyi.system.domain.InfoUser;
- import com.ruoyi.system.mapper.InfoUserMapper;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import java.time.Instant;
- import java.time.temporal.ChronoUnit;
- import java.util.Date;
- /** 普通用户主动注销;调用登录恢复前必须已经完成短信或第三方身份验证。 */
- @Service
- public class UserCancellationService {
- private final InfoUserMapper users;
- private final RedisCache redis;
- private final int graceDays;
- public UserCancellationService(InfoUserMapper users, RedisCache redis,
- @Value("${user.cancellation.grace-days:7}") int graceDays) {
- this.users = users; this.redis = redis;
- this.graceDays = graceDays > 0 && graceDays <= 365 ? graceDays : 7;
- }
- public record CancellationView(
- @com.fasterxml.jackson.annotation.JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- Date cancellationDeadlineAt, int graceDays) { }
- @Transactional(rollbackFor = Exception.class)
- public CancellationView request(Long userId) {
- // 与认证恢复共用数据库行锁;重复申请不能延长原截止时间。
- InfoUser user = users.selectCancellationUserForUpdate(userId);
- requireUser(user);
- if (!"0".equals(user.getDelFlag())) throw unavailable();
- Date deadline = Date.from(Instant.now().plus(graceDays, ChronoUnit.DAYS));
- if (users.requestUserCancellation(userId, deadline) != 1) throw unavailable();
- redis.deleteKeys(CacheConstants.USER_TOKEN_KEY + userId + ":*");
- return new CancellationView(deadline, graceDays);
- }
- @Transactional(rollbackFor = Exception.class)
- public InfoUser authenticatedLogin(Long userId) {
- // 登录入口的外层事务持有此锁至签发新会话完成,防止并发注销覆盖恢复。
- InfoUser user = users.selectCancellationUserForUpdate(userId);
- requireUser(user);
- if ("0".equals(user.getDelFlag())) return user;
- Date now = new Date();
- if (!canRecover(user, now) || users.restoreCancelledUser(userId, now) != 1) throw unavailable();
- user.setDelFlag("0"); user.setCancellationDeadlineAt(null);
- return user;
- }
- public static boolean canRecover(InfoUser user, Date now) {
- return user != null && "0".equals(user.getUserType()) && "0".equals(user.getStatus())
- && "1".equals(user.getDelFlag()) && user.getCancellationDeadlineAt() != null
- && user.getCancellationDeadlineAt().after(now);
- }
- private void requireUser(InfoUser user) {
- if (user == null || !"0".equals(user.getUserType()) || !"0".equals(user.getStatus())) throw unavailable();
- }
- private ServiceException unavailable() { return new ServiceException(MessageUtils.message("no.user.stop")); }
- }
|