增加重置密码修改用户信息功能

This commit is contained in:
戚辰先生 2024-11-30 18:13:22 +08:00
parent 455ee5ff73
commit 5cc0deb917
7 changed files with 83 additions and 7 deletions

View File

@ -0,0 +1,16 @@
package com.qqchen.deploy.backend.framework.exception;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import lombok.Getter;
@Getter
public class UniqueConstraintException extends BusinessException {
private final String field;
private final String value;
public UniqueConstraintException(ResponseCode code, String field, String value) {
super(code);
this.field = field;
this.value = value;
}
}

View File

@ -4,11 +4,13 @@ import com.qqchen.deploy.backend.framework.api.Response;
import com.qqchen.deploy.backend.framework.enums.ResponseCode; import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.exception.SystemException; import com.qqchen.deploy.backend.framework.exception.SystemException;
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.MalformedJwtException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
@ -76,4 +78,11 @@ public class GlobalExceptionHandler {
log.error("Unexpected error occurred", e); log.error("Unexpected error occurred", e);
return Response.error(ResponseCode.ERROR); return Response.error(ResponseCode.ERROR);
} }
@ExceptionHandler(UniqueConstraintException.class)
public Response<?> handleUniqueConstraintException(UniqueConstraintException e) {
String message = messageSource.getMessage(e.getErrorCode().getMessageKey(), new Object[] {e.getField(), e.getValue()}, LocaleContextHolder.getLocale());
log.warn("Unique constraint violation: {} = {}", e.getField(), e.getValue());
return Response.error(e.getErrorCode(), message);
}
} }

View File

@ -66,6 +66,7 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
@Transactional @Transactional
public D create(D dto) { public D create(D dto) {
validateDatabaseOperation("create"); validateDatabaseOperation("create");
validateUniqueConstraints(dto);
T entity = converter.toEntity(dto); T entity = converter.toEntity(dto);
T savedEntity = repository.save(entity); T savedEntity = repository.save(entity);
return converter.toDto(savedEntity); return converter.toDto(savedEntity);
@ -416,4 +417,12 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
"Database operation '" + operation + "' is not supported in integration service"); "Database operation '" + operation + "' is not supported in integration service");
} }
} }
/**
* 校验唯一约束
* 子类可以重写此方法实现具体的唯一性检查
*/
protected void validateUniqueConstraints(D dto) {
// 默认不做任何检查
}
} }

View File

@ -1,7 +1,7 @@
package com.qqchen.deploy.backend.repository; package com.qqchen.deploy.backend.repository;
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
import com.qqchen.deploy.backend.entity.User; import com.qqchen.deploy.backend.entity.User;
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.Optional; import java.util.Optional;
@ -9,5 +9,18 @@ import java.util.Optional;
@Repository @Repository
public interface IUserRepository extends IBaseRepository<User, Long> { public interface IUserRepository extends IBaseRepository<User, Long> {
/**
* 根据用户名查找未删除的用户用于登录等业务操作
*/
Optional<User> findByUsernameAndDeletedFalse(String username); Optional<User> findByUsernameAndDeletedFalse(String username);
/**
* 检查用户名是否存在包括已删除的记录
*/
boolean existsByUsername(String username);
/**
* 检查邮箱是否存在包括已删除的记录
*/
boolean existsByEmail(String email);
} }

View File

@ -3,6 +3,7 @@ package com.qqchen.deploy.backend.service.impl;
import com.qqchen.deploy.backend.entity.Role; import com.qqchen.deploy.backend.entity.Role;
import com.qqchen.deploy.backend.framework.enums.ResponseCode; import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
import com.qqchen.deploy.backend.model.RoleDTO; import com.qqchen.deploy.backend.model.RoleDTO;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.repository.IRoleRepository; import com.qqchen.deploy.backend.repository.IRoleRepository;
@ -42,4 +43,17 @@ public class RoleServiceImpl extends BaseServiceImpl<Role, RoleDTO, Long> implem
throw new BusinessException(ResponseCode.ROLE_NAME_EXISTS); throw new BusinessException(ResponseCode.ROLE_NAME_EXISTS);
} }
} }
@Override
protected void validateUniqueConstraints(RoleDTO dto) {
// 检查角色编码唯一性
if (repository.existsByCodeAndDeletedFalse(dto.getCode())) {
throw new UniqueConstraintException(ResponseCode.ROLE_CODE_EXISTS, "code", dto.getCode());
}
// 检查角色名称唯一性
if (repository.existsByNameAndDeletedFalse(dto.getName())) {
throw new UniqueConstraintException(ResponseCode.ROLE_NAME_EXISTS, "name", dto.getName());
}
}
} }

View File

@ -5,6 +5,7 @@ import com.qqchen.deploy.backend.framework.annotation.ServiceType;
import com.qqchen.deploy.backend.framework.annotation.Audited; import com.qqchen.deploy.backend.framework.annotation.Audited;
import com.qqchen.deploy.backend.framework.enums.ResponseCode; import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
import com.qqchen.deploy.backend.framework.security.SecurityUtils; import com.qqchen.deploy.backend.framework.security.SecurityUtils;
import com.qqchen.deploy.backend.framework.security.util.JwtTokenUtil; import com.qqchen.deploy.backend.framework.security.util.JwtTokenUtil;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
@ -27,6 +28,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -160,4 +162,17 @@ public class UserServiceImpl extends BaseServiceImpl<User, UserDTO, Long> implem
repository.save(user); repository.save(user);
log.info("用户 {} 密码已重置", user.getUsername()); log.info("用户 {} 密码已重置", user.getUsername());
} }
@Override
protected void validateUniqueConstraints(UserDTO dto) {
// 检查用户名唯一性包括已删除的记录
if (userRepository.existsByUsername(dto.getUsername())) {
throw new UniqueConstraintException(ResponseCode.USERNAME_EXISTS, "username", dto.getUsername());
}
// 检查邮箱唯一性包括已删除的记录
if (StringUtils.hasText(dto.getEmail()) && userRepository.existsByEmail(dto.getEmail())) {
throw new UniqueConstraintException(ResponseCode.EMAIL_EXISTS, "email", dto.getEmail());
}
}
} }

View File

@ -14,8 +14,8 @@ data.not.found=找不到ID为{0}的{1}
# 用户相关 # 用户相关
user.not.found=用户不存在 user.not.found=用户不存在
user.username.exists=用户名已存在 user.username.exists=用户名"{0}"已存在
user.email.exists=邮箱已存在 user.email.exists=邮箱"{0}"已存在
user.login.error=用户名或密码错误 user.login.error=用户名或密码错误
# 系统异常消息 # 系统异常消息
@ -42,8 +42,8 @@ jwt.token.missing=未提供登录凭证
# 角色相关错误消息 # 角色相关错误消息
role.not.found=角色不存在 role.not.found=角色不存在
role.code.exists=角色编码已存在 role.code.exists=角色编码"{0}"已存在
role.name.exists=角色名称已存在 role.name.exists=角色名称"{0}"已存在
role.in.use=角色正在使用中,无法删除 role.in.use=角色正在使用中,无法删除
role.admin.cannot.delete=不能删除超级管理员角色 role.admin.cannot.delete=不能删除超级管理员角色
role.admin.cannot.update=不能修改超级管理员角色 role.admin.cannot.update=不能修改超级管理员角色