16 KiB
title, url, publishedTime
| title | url | publishedTime |
|---|---|---|
| 代码重构:密码更新接口 - 犬小哈专栏 | https://www.quanxiaoha.com/column/10317.html | null |
本小节中,我们继续来重构认证服务,将通过操作数据库来更新密码的部分,改写为通过 Feign 调用用户服务来实现。
接口定义
首先,需要为用户服务添加密码更新接口,以便认证服务调用。
接口地址
POST /user/password/update
入参
{
"encodePassword": "xxx", // 加密后的密码
}
出参
{
"success": true,
"message": null,
"errorCode": null,
"data": null
}
创建 DTO 实体类
编辑 xiaohashu-user-api 模块,在 /dto/req 包下创建 UpdateUserPasswordReqDTO 入参实体类,代码如下:
package com.quanxiaoha.xiaohashu.user.dto.req;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author: 犬小哈
* @date: 2024/4/7 15:17
* @version: v1.0.0
* @description: 密码更新
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UpdateUserPasswordReqDTO {
@NotBlank(message = "密码不能为空")
private String encodePassword;
}
编辑 service 业务层
编辑 xiaohashu-user-biz 模块中的 UserService 接口,声明一个密码更新方法,代码如下:
package com.quanxiaoha.xiaohashu.user.biz.service;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.xiaohashu.user.biz.model.vo.UpdateUserInfoReqVO;
import com.quanxiaoha.xiaohashu.user.dto.req.FindUserByPhoneReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.RegisterUserReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.UpdateUserPasswordReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.resp.FindUserByPhoneRspDTO;
/**
* @author: 犬小哈
* @date: 2024/4/7 15:41
* @version: v1.0.0
* @description: 用户业务
**/
public interface UserService {
// 省略...
/**
* 更新密码
*
* @param updateUserPasswordReqDTO
* @return
*/
Response<?> updatePassword(UpdateUserPasswordReqDTO updateUserPasswordReqDTO);
}
接着,在其实现类中实现上述方法,代码如下:
package com.quanxiaoha.xiaohashu.user.biz.service.impl;
import com.google.common.base.Preconditions;
import com.quanxiaoha.framework.biz.context.holder.LoginUserContextHolder;
import com.quanxiaoha.framework.common.enums.DeletedEnum;
import com.quanxiaoha.framework.common.enums.StatusEnum;
import com.quanxiaoha.framework.common.exception.BizException;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.framework.common.util.JsonUtils;
import com.quanxiaoha.framework.common.util.ParamUtils;
import com.quanxiaoha.xiaohashu.oss.api.FileFeignApi;
import com.quanxiaoha.xiaohashu.user.biz.constant.RedisKeyConstants;
import com.quanxiaoha.xiaohashu.user.biz.constant.RoleConstants;
import com.quanxiaoha.xiaohashu.user.biz.domain.dataobject.RoleDO;
import com.quanxiaoha.xiaohashu.user.biz.domain.dataobject.UserDO;
import com.quanxiaoha.xiaohashu.user.biz.domain.dataobject.UserRoleDO;
import com.quanxiaoha.xiaohashu.user.biz.domain.mapper.RoleDOMapper;
import com.quanxiaoha.xiaohashu.user.biz.domain.mapper.UserDOMapper;
import com.quanxiaoha.xiaohashu.user.biz.domain.mapper.UserRoleDOMapper;
import com.quanxiaoha.xiaohashu.user.biz.enums.ResponseCodeEnum;
import com.quanxiaoha.xiaohashu.user.biz.enums.SexEnum;
import com.quanxiaoha.xiaohashu.user.biz.model.vo.UpdateUserInfoReqVO;
import com.quanxiaoha.xiaohashu.user.biz.rpc.OssRpcService;
import com.quanxiaoha.xiaohashu.user.biz.service.UserService;
import com.quanxiaoha.xiaohashu.user.dto.req.FindUserByPhoneReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.RegisterUserReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.UpdateUserPasswordReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.resp.FindUserByPhoneRspDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @author: 犬小哈
* @date: 2024/4/7 15:41
* @version: v1.0.0
* @description: 用户业务
**/
@Service
@Slf4j
public class UserServiceImpl implements UserService {
// 省略...
/**
* 更新密码
*
* @param updateUserPasswordReqDTO
* @return
*/
@Override
public Response<?> updatePassword(UpdateUserPasswordReqDTO updateUserPasswordReqDTO) {
// 获取当前请求对应的用户 ID
Long userId = LoginUserContextHolder.getUserId();
UserDO userDO = UserDO.builder()
.id(userId)
.password(updateUserPasswordReqDTO.getEncodePassword()) // 加密后的密码
.updateTime(LocalDateTime.now())
.build();
// 更新密码
userDOMapper.updateByPrimaryKeySelective(userDO);
return Response.success();
}
}
编辑 controller 层
业务层代码编写完毕后,在 UserController 控制器中添加 /user/password/update 密码更新接口,代码如下:
package com.quanxiaoha.xiaohashu.user.biz.controller;
import com.quanxiaoha.framework.biz.operationlog.aspect.ApiOperationLog;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.xiaohashu.user.biz.model.vo.UpdateUserInfoReqVO;
import com.quanxiaoha.xiaohashu.user.biz.service.UserService;
import com.quanxiaoha.xiaohashu.user.dto.req.FindUserByPhoneReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.RegisterUserReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.UpdateUserPasswordReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.resp.FindUserByPhoneRspDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: 犬小哈
* @date: 2024/4/4 13:22
* @version: v1.0.0
* @description: 用户
**/
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Resource
private UserService userService;
// 省略...
// ===================================== 对其他服务提供的接口 =====================================
// 省略...
@PostMapping("/password/update")
@ApiOperationLog(description = "密码更新")
public Response<?> updatePassword(@Validated @RequestBody UpdateUserPasswordReqDTO updateUserPasswordReqDTO) {
return userService.updatePassword(updateUserPasswordReqDTO);
}
}
封装 Feign 客户端接口
回到 xiaohashu-user-api 模块,将 Feign 客户端接口封装好,代码如下:
package com.quanxiaoha.xiaohashu.user.api;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.xiaohashu.user.constant.ApiConstants;
import com.quanxiaoha.xiaohashu.user.dto.req.FindUserByPhoneReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.RegisterUserReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.UpdateUserPasswordReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.resp.FindUserByPhoneRspDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
* @author: 犬小哈
* @date: 2024/4/13 22:56
* @version: v1.0.0
* @description: TODO
**/
@FeignClient(name = ApiConstants.SERVICE_NAME)
public interface UserFeignApi {
String PREFIX = "/user";
// 省略...
/**
* 更新密码
*
* @param updateUserPasswordReqDTO
* @return
*/
@PostMapping(value = PREFIX + "/password/update")
Response<?> updatePassword(@RequestBody UpdateUserPasswordReqDTO updateUserPasswordReqDTO);
}
封装 rpc 层
编辑 xiaohashu-auth 认证服务中的 UserRpcService , 将 Feign 调用用户服务的密码更新接口,封装成一个方法:
package com.quanxiaoha.xiaohashu.auth.rpc;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.xiaohashu.user.api.UserFeignApi;
import com.quanxiaoha.xiaohashu.user.dto.req.FindUserByPhoneReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.RegisterUserReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.req.UpdateUserPasswordReqDTO;
import com.quanxiaoha.xiaohashu.user.dto.resp.FindUserByPhoneRspDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
/**
* @author: 犬小哈
* @date: 2024/4/13 23:29
* @version: v1.0.0
* @description: 用户服务
**/
@Component
public class UserRpcService {
@Resource
private UserFeignApi userFeignApi;
// 省略...
/**
* 密码更新
*
* @param encodePassword
*/
public void updatePassword(String encodePassword) {
UpdateUserPasswordReqDTO updateUserPasswordReqDTO = new UpdateUserPasswordReqDTO();
updateUserPasswordReqDTO.setEncodePassword(encodePassword);
userFeignApi.updatePassword(updateUserPasswordReqDTO);
}
}
重构 service 层
编辑 xiaohashu-auth 认证服务中 UserServiceImpl 类的修改密码方法,如下图标注所示,重构成通过 RPC 调用用户服务,来更新用户密码,代码如下:
package com.quanxiaoha.xiaohashu.auth.service.impl;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.common.base.Preconditions;
import com.quanxiaoha.framework.biz.context.holder.LoginUserContextHolder;
import com.quanxiaoha.framework.common.exception.BizException;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.xiaohashu.auth.constant.RedisKeyConstants;
import com.quanxiaoha.xiaohashu.auth.domain.dataobject.UserDO;
import com.quanxiaoha.xiaohashu.auth.domain.mapper.RoleDOMapper;
import com.quanxiaoha.xiaohashu.auth.domain.mapper.UserDOMapper;
import com.quanxiaoha.xiaohashu.auth.domain.mapper.UserRoleDOMapper;
import com.quanxiaoha.xiaohashu.auth.enums.LoginTypeEnum;
import com.quanxiaoha.xiaohashu.auth.enums.ResponseCodeEnum;
import com.quanxiaoha.xiaohashu.auth.model.vo.user.UpdatePasswordReqVO;
import com.quanxiaoha.xiaohashu.auth.model.vo.user.UserLoginReqVO;
import com.quanxiaoha.xiaohashu.auth.rpc.UserRpcService;
import com.quanxiaoha.xiaohashu.auth.service.UserService;
import com.quanxiaoha.xiaohashu.user.dto.resp.FindUserByPhoneRspDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import java.time.LocalDateTime;
import java.util.*;
/**
* @author: 犬小哈
* @date: 2024/4/7 15:41
* @version: v1.0.0
* @description: TODO
**/
@Service
@Slf4j
public class UserServiceImpl implements UserService {
// 省略...
/**
* 修改密码
*
* @param updatePasswordReqVO
* @return
*/
@Override
public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
// 新密码
String newPassword = updatePasswordReqVO.getNewPassword();
// 密码加密
String encodePassword = passwordEncoder.encode(newPassword);
// RPC: 调用用户服务:更新密码
userRpcService.updatePassword(encodePassword);
return Response.success();
}
}
重命名与删除代码
目前,我们已经将本应属于用户服务的相关功能,都剥离到了用户服务中, 以接口的形式提供出来。但是,还有一些遗留工作需要处理一下,首先是认证服务中的相关类命名, 如下图标注所示,再叫 UserXXX 显得有些不太合适:
重命名一下,如下:
UserController -> AuthController
UserService -> AuthService
UserServiceImpl -> AuthServiceImpl
另外,将之前测试用的
TestController删除掉。
接着,编辑 application.yml 配置文件,将测试用的相关配置删除,如下图标注:
现在,认证服务已经不用操作数据库了,而是通过调用用户服务。所以,删除掉数据库相关的代码,如 /domain 包、/resources/mapper 映射文件、generatorConfig.xml 代码生成器配置:
同时,将 application.yml 配置文件中,mybatis 的配置项删除,如下贴出来的部分:
mybatis:
# MyBatis xml 配置文件路径
mapper-locations: classpath:/mapper/**/*.xml
编辑 application-dev.yml 配置文件,将数据源相关的配置删除,只保留下图部分:
将认证服务启动类头上的 @MapperScan("com.quanxiaoha.xiaohashu.auth.domain.mapper") 注解删除,只保留如下:
package com.quanxiaoha.xiaohashu.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients(basePackages = "com.quanxiaoha.xiaohashu")
public class XiaohashuAuthApplication {
public static void main(String[] args) {
SpringApplication.run(XiaohashuAuthApplication.class, args);
}
}
还需要将认证服务 pom.xml 中,如下依赖、插件都删除:
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
<build>
<plugins>
// 省略...
<!-- 代码生成器 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
最后,AuthServiceImpl 业务类中注入的相关 mapper 引用、以及编程式事务 transactionTemplate 注入,统统删除干净~
自测一波
清理完毕后,重启认证服务,保证没有任何问题。然后,再重启用户服务,通过 ApiPost 测试一波密码更新接口,确认接口功能也是正常的。
至此,整个重构工作就基本结束了。