From 08043672f9a1c0a2f23b441c52b56bec17f30002 Mon Sep 17 00:00:00 2001 From: meowrain Date: Sun, 18 Jan 2026 17:31:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E9=82=AE=E7=AE=B1=E7=AE=A1=E7=90=86=E5=92=8C=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E8=B5=84=E6=96=99=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复邮箱验证码接口参数绑定问题 (@RequestParam -> @ModelAttribute) - 实现异步邮件发送,使用独立线程池避免阻塞 - 完成邮箱绑定/解绑功能 - 实现修改密码功能 - 实现用户资料查询和更新功能 - 添加个人资料相关 DTO - 更新网关过滤器使用新的服务名称 Co-Authored-By: Claude --- .../gateway/filter/AuthGlobalFilter.java | 2 +- .../userservice/config/AsyncConfig.java | 40 +++ .../controller/UserController.java | 28 +- .../userservice/dto/req/BindEmailRequest.java | 2 +- .../dto/req/ChangePasswordRequestDTO.java | 13 + .../dto/req/UserProfileUpdateRequestDTO.java | 13 + .../dto/resp/UserProfileRespDTO.java | 10 + .../userservice/service/EmailService.java | 7 + .../userservice/service/UserService.java | 20 +- .../service/impl/EmailServiceImpl.java | 21 ++ .../service/impl/UserServiceImpl.java | 242 +++++++++++++----- 11 files changed, 310 insertions(+), 88 deletions(-) create mode 100644 aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/config/AsyncConfig.java create mode 100644 aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/ChangePasswordRequestDTO.java create mode 100644 aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/UserProfileUpdateRequestDTO.java create mode 100644 aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/resp/UserProfileRespDTO.java diff --git a/aioj-backend-gateway/src/main/java/cn/meowrain/aioj/backend/gateway/filter/AuthGlobalFilter.java b/aioj-backend-gateway/src/main/java/cn/meowrain/aioj/backend/gateway/filter/AuthGlobalFilter.java index c12689d..5cf1775 100644 --- a/aioj-backend-gateway/src/main/java/cn/meowrain/aioj/backend/gateway/filter/AuthGlobalFilter.java +++ b/aioj-backend-gateway/src/main/java/cn/meowrain/aioj/backend/gateway/filter/AuthGlobalFilter.java @@ -105,7 +105,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered { private Mono validateToken(String token) { return webClientBuilder.build() .post() - .uri("lb://auth-service/api/v1/auth/validate") + .uri("lb://aioj-auth-service/api/v1/auth/validate") .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) .contentType(MediaType.APPLICATION_JSON) .retrieve() diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/config/AsyncConfig.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/config/AsyncConfig.java new file mode 100644 index 0000000..d985b08 --- /dev/null +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/config/AsyncConfig.java @@ -0,0 +1,40 @@ +package cn.meowrain.aioj.backend.userservice.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 异步配置类 + * + * @author meowrain + * @since 2026-01-18 + */ +@Slf4j +@Configuration +@EnableAsync +public class AsyncConfig { + + @Bean("emailExecutor") + public Executor emailExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + // 核心线程数 + executor.setCorePoolSize(2); + // 最大线程数 + executor.setMaxPoolSize(5); + // 队列容量 + executor.setQueueCapacity(100); + // 线程名前缀 + executor.setThreadNamePrefix("email-async-"); + // 拒绝策略:由调用线程执行 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + log.info("邮件异步线程池初始化完成: coreSize=2, maxSize=5, queueCapacity=100"); + return executor; + } +} diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/controller/UserController.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/controller/UserController.java index 958f77b..7affa75 100644 --- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/controller/UserController.java +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/controller/UserController.java @@ -1,13 +1,10 @@ package cn.meowrain.aioj.backend.userservice.controller; -import cn.meowrain.aioj.backend.framework.core.utils.ContextHolderUtils; import cn.meowrain.aioj.backend.framework.core.web.Result; import cn.meowrain.aioj.backend.framework.core.web.Results; -import cn.meowrain.aioj.backend.userservice.dto.req.AvatarUpdateRequestDTO; -import cn.meowrain.aioj.backend.userservice.dto.req.BindEmailRequest; -import cn.meowrain.aioj.backend.userservice.dto.req.EmailSendCodeRequestDTO; -import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO; +import cn.meowrain.aioj.backend.userservice.dto.req.*; import cn.meowrain.aioj.backend.userservice.dto.resp.UserAuthRespDTO; +import cn.meowrain.aioj.backend.userservice.dto.resp.UserProfileRespDTO; import cn.meowrain.aioj.backend.userservice.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -15,7 +12,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; @RequiredArgsConstructor @RestController() @@ -60,7 +56,7 @@ public class UserController { @Operation(summary = "发送验证码", description = "根据用户注册的邮箱发送验证码") @GetMapping("/email/send-code") public Result getVerifyCode(@Parameter(description = "邮箱信息", required = true) - @Valid @RequestParam EmailSendCodeRequestDTO request) { + @Valid @ModelAttribute EmailSendCodeRequestDTO request) { userService.sendEmailCode(request.getEmail()); return Results.success(null); } @@ -73,8 +69,8 @@ public class UserController { */ @Operation(summary = "绑定邮箱", description = "根据用户注册的邮箱绑定邮箱") @PostMapping("/email/bind") - public Result bindEmail(@RequestBody BindEmailRequest request) { - userService.bindEmail(request.getEmail(), request.getCode()); + public Result bindEmail(@RequestBody @Valid BindEmailRequest request) { + userService.bindEmail(request.getEmail(), request.getVerifyCode()); return Results.success(null); } @@ -86,20 +82,22 @@ public class UserController { @Operation(summary = "解绑邮箱", description = "根据用户注册的邮箱解绑邮箱") @PostMapping("/email/unbind") public Result unbindEmail() { - userService.unbindEmail(ContextHolderUtils.getCurrentUserId()); + userService.unbindEmail(); return Results.success(null); } @Operation(summary = "个人资料管理", description = "获取完整个人资料") @GetMapping("/profile") - public Result getUserProfile() { - return Results.success(); + public Result getUserProfile() { + UserProfileRespDTO userProfileRespDTO = userService.getUserProfile(); + return Results.success(userProfileRespDTO); } @Operation(summary = "个人资料管理-更新个人资料", description = "更新个人资料") @PutMapping("/profile") - public Result updateUserProfile() { + public Result updateUserProfile(@RequestBody UserProfileUpdateRequestDTO dto) { + userService.updateUserProfile(dto); return Results.success(); } @@ -110,8 +108,10 @@ public class UserController { return Results.success(); } + @PutMapping("/password") @Operation(summary = "个人资料管理-修改密码",description = "修改密码") - public Result changePassword() { + public Result changePassword(@RequestBody ChangePasswordRequestDTO dto) { + userService.changePassword(dto); return Results.success(); } } diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/BindEmailRequest.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/BindEmailRequest.java index 9bd9684..44eb37f 100644 --- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/BindEmailRequest.java +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/BindEmailRequest.java @@ -12,5 +12,5 @@ public class BindEmailRequest { @Schema(description = "邮箱",example = "123@qq.com") private String email; @Schema(description = "验证码",example = "123456") - private String code; + private String verifyCode; } diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/ChangePasswordRequestDTO.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/ChangePasswordRequestDTO.java new file mode 100644 index 0000000..7fae58d --- /dev/null +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/ChangePasswordRequestDTO.java @@ -0,0 +1,13 @@ +package cn.meowrain.aioj.backend.userservice.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "修改密码请求参数") +public class ChangePasswordRequestDTO { + @Schema(description = "旧密码") + private String oldPassword; + @Schema(description = "新密码") + private String newPassword; +} diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/UserProfileUpdateRequestDTO.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/UserProfileUpdateRequestDTO.java new file mode 100644 index 0000000..c49fbdc --- /dev/null +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/req/UserProfileUpdateRequestDTO.java @@ -0,0 +1,13 @@ +package cn.meowrain.aioj.backend.userservice.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "用户个人资料更新请求DTO") +public class UserProfileUpdateRequestDTO { + @Schema(description = "用户昵称") + private String userName; + @Schema(description = "用户简介") + private String userProfile; +} diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/resp/UserProfileRespDTO.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/resp/UserProfileRespDTO.java new file mode 100644 index 0000000..a8f755c --- /dev/null +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/dto/resp/UserProfileRespDTO.java @@ -0,0 +1,10 @@ +package cn.meowrain.aioj.backend.userservice.dto.resp; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "用户个人资料响应DTO") +public class UserProfileRespDTO { + +} diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/EmailService.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/EmailService.java index f1e74c7..f19b589 100644 --- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/EmailService.java +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/EmailService.java @@ -10,4 +10,11 @@ public interface EmailService { * @param email 收件人邮箱 */ void sendVerifyCode(String email); + + /** + * 获取邮箱验证码 + * @param email 收件人邮箱 + * @return 验证码 + */ + String getVerifyCode(String email); } diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/UserService.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/UserService.java index 84ec10a..6fa0fee 100644 --- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/UserService.java +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/UserService.java @@ -2,8 +2,11 @@ package cn.meowrain.aioj.backend.userservice.service; import cn.meowrain.aioj.backend.userservice.dao.entity.User; +import cn.meowrain.aioj.backend.userservice.dto.req.ChangePasswordRequestDTO; +import cn.meowrain.aioj.backend.userservice.dto.req.UserProfileUpdateRequestDTO; import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO; import cn.meowrain.aioj.backend.userservice.dto.resp.UserAuthRespDTO; +import cn.meowrain.aioj.backend.userservice.dto.resp.UserProfileRespDTO; import com.baomidou.mybatisplus.extension.service.IService; public interface UserService extends IService { @@ -42,7 +45,7 @@ public interface UserService extends IService { /** * 解绑邮箱 */ - void unbindEmail(Long userId); + void unbindEmail(); /** * 设置用户头像 @@ -50,4 +53,19 @@ public interface UserService extends IService { * @return */ void setProfileAvatar(Long fileId); + + /** + * 修改密码 + */ + void changePassword(ChangePasswordRequestDTO dto); + + /** + * 更新用户个人资料 + */ + void updateUserProfile(UserProfileUpdateRequestDTO dto); + + /** + * 获取用户个人资料 + */ + UserProfileRespDTO getUserProfile(); } diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/EmailServiceImpl.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/EmailServiceImpl.java index f865215..e7101f9 100644 --- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/EmailServiceImpl.java +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/EmailServiceImpl.java @@ -1,5 +1,6 @@ package cn.meowrain.aioj.backend.userservice.service.impl; +import cn.meowrain.aioj.backend.framework.core.exception.ClientException; import cn.meowrain.aioj.backend.framework.core.exception.ServiceException; import cn.meowrain.aioj.backend.userservice.common.constants.RedisKeyConstants; import cn.meowrain.aioj.backend.userservice.service.EmailService; @@ -11,6 +12,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.io.UnsupportedEncodingException; @@ -95,6 +97,7 @@ public class EmailServiceImpl implements EmailService { } + @Async("emailExecutor") @Override public void sendVerifyCode(String email) { // 生成验证码 @@ -124,4 +127,22 @@ public class EmailServiceImpl implements EmailService { } } + + /** + * 获取邮箱验证码 + * @param email 收件人邮箱 + * @return 验证码 + */ + @Override + public String getVerifyCode(String email) { + String redisKey = String.format(RedisKeyConstants.EMAIL_CODE_PREFIX,email); + // 从redis里面获取验证码,用Object接收,因为redis里面可能存储的是null 比如过期这种情况 + Object verifyCodeInSystem = redisTemplate.opsForValue().get(redisKey); + if(verifyCodeInSystem == null) { + throw new ClientException("验证码不存在或已过期"); + } + // 转换为字符串 + return verifyCodeInSystem.toString(); + } + } diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/UserServiceImpl.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/UserServiceImpl.java index 4d963c2..d88afac 100644 --- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/UserServiceImpl.java +++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/UserServiceImpl.java @@ -10,8 +10,11 @@ import cn.meowrain.aioj.backend.userservice.dao.entity.User; import cn.meowrain.aioj.backend.userservice.dao.mapper.UserMapper; import cn.meowrain.aioj.backend.userservice.dto.chains.context.UserRegisterRequestParamVerifyContext; +import cn.meowrain.aioj.backend.userservice.dto.req.ChangePasswordRequestDTO; +import cn.meowrain.aioj.backend.userservice.dto.req.UserProfileUpdateRequestDTO; import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO; import cn.meowrain.aioj.backend.userservice.dto.resp.UserAuthRespDTO; +import cn.meowrain.aioj.backend.userservice.dto.resp.UserProfileRespDTO; import cn.meowrain.aioj.backend.userservice.service.EmailService; import cn.meowrain.aioj.backend.userservice.service.UserService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -29,90 +32,187 @@ import java.util.Date; @Slf4j public class UserServiceImpl extends ServiceImpl implements UserService { - private final UserRegisterRequestParamVerifyContext userRegisterRequestParamVerifyContext; + private final UserRegisterRequestParamVerifyContext userRegisterRequestParamVerifyContext; - private final EmailService emailService; + private final EmailService emailService; - @Override - public Long userRegister(UserRegisterRequestDTO request) { - UserAuthRespDTO authInfoByUserAccount = findAuthInfoByUserAccount(request.getUserAccount()); - if (authInfoByUserAccount != null) { - throw new ClientException("重复创建用户"); - } + @Override + public Long userRegister(UserRegisterRequestDTO request) { + UserAuthRespDTO authInfoByUserAccount = findAuthInfoByUserAccount(request.getUserAccount()); + if (authInfoByUserAccount != null) { + throw new ClientException("重复创建用户"); + } - log.info("进行用户注册"); - userRegisterRequestParamVerifyContext.handler(ChainMarkEnums.USER_REGISTER_REQ_PARAM_VERIFY.getMarkName(), - request); - // 使用 BCrypt 加密密码 - Date now = new Date(); - String salt = BCrypt.gensalt(); - String encryptPassword = BCrypt.hashpw(request.getUserPassword(), salt); - User user = new User().setUserAccount(request.getUserAccount()) - .setUserPassword(encryptPassword) - .setUserRole("user") - .setCreateTime(now) - .setUpdateTime(now); - try { - // 需要修改表,使得用户名是唯一的 - this.save(user); - } - catch (DuplicateKeyException e) { - log.error("重复创建用户"); - throw new ServiceException("用户名已存在", ErrorCode.SYSTEM_ERROR); - } + log.info("进行用户注册"); + userRegisterRequestParamVerifyContext.handler(ChainMarkEnums.USER_REGISTER_REQ_PARAM_VERIFY.getMarkName(), + request); + // 使用 BCrypt 加密密码 + Date now = new Date(); + String salt = BCrypt.gensalt(); + String encryptPassword = BCrypt.hashpw(request.getUserPassword(), salt); + User user = new User().setUserAccount(request.getUserAccount()) + .setUserPassword(encryptPassword) + .setUserRole("user") + .setCreateTime(now) + .setUpdateTime(now); + try { + // 需要修改表,使得用户名是唯一的 + this.save(user); + } catch (DuplicateKeyException e) { + log.error("重复创建用户"); + throw new ServiceException("用户名已存在", ErrorCode.SYSTEM_ERROR); + } - return user.getId(); - } + return user.getId(); + } - @Override - public UserAuthRespDTO findAuthInfoByUserAccount(String userAccount) { - User one = this.lambdaQuery().eq(User::getUserAccount, userAccount).one(); - UserAuthRespDTO userAuthDTO = new UserAuthRespDTO(); - if (one != null) { - BeanUtils.copyProperties(one, userAuthDTO); - return userAuthDTO; - } - return null; - } + @Override + public UserAuthRespDTO findAuthInfoByUserAccount(String userAccount) { + User one = this.lambdaQuery().eq(User::getUserAccount, userAccount).one(); + UserAuthRespDTO userAuthDTO = new UserAuthRespDTO(); + if (one != null) { + BeanUtils.copyProperties(one, userAuthDTO); + return userAuthDTO; + } + return null; + } - @Override - public UserAuthRespDTO findAuthInfoByUserId(Long userId) { - User one = this.lambdaQuery().eq(User::getId, userId).one(); - UserAuthRespDTO userAuthDTO = new UserAuthRespDTO(); - if (one != null) { - BeanUtils.copyProperties(one, userAuthDTO); - return userAuthDTO; - } - return null; + @Override + public UserAuthRespDTO findAuthInfoByUserId(Long userId) { + User one = this.lambdaQuery().eq(User::getId, userId).one(); + UserAuthRespDTO userAuthDTO = new UserAuthRespDTO(); + if (one != null) { + BeanUtils.copyProperties(one, userAuthDTO); + return userAuthDTO; + } + return null; - } + } - @Override - public void sendEmailCode(String email) { - emailService.sendVerifyCode(email); - } + @Override + public void sendEmailCode(String email) { + emailService.sendVerifyCode(email); + } - @Override - public void bindEmail(String email, String code) { - Long currentUserId = ContextHolderUtils.getCurrentUserId(); + @Override + public void bindEmail(String email, String code) { + if (email == null || code == null) { + throw new ClientException("邮箱或验证码不能为空"); + } + Long currentUserId = ContextHolderUtils.getCurrentUserId(); + // 检查用户是否存在 + User user = this.lambdaQuery().eq(User::getId, currentUserId).one(); + if (user == null) { + throw new ClientException("用户不存在"); + } - } + // 验证邮箱验证码 + // 从redis里面获取验证码 + String verifyCodeInSystem = emailService.getVerifyCode(email); + // 验证验证码是否匹配 + if (!verifyCodeInSystem.equals(code)) { + throw new ClientException("验证码错误,请重新输入"); + } - @Override - public void unbindEmail(Long userId) { - User one = this.lambdaQuery().eq(User::getId, userId).one(); + // 绑定邮箱 + user.setUserEmail(email); + user.setUpdateTime(new Date()); + this.updateById(user); + } - } + @Override + public void unbindEmail() { + Long currentUserId = ContextHolderUtils.getCurrentUserId(); + User user = this.lambdaQuery().eq(User::getId, currentUserId).one(); + if (user == null) { + throw new ClientException("用户不存在"); + } - @Transactional(rollbackFor = Exception.class) - @Override - public void setProfileAvatar(Long fileId) { - Long currentUserId = ContextHolderUtils.getCurrentUserId(); - User user = this.lambdaQuery().eq(User::getId, currentUserId).one(); - user.setUserAvatar(fileId); - user.setUpdateTime(new Date()); - this.updateById(user); - } + if (user.getUserEmail() == null) { + throw new ClientException("邮箱未绑定"); + } + // 这种方法避免了查询整个对象,并且能精确控制 NULL 值的更新。 + boolean success = this.lambdaUpdate() + // 设置 userEmail 为 NULL + .set(User::getUserEmail, null) + // 设置 updateTime 为当前时间 + .set(User::getUpdateTime, new Date()) + // 筛选条件:用户ID + .eq(User::getId, currentUserId) + // 执行更新 + .update(); + + if (!success) { + throw new ClientException("解绑失败,请重试"); + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void setProfileAvatar(Long fileId) { + Long currentUserId = ContextHolderUtils.getCurrentUserId(); + User user = this.lambdaQuery().eq(User::getId, currentUserId).one(); + user.setUserAvatar(fileId); + user.setUpdateTime(new Date()); + this.updateById(user); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void changePassword(ChangePasswordRequestDTO dto) { + Long currentUserId = ContextHolderUtils.getCurrentUserId(); + User user = this.lambdaQuery().eq(User::getId, currentUserId).one(); + + // 检查用户是否存在 + if (user == null) { + throw new ClientException("用户不存在"); + } + + // 检查旧密码是否正确 + String oldPassword = user.getUserPassword(); + if (!BCrypt.checkpw(dto.getOldPassword(), oldPassword)) { + throw new ClientException("旧密码错误"); + } + + // 检查新密码是否与旧密码相同 + if (BCrypt.checkpw(dto.getNewPassword(), oldPassword)) { + throw new ClientException("新密码不能与旧密码相同"); + } + + + // 加密新密码 + Date now = new Date(); + String salt = BCrypt.gensalt(); + String encryptPassword = BCrypt.hashpw(dto.getNewPassword(), salt); + // 更新用户密码 + user.setUserPassword(encryptPassword); + user.setUpdateTime(now); + this.updateById(user); + } + + @Override + public void updateUserProfile(UserProfileUpdateRequestDTO dto) { + Long currentUserId = ContextHolderUtils.getCurrentUserId(); + User user = this.lambdaQuery().eq(User::getId, currentUserId).one(); + if (user == null) { + throw new ClientException("用户不存在"); + } + // 更新用户个人资料 + user.setUserName(dto.getUserName()); + user.setUserProfile(dto.getUserProfile()); + user.setUpdateTime(new Date()); + this.updateById(user); + } + + /** + * 获取用户个人资料 + * @return 用户个人资料 + */ + @Override + public UserProfileRespDTO getUserProfile() { + // TODO: 待实现 从数据库查询用户个人资料 + return null; + } }