2023-06-18  阅读(4)
原文作者:代码有毒 mrcode 原文地址:https://mrcode.blog.csdn.net/article/details/81942345

短信登录配置及重构

重构思路:

  1. 重构不是更改已有的功能

  2. 重构是不影响已有功能的情况下,对已有代码进行抽象封装

  3. 多处使用相同代码的地方,需要抽出来

  4. 比如上章节的很多代码,

    如:图形验证码过滤器和短信验证码过滤器重复代码太多
    服务接口的url地址和过滤器中的过滤器地址重复
    等..

系统配置相关的代码结构

core项目中的重构如下:

  • 密码登录的配置代码
  • 短信登录的配置代码
  • 验证码相关的配置代码

browser项目:

  • BrowserSecurityConfig

  • 只留下浏览器特有的配置代码

    • 如记住我的功能,只有浏览器特有这样的功能

app:

  • AppSecurityConfig
  • App特有的配置代码

通过配置apply功能进行配置的引用

202306181903044231.png

感受

花了6个小时看老师重构之后的代码,然后完成了自己跟练的项目代码;

太厉害!!这个重构技巧太牛逼了;

总之:当有两处重复代码的时候 就要抽取代码了。这个需要大量的经验才能不分类好,不至于越抽越乱

这里再啰嗦下:
关于用户名密码登录和短信登录表单提交的url地址,不需要真实存在,
因为这个是提供这两个特定过滤器框架特定的拦截点。只有提交到指定的拦截点,
才会进入认证功能服务

此次重构一些知识点

  • 善用 HttpSecurity.apply 应用分离之后的配置类
  • 程序中有手动写字符串2次的就抽成 SecurityConstants 常量接口类
  • 善用 Autowired注解提供的 依赖查找功能
  • 善用 类名统一起名
  • 善用枚举类 提供相应的支持

善用 HttpSecurity.apply 应用分离之后的配置类

     HttpSecurity.apply 方法跟踪进来是父类的;这里是一个泛型,所有需要看HttpSecurity对应传递的是什么类型
    public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
            extends AbstractSecurityBuilder<O> {
          public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
            throws Exception {
            configurer.addObjectPostProcessor(objectPostProcessor);
            configurer.setBuilder((B) this);
            add(configurer);
            return configurer;
          }
    
    --------- HttpSecurity 声明
    public final class HttpSecurity extends
            AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
            implements SecurityBuilder<DefaultSecurityFilterChain>,
            HttpSecurityBuilder<HttpSecurity> {
    
    ------------ 注意看对比
    public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer
    
    AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
    
    这里的c对应的泛型就是 <O, B> ,而O,B对应到HttpSecurity的声明就是<DefaultSecurityFilterChain, HttpSecurity>
    
    HttpSecurity.apply 返回一个SecurityConfigurerAdapter<O, B>,所以这里只要继承该类,就是apply需要的对象了
    
    ------------- 如下示例
    /**
     * 验证码配置
     * @author : zhuqiang
     * @version : V1.0
     * @date : 2018/8/5 20:05
     */
    @Component
    public class ValidateCodeSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
        /**
         * @see ValidateCodeFilter  目前融合了短信和图形验证码的验证功能
         */
        @Autowired
        private Filter validateCodeFilter;
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            // 由源码得知,在最前面的是UsernamePasswordAuthenticationFilter
            http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
        }
    }

SecurityConstants 常量接口类

在重构中就已经发现这样做的好处了。因为这个代码被分离写和配置的,老是忘记在哪些地方用过
在修改的时候经常忘记修改,或则找不到,所以需要抽成常量类

    public interface SecurityConstants {
    
        /**
         * 默认的处理验证码的url前缀
         */
        public static final String DEFAULT_VALIDATE_CODE_URL_PREFIX = "/code";

善用 Autowired注解提供的 依赖查找功能

把多个实现类统一管理,特别是使用模板方法抽取公用逻辑的时候,就拍上用处了
如下代码,还提供了按beanName查找指定的子类实现;
还提供了按自定义类型,下面会讲到善用命名会在某些地方起到奇效

    /**
     * 处理器持有者,用来管理所有验证码类型的处理器
     * @author : zhuqiang
     * @version : V1.0
     * @date : 2018/8/5 20:40
     */
    @Component
    public class ValidateCodeProcessorHolder {
        @Autowired
        private Map<String, ValidateCodeProcessor> validateCodeProcessors;
    
        public ValidateCodeProcessor findValidateCodeProcessor(ValidateCodeType type) {
            return findValidateCodeProcessor(type.toString().toLowerCase());
        }
    
        public ValidateCodeProcessor findValidateCodeProcessor(String type) {
            String beanName = type.toLowerCase() + ValidateCodeProcessor.class.getSimpleName();
            ValidateCodeProcessor processor = validateCodeProcessors.get(beanName);
            if (processor == null) {
                throw new ValidateCodeException("验证码处理器 " + beanName + " 不存在");
            }
            return processor;
        }
    }

善用 类名统一起名

如这里的几个类

  • ValidateCodeProcessor 验证码处理接口
  • ImageValidateCodeProcessor 图片验证码处理接口
  • SmsValidateCodeProcessor 短信验证码处理接口

这里的前缀,配合上面的技巧 善用 Autowired注解提供的 依赖查找功能,使用以下代码就能方便的获取到对应的处理器

    他们都一个共同的父类,有公用的步骤,变化的部分由子类实现;
    public abstract class AbstractValidateCodeProcessor<C extends ValidateCode> implements ValidateCodeProcessor {
      /**
       * 根据请求的url获取校验码的类型:
       * ValidateCodeProcessorHolder : 中持有所有本类的子类型,获取getClass能拿到具体的实例类名
       * @return
       * @see ValidateCodeProcessorHolder
       */
      private ValidateCodeType getValidateCodeType() {
          // 处理器 命名规则:ImageValidateCodeProcessor,拿到前缀即可
          // 返回 Image
          String type = StringUtils.substringBefore(getClass().getSimpleName(), ValidateCodeProcessor.class.getSimpleName());
          return ValidateCodeType.valueOf(type.toUpperCase());
      }
    }
    
    在外部使用 type + ValidateCodeProcessor.class.getSimpleName() 就能获取到完整的类名,
    也就能使用ValidateCodeProcessorHolder动态的获取处理器了

善用枚举类提供相应的支持

枚举类的名称是 短信和图片验证功能的前缀。配合上面的几条。
在使用模板方法模式抽取公用逻辑的时候,可以使用前缀获取不同功能支持的动态常量等类容
在外部要动态使用服务的时候,也能用前缀+具体的的父类命名获取到

    public enum ValidateCodeType {
        /**
         * 短信验证码
         */
        SMS {
            @Override
            public String getParamNameOnValidate() {
                return SecurityConstants.DEFAULT_PARAMETER_NAME_CODE_SMS;
            }
        },
        /**
         * 图片验证码
         */
        IMAGE {
            @Override
            public String getParamNameOnValidate() {
                return SecurityConstants.DEFAULT_PARAMETER_NAME_CODE_IMAGE;
            }
        };
    
        /**
         * 校验时从请求中获取的参数的名字
         * @return
         */
        public abstract String getParamNameOnValidate();
    }

Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文