• 【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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.2 LoginRequest

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

    @Data
    public class LoginRequest implements Serializable {
    
        private String username;
    
        private String password;
    
        private String vcode;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用@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
    • 2
    • 3

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2

  • 相关阅读:
    多测师肖sir_高级金牌讲师_python之作业006
    【数据分析】基于matlab GUI齿轮箱振动数据分析【含Matlab源码 2122期】
    记一次生产中使用CompletableFuture遇到的坑
    实时天气API
    30、Java高级特性——Java API、枚举、包装类、装箱和拆箱
    PFA晶圆夹在半导体芯片制造中的应用
    Ubuntu 20.04编译Chrome浏览器
    python项目之酒店客房入侵检测系统的设计与实现
    最大人工岛[如何让一个连通分量的所有节点都记录总节点数?+给连通分量编号]
    .NET程序配置文件
  • 原文地址:https://blog.csdn.net/weixin_55751186/article/details/136496376