【springcloud】一些项目结构模式

springboot的一些项目结构模式,代码写法梳理

1 auth 登录有关服务

该示例演示了对于登录功能的处理。
目录结构:

  • controller
    • LoginController
  • domain
    • LoginRequest
  • service
    • impl
      • DefaultLoginService 登录方法
    • LoginService
    • PasswordService 密码校验
    • TokenService 身份验证

各类主要代码如下:

1.1 LoginController

@Slf4j
@RestController
@ResponseAdvice
@RequestMapping("/login")
public class LoginController {

    @Autowired
    private LoginService loginService;

    @PostMapping("/")
    public String login(@RequestBody LoginRequest request) {
        return loginService.login(request);
    }
}

1.2 LoginRequest

LoginRequest的实体类,表示登录请求的数据。实现了Serializable接口,意味着它可以被序列化。类中有三个私有字段:username表示用户名,password表示密码,vcode表示验证码。

@Data
public class LoginRequest implements Serializable {

    private String username;

    private String password;

    private String vcode;
}

使用@Data注解,Lombok会在编译时为该类的所有非静态字段生成以下方法:

getter方法(如public String getUsername())
setter方法(如public void setUsername(String username))
toString() 方法 equals() 和 hashCode() 方法
默认构造函数(如果没有其他构造函数)

1.3 LoginService

接口,声明一个login方法处理请求

public interface LoginService {
    String login(LoginRequest request);
}

1.4 DefaultLoginService 登录校验

LoginService接口的实现,注入1.7 UserServiceClient用于获取用户信息,1.5 PasswordService用于校验密码,1.6 TokenService用于生成和校验token

@Slf4j
@Service("loginService")
public class DefaultLoginService implements LoginService {

    @Resource
    private UserServiceClient userServiceClient; // 用户服务客户端

    @Resource
    private PasswordService passwordService; // 密码服务

    @Resource
    private TokenService tokenService; // Token服务

    /**
     * 处理用户登录请求。
     *
     * @param request 包含登录所需信息的请求对象,如用户名和密码。
     * @return 经过验证的用户token。
     */
    public String login(LoginRequest request) {
        // 通过用户名获取用户信息
        ResponseWrapper<SysUser> userWrapper = userServiceClient.getUser(request.getUsername());
        SysUser user = userWrapper.getData();
        // 断言判断用户存在且未被禁用或删除,如果false会抛出异常消息
        Assert.nonNull(user, USER_NOT_EXIST);
        Assert.isFalse(user.getBlocked(), USER_BLOCKED);
        Assert.isFalse(user.getDeleted(), USER_DELETED);
        // 验证密码
        passwordService.validate(user, request.getPassword());
        // 生成并返回token
        return tokenService.validate(user);
    }

}


1.5 PasswordService 密码验证&用户锁定

@Service //该类为服务组件
public class PasswordService {

    @Autowired //注入Redis服务
    private RedisService redisService;

    /**
     * 验证用户密码是否正确,并管理密码验证失败的重试次数,以防止暴力破解。
     * 
     * @param user 表示需要验证的用户对象。
     * @param password 用户输入的密码。
     * @throws ApiException 如果用户被锁定或者密码不正确时抛出。
     */
    public void validate(SysUser user, String password) {
        String username = user.getUsername();
        // 构造重试次数的Redis键名
        String retryKey = retryCountKeyPrefix + username;
        // 从Redis获取或默认设置重试次数
        Integer retryCount = redisService.getOrDefault(retryKey, 0, Integer.class);
        // 确保重试次数未超过最大值,否则抛出用户锁定异常
        Assert.isTrue(retryCount < maxRetryCount, USER_LOCKED);
        // 当重试次数达到最大值时,锁定用户
        if (retryCount >= maxRetryCount) {
            // 在Redis中设置用户锁定时间
            redisService.set(lockTimeKeyPrefix + username, maxLockTime);
            throw new ApiException(ResponseCode.USER_LOCKED); // 抛出用户锁定异常
        }
        if (!verify(password, user.getPassword())) { // 验证密码失败
            redisService.set(retryKey, retryCount + 1); // 更新重试次数
            throw new ApiException(ResponseCode.PASSWORD_INCORRECT); // 抛出密码不正确异常
        } else { // 密码验证成功
            redisService.delete(retryKey); // 清除重试次数
        }
    }


    /**
     * 验证输入的密码是否与存储的密码相等。
     * 
     * @param input 用户输入的密码。
     * @param saved 存储的密码。
     * @return 返回一个布尔值,表示密码是否匹配。
     */
    private boolean verify(String input, String saved) {
    // 使用Objects静态工具类的equals方法比较两个字符串是否相等
        return Objects.equals(input, saved); 
    }
}

1.6 TokenService 身份验证&token管理

@Service
public class TokenService {

    @Resource
    private RedisService redisService; // 注入Redis服务,用于token的存储和查询

    /**
     * 验证用户登录状态,如果不存在有效token,则创建新的token并返回。
     * 
     * @param user 用户信息
     * @return 返回有效的token字符串
     */
    public String validate(SysUser user) {
        String key = loginKeyPrefix + user.getId(); // 生成用户登录key
        // 查询缓存中是否存在有效的token
        String token = redisService.get(key);
        // 如果token不存在或已失效,则重新生成并保存token
        if (Objects.isNull(token) || !JwtTokenUtils.isValid(token)) {
            redisService.delete(key); // 删除失效的token
            token = JwtTokenUtils.generateToken(user.getUsername(), user); // 生成新的token
            redisService.set(key, token, expiration); // 新token保存至缓存
            return token;
        }
        // 存在有效token时,检查是否需要刷新
        refresh(key);
        return token;
    }

    /**
     * 刷新token,当token剩余有效期超过设定时间的1/5时,更新token有效期。
     * 
     * @param key 用户的token存储key
     */
    private void refresh(String key) {
        // 获取当前token的剩余有效期
        long toExpired = redisService.getTime(key);
        // 判断是否需要刷新token的有效期
        if ((expiration * ratio) > toExpired) {
            redisService.expire(key, expiration); // 更新token有效期
        }
    }

}

1.7 UserServiceClient 远程调用

@FeignClient(name = "system")
//@FeignClient(name = "system", url = "http://localhost:11001")
// 用户服务客户端接口。用于通过Feign进行远程调用用户服务。
public interface UserServiceClient {
    /**根据用户名获取用户信息。
     * 
     * @param username 用户名,用于查询特定用户的信息。
     * @return 返回用户信息的响应包装器。响应包装器中包含具体的用户信息对象SysUser。
     */
    @GetMapping("/user/{username}")
    ResponseWrapper<SysUser> getUser(@PathVariable("username") String username);
}

2

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Cloud提供了自动扫描的功能,可以方便地将服务注册到服务注册中心。下面是一些关于Spring Cloud自动扫描的常见问题和解决方法: 1. 问题:服务无法注册到服务注册中心。 解决方法:确保你在服务的启动类上添加了`@EnableDiscoveryClient`或`@EnableEurekaClient`注解,这样Spring Cloud会自动将该服务注册到注册中心。 2. 问题:服务注册到了注册中心,但无法被其他服务发现。 解决方法:确保你在需要发现其他服务的地方使用了`@Autowired`注解将`DiscoveryClient`或`EurekaClient`注入到你的类中,这样你就可以使用它们来发现其他服务。 3. 问题:服务无法正确地绑定到注册中心。 解决方法:检查你的配置文件,确保你正确地配置了注册中心的地址和端口。对于Eureka注册中心,可以使用`eureka.client.service-url.defaultZone`属性来配置。 4. 问题:服务在启动时报错,提示找不到相关的依赖。 解决方法:确保你在服务的pom.xml文件中添加了正确的Spring Cloud依赖。可以参考Spring Cloud官方文档或示例项目来获取正确的依赖信息。 5. 问题:服务在启动时报错,提示找不到自动扫描注解。 解决方法:检查你的服务的包结构和注解的使用方式。确保你的服务包含在自动扫描的范围内,并且使用了正确的注解(如`@RestController`、`@Service`等)标识组件。 如果以上方法都无法解决问题,可以尝试在启动应用程序时打开调试模式,查看详细的错误信息,以便更好地定位问题。同时,也可以参考Spring Cloud官方文档和社区论坛来获取更多的帮助和支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值