SpringMVC简单仿写

news2024/11/29 0:34:47

之前我分享过SpringMVC的基本原理与配置(原文链接:https://blog.csdn.net/L170311/article/details/129339120),为了更深层次的学习,精益求精,手动仿写了一个MVC原理实现demo,一起学习一下吧


结构目录:

 两个自定义注解,两个Controller,核心ImitateSpringMVC,以及测试Main

 @Controller和@RequestMapping

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Controller {


}



@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface RequestMapping {

    String value() default "";
}


@Documented     

        该注解的作用就是在生产文档的时候,保留自定义注解的存在,例如:

         -d doc Test.java ; 如果Test.java中有自定义的注解,然后该注解上面有@Documented,那么生成的文档中就会包含自定义注解部分,反之就没有。

@Retention(RetentionPolicy.RUNTIME)

    
@Target(ElementType.TYPE)

 

        target英文有目标、目的的意思。 @Target在java中是注释类。@Target作用于修饰的注释可以修饰的类型范围

        @Target包含一个ElementType[]元素类型的数组。ElementType[]数组值value,表明Target修饰的注释可以修饰的类型范围。ElementType枚举值包含方法、属性、类等等。

        ANNOTATION_TYPE: 注解只能修饰注解,不能修饰其他的东西

        CONSTRUCTOR: 注解只能修饰构造方法

        FIELD: 注解只能修饰属性(成员变量) 字段加解密注解标记拦截

        LOCAL_VARIABLE: 注解只能修饰局部变量

        METHOD: 注解只能修饰方法 对应的方法进行拦截

        PACKAGE: 注解只能修饰包

        PARAMETER: 注解只能修饰方法的参数

        TYPE: 注解只能修饰类、接口、枚举

 TestController

@Controller
@RequestMapping("test")
public class TestController {
    @RequestMapping
    public  String index(){
        System.out.println("test->index");
        return "";
    }
    @RequestMapping("index1")
    public  String index1(){
        System.out.println("test->index1");
        return "";
    }
}

核心:ImitateSpringMVC

public class ImitateSpringMVC {
    private static HashMap<String, Map<String, Method>> map=new HashMap<>();
    private static HashMap<String, Object> objMap=new HashMap<>();
    public static void exec(String classPath,String methodPath){
        if(objMap.get(classPath)==null){
            System.out.println("没有这个类 404");
        }else {
            if(map.get(classPath).get(methodPath)==null){
                System.out.println("没有这个方法 404");
            }else {
                try {
                    map.get(classPath).get(methodPath).invoke(objMap.get(classPath));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    public static void scanner(String path,String packageName){
        //遍历当前路径下的所有文件
        List<String> paths = traverseFolder2(path);
        for (String p : paths) {
            p=p.substring(path.length()-1);
            try {
                String className=packageName+"."+p.replaceAll( Matcher.quoteReplacement(File.separator),".");
                String replace = className.replace(".class", "");

                //通过类加载器加载类信息
                Class<?> cl = ClassLoader.getSystemClassLoader().loadClass(replace);
                if(isController(cl)){
                    if(isRequestMapping(cl)){

                        //获得我们设置在@RequestMapping里的值
                        RequestMapping requestMapping = getRequestMapping(cl);

                        //如果注解值重复,抛异常
                        if(map.containsKey(requestMapping.value())){
                            throw  new RuntimeException("类多注解值:"+requestMapping.value());
                        }else {
                            map.put(requestMapping.value(),new HashMap<>());
                            objMap.put(requestMapping.value(),cl.newInstance());
                        }

                        //获得当前类对象声明的所有方法
                        Method[] declaredMethods = cl.getDeclaredMethods();
                        for (Method declaredMethod : declaredMethods) {

                            //遍历,判定方法是否带有@RequestMapping注解
                            if(isRequestMapping(declaredMethod)){
                                RequestMapping mapping = getRequestMapping(declaredMethod);

                                //判定方法的注解值是否重复
                                if(map.get(requestMapping.value()).containsKey(mapping.value())){
                                    throw  new RuntimeException("方法多注解值:"+requestMapping.value());
                                }else {
                                    map.get(requestMapping.value()).put(mapping.value(),declaredMethod);
                                    //现在的map<K,V>中k是我们获取到类对象的@RequestMapping的值,V是类对象方法的@RequestMapping的值,组成的一个集合
                                }
                            }
                        }
                    }else {
                        throw  new RuntimeException("类无requestMapping");
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }


    }

    //判定类文件是否带有@Controller注解
    private static boolean isController(Class cl){
        Annotation annotation = cl.getAnnotation(Controller.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    //判定类文件是否带有@RequestMapping注解
    private static boolean isRequestMapping(Class cl){
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    private  static boolean isRequestMapping(Method method){
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    private static RequestMapping getRequestMapping(Class cl){
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }
    private static RequestMapping getRequestMapping(Method method){
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }
    private static List<String> traverseFolder2(String path) {
        File file = new File(path);
        List<String> classFiles=new ArrayList<>();
        //如果文件存在,开始遍历
        if (file.exists()) {
            LinkedList<File> list = new LinkedList<File>();
            File[] files = file.listFiles();
            for (File file2 : files) {
                //如果文件是文件夹的形式,放入list
                if (file2.isDirectory()) {
                    list.add(file2);
                } else {
                    classFiles.add(file2.getAbsolutePath());
                }
            }
            File temp_file;
            while (!list.isEmpty()) {
                temp_file = list.removeFirst();
                files = temp_file.listFiles();
                for (File file2 : files) {
                    if (file2.isDirectory()) {
                        list.add(file2);
                    } else {
                        classFiles.add(file2.getAbsolutePath());
                    }
                }
            }
        } else {

        }

        return classFiles;
    }
}

 

IndexController

@Controller
@RequestMapping
public class IndexController {
    @RequestMapping
    public  void index(){
        System.out.println("index -> index");
    }

}

 Main

public class Main {
    static {
        //获得当前类的路径
        String path = Main.class.getResource("").getPath();
        //获得当前类的包名
        String packageName = Main.class.getPackage().getName();
        //传入到MVC的方法中
        ImitateSpringMVC.scanner(path,packageName);
    }

    public static void main(String[] args) {
        ImitateSpringMVC.exec("","");
        ImitateSpringMVC.exec("test","index1");
        ImitateSpringMVC.exec("test","");
        System.out.println("SpringMVC!");
    }


}

demo已上传gitee平台:https://gitee.com/dont-live-in-the-past/spring-mvc-simple-imitation

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402092.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用预训练模型自动续写文本的四种方法

作者&#xff1a;皮皮雷 来源&#xff1a;投稿 编辑&#xff1a;学姐 这篇文章以中文通用领域文本生成为例&#xff0c;介绍四种常用的模型调用方法。在中文文本生成领域&#xff0c;huggingface上主要有以下比较热门的pytorch-based预训练模型&#xff1a; 本文用到了其中的ue…

RFID在技术在工业产线上的应用

RFID在技术在工业产线上的应用一工业产线需求制造业生产线几乎每月都要损耗大量物料&#xff0c;并且生产结果与预期因为有误差而影响交货的情况时有发生&#xff0c;生产线也往往因人为原因造成种种误差。将RFID标签贴在生产物料或产品上&#xff0c;可自动记录产品的数量、规…

学完Java只能在互联网公司任职吗?

当然不是只有互联网公司需要软件&#xff0c;需要开发技术人员&#xff0c;传统行业、新经济领域都有软件项目需求&#xff1b;Java也不是只能做网站、企业应用&#xff0c;还可以用于嵌入式、游戏…… 互联网时代的手机、智能电视、家具、机械设备等各种有形产品都将会嵌入智…

二、Neo4j源码研究系列 - 单步调试

二、Neo4j源码研究系列 - 单步调试 一、背景介绍 上一篇我们已经把了neo4j的源码准备以及打包流程完成了&#xff0c;本篇将讲解如何对neo4j进行单步调试。对于不了解如何编译打包neo4j的读者&#xff0c;请阅读《一、Neo4j源码研究系列 - 源代码准备》。 大纲&#xff1a; …

【改机教程】iOS系统去除小黑条,改拍照声、拨号音、键盘音,不用越狱,支持所有机型

大家好&#xff0c;上次给大家分享了几个iOS系统免越狱改机教程 今天带来最新的教程&#xff0c;这次修改利用的是同一个漏洞&#xff0c;由外网大神 tamago 开发&#xff0c;国内大神冷风 进行汉化和优化 可以修改的地方包括 去除底部小黑条 dock栏透明 桌面文件夹透明 桌面…

golang 占位符还傻傻分不清?

xdm &#xff0c;写 C/C 语言的时候有格式控制符&#xff0c;例如 %s , %d , %c , %p 等等 在写 golang 的时候&#xff0c;也是有对应的格式控制符&#xff0c;也叫做占位符&#xff0c;写这个占位符&#xff0c;需要有对应的数据与之对应&#xff0c;不能瞎搞 基本常见常用…

Cobalt Strike---(2)

数据管理 Cobalt Strike 的团队服务器是行动期间Cobalt Strike 收集的所有信息的中间商。Cobalt Strike 解析来 自它的 Beacon payload 的输出&#xff0c;提取出目标、服务和凭据。 如果你想导出 Cobalt Strike 的数据&#xff0c;通过 Reporting → Export Data 。Cobalt Str…

CentOS7自签SSL证书并配置nginx

一、生成SSL证书 1、安装依赖包 yum install -y openssl openssl-devel 2、生成私钥&#xff0c;会让你输入一个 4~2048 位的密码&#xff0c;你需要暂时记住这个密码 openssl genrsa -des3 -out server.key 2048 输入两遍相同的密码 3、生成CSR(Certificate Signing Request …

Postgresql-12.5 visual studio-2022 windows 添加pg工程并调试

pg内核学习&#xff0c;记录一下 文章目录安装包编译安装VS添加Postgresql工程调试源码安装包 &#xff08;1&#xff09;perl下载 https://www.perl.org/get.html &#xff08;2&#xff09;diff下载 http://gnuwin32.sourceforge.net/packages/diffutils.htm &#xff08;…

23届非科班选手秋招转码指南

1.秋招情况介绍 1.1自我介绍 我是一名23届非科班转码选手&#xff0c;本硕均就读于某211院校机械专业&#xff0c;秋招共计拿下12份offer&#xff0c;包括大疆创新、海康威视、联发科技、理想汽车、中电28、阳光电源等各行业、各种性质企业的意向。主要的投递岗位为嵌入式软件…

若依微服务版在定时任务里面跨模块调用服务

第一步 在被调用的模块中添加代理 RemoteTaskFallbackFactory.java: package com.ruoyi.rpa.api.factory;import com.ruoyi.common.core.domain.R; import com.ruoyi.rpa.api.RemoteTaskService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springf…

【springmvc】执行流程

SpringMVC执行流程 原理图 1、SpringMVC常用组件 DispatcherServlet&#xff1a;前端控制器&#xff0c;不需要工程师开发&#xff0c;由框架提供 作用&#xff1a;统一处理请求和响应&#xff0c;整个流程控制的中心&#xff0c;由它调用其它组件处理用户的请求 HandlerMa…

Windows7,10使用:Vagrant+VirtualBox 安装 centos7

一、Vagrant&#xff0c;VirtualBox 是什么二、版本说明1、win7下建议安装版本2、win10下建议安装版本三、Windows7下安装1、安装Vagrant2、安装VirtualBox3、打开VirtualBox&#xff0c;配置虚拟机默认安装地址四、windows7下载.box文件&#xff0c;安装centos 71、下载一个.b…

拐点!新能源车交付均价首次「低于」燃油车,智能电动成新爆点

2023年开局&#xff0c;随着特斯拉打响新能源汽车市场的「价格战」首炮&#xff0c;除部分燃油车品牌&#xff08;仍依赖自身多年的用户和品牌积累的溢价能力&#xff09;没有跟进之外&#xff0c;几乎所有的新能源车型都在进行车型价格的下调。 而数据也在反映市场的拐点即将来…

深入理解Zookeeper的ZAB协议

ZAB是什么ZAB&#xff08;Zookeeper Atomic Broadcast&#xff09;&#xff1a;Zookeeper原子广播ZAB是为了保证Zookeeper数据一致性而产生的算法&#xff08;指的是Zookeeper集群模式&#xff09;。它不仅能解决正常情况下的数据一致性问题&#xff0c;还可以保证主节点发生宕…

最全的论文写作技巧(建议收藏)

近10年来&#xff0c;笔者有幸多次参与教学论文的评审工作&#xff0c;在此&#xff0c;特将教学论文写作的步骤及相关问题整理汇总如下&#xff1a; 一、选定论题 &#xff08;一&#xff09;论题在文中的地位与作用 严格地讲&#xff0c;论文写作是从选定论题开始的。选题…

Android源码分析 - Parcel 与 Parcelable

0. 相关分享 Android-全面理解Binder原理 Android特别的数据结构&#xff08;二&#xff09;ArrayMap源码解析 1. 序列化 - Parcelable和Serializable的关系 如果我们需要传递一个Java对象&#xff0c;通常需要对其进行序列化&#xff0c;通过内核进行数据转发&#xff0c;…

这几个群,程序员可千万不要进!

震惊&#xff01;某摸鱼网站惊现肾结石俱乐部&#xff01; &#xff08;图源V2EX&#xff09; 无关地域、无关性别&#xff0c;各位程序员们在肾结石这个病上面有着出奇一致的反应。诸如此类的各种职业病在我们的生活中更是十分常见。 也可能是到年纪了&#xff0c;在办公室…

ATTCK v12版本战术介绍——提权(一)

一、引言在前几期文章中我们介绍了ATT&CK中侦察、资源开发、初始访问、执行、持久化战术理论知识及实战研究&#xff0c;通过实战场景验证行之有效的检测规则、防御措施&#xff0c;本期我们为大家介绍ATT&CK 14项战术中提权战术&#xff08;一&#xff09;&#xff0c…

计算机图形学09:二维观察之点的裁剪

作者&#xff1a;非妃是公主 专栏&#xff1a;《计算机图形学》 博客地址&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录专栏推荐专栏系列文章序一、二维观察基本…