手写简单模拟mvc

news2024/9/21 18:49:16

目录结构:

 两个注解类:

@Controller:

package com.heaboy.annotation;

import java.lang.annotation.*;

/**
 * 注解没有功能只是简单标记
 *  .RUNTIME    运行时还能看到
 *  .CLASS  类里面还有,构建对象久没来了,这个说明是给类加载器的
 *  .SOURCE  表示这个注解能存活到哪一阶段(源码阶段)仅在   .java阶段有用 也就是仅在编译阶段有 
 *   用 
 *   是让编译器去看的
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Controller {
}

@RequestMapping:

package com.heaboy.annotation;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})//既在类上有用 在方法上也能用
public @interface RequestMapping {
    /**
     * 表明使用这个注解需要传入一个值,可以通过value()的形式传入, dafault是设置默认值 表明既可以传值
     * 也可以不传,使用设置的默认值null
     * @return
     */
    String value() default "";

}

两个Controller类:

TestController:

package com.heaboy.Controller;

import com.heaboy.annotation.Controller;
import com.heaboy.annotation.RequestMapping;

@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 "";
    }
    @RequestMapping("index2")
    public String index2(){
        System.out.println("test->index2");
        return "";
    }
//    @RequestMapping("index1")
//    public String index3(){
//        System.out.println("test->index3");
//        return "";
//    }

}

IndexController类:

package com.heaboy;

import com.heaboy.annotation.Controller;
import com.heaboy.annotation.RequestMapping;

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

最重要的模拟mvc功能类:HeaboyMvc

package com.heaboy.mvc;

import com.heaboy.annotation.Controller;
import com.heaboy.annotation.RequestMapping;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;

/**
 * @author heaboy
 * mvc类
 */
public class HeaboyMvc {
    private static HashMap<String, Map<String, Method>> map = new HashMap<>();
    // 创建一个静态的哈希映射,用于存储类路径和方法路径对应的Method对象
    private static HashMap<String, Object> objMap = new HashMap<>();
    // 创建一个静态的哈希映射,用于存储类路径和对应的实例对象

    public static void exec(String classPath, String methodPath) {
        // 定义一个公开的静态方法,用于执行指定类路径和方法路径的方法
        if (objMap.get(classPath) == null) {
            // 如果objMap中没有对应的类实例,则输出错误信息
            System.out.println("没有这个类 404");
        } else {
            // 如果有对应的类实例
            if (map.get(classPath).get(methodPath) == null) {
                // 如果map中没有对应的方法,则输出错误信息
                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”后缀
                Class<?> cl = ClassLoader.getSystemClassLoader().loadClass(replace);
                // 加载类文件到内存
                if (isController(cl)) {
                    // 检查当前类是否为控制器
                    if (isRequestMapping(cl)) {
                        // 检查当前类是否包含RequestMapping注解
                        RequestMapping requestMapping = getRequestMapping(cl);
                        // 获取类的RequestMapping注解对象
                        if (map.containsKey(requestMapping.value())) {
                            // 如果map中已经包含了该注解值
                            throw new RuntimeException("类多注解值:" + requestMapping.value());
                            // 抛出运行时异常,表示类有多个注解值
                        } else {
                            // 如果没有包含该注解值
                            map.put(requestMapping.value(), new HashMap<>());
                            // 在map中添加一个新的映射项,key为注解值,value为一个新的HashMap
                            objMap.put(requestMapping.value(), cl.newInstance());
                            // 创建该类的实例,并存储在objMap中
                        }
                        Method[] declaredMethods = cl.getDeclaredMethods();
                        // 获取类中声明的所有方法
                        for (Method declaredMethod : declaredMethods) {
                            // 遍历每个方法
                            if (isRequestMapping(declaredMethod)) {
                                // 如果方法包含RequestMapping注解
                                RequestMapping mapping = getRequestMapping(declaredMethod);
                                // 获取方法的RequestMapping注解对象
                                if (map.get(requestMapping.value()).containsKey(mapping.value())) {
                                    // 如果map中已经包含了该方法注解值
                                    throw new RuntimeException("方法多注解值:" + requestMapping.value());
                                    // 抛出运行时异常,表示方法有多个注解值
                                } else {
                                    // 如果没有包含该方法注解值
                                    map.get(requestMapping.value()).put(mapping.value(), declaredMethod);
                                    // 将方法存储在map中
                                }
                            }
                        }
                    } else {
                        // 如果类不包含RequestMapping注解
                        throw new RuntimeException("类无requestMapping");
                        // 抛出运行时异常,表示类无RequestMapping注解
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                // 捕获类未找到异常,并打印堆栈跟踪信息
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                // 捕获非法访问异常,并打印堆栈跟踪信息
            } catch (InstantiationException e) {
                e.printStackTrace();
                // 捕获实例化异常,并打印堆栈跟踪信息
            }
        }
    }

    private static boolean isController(Class cl) {
        // 定义一个私有的静态方法,用于检查类是否为控制器
        Annotation annotation = cl.getAnnotation(Controller.class);
        // 获取类的Controller注解对象
        if (annotation != null) {
            // 如果注解对象不为null
            return true;
            // 返回true,表示类为控制器
        }
        return false;
        // 返回false,表示类不是控制器
    }

    private static boolean isRequestMapping(Class cl) {
        // 定义一个私有的静态方法,用于检查类是否包含RequestMapping注解
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        // 获取类的RequestMapping注解对象
        if (annotation != null) {
            // 如果注解对象不为null
            return true;
            // 返回true,表示类包含RequestMapping注解
        }
        return false;
        // 返回false,表示类不包含RequestMapping注解
    }

    private static boolean isRequestMapping(Method method) {
        // 定义一个私有的静态方法,用于检查方法是否包含RequestMapping注解
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        // 获取方法的RequestMapping注解对象
        if (annotation != null) {
            // 如果注解对象不为null
            return true;
            // 返回true,表示方法包含RequestMapping注解
        }
        return false;
        // 返回false,表示方法不包含RequestMapping注解
    }

    private static RequestMapping getRequestMapping(Class cl) {
        // 定义一个私有的静态方法,用于获取类的RequestMapping注解对象
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        // 获取类的RequestMapping注解对象
        if (annotation instanceof RequestMapping) {
            // 如果注解对象是RequestMapping类型
            return (RequestMapping) annotation;
            // 将注解对象强制转换为RequestMapping类型并返回
        }
        return null;
        // 返回null,表示类不包含RequestMapping注解
    }

    private static RequestMapping getRequestMapping(Method method) {
        // 定义一个私有的静态方法,用于获取方法的RequestMapping注解对象
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        // 获取方法的RequestMapping注解对象
        if (annotation instanceof RequestMapping) {
            // 如果注解对象是RequestMapping类型
            return (RequestMapping) annotation;
            // 将注解对象强制转换为RequestMapping类型并返回
        }
        return null;
        // 返回null,表示方法不包含RequestMapping注解
    }

    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) {
                // 遍历每个文件和子文件夹
                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 {
            // 如果文件夹不存在
            System.out.println("路径不存在");
        }
        return classFiles;
        // 返回类文件路径列表
    }
    // 结束 traverseFolder2 方法
}

测试类:Main

package com.heaboy;

import com.heaboy.mvc.HeaboyMvc;

public class Main {
    static {
        String path = Main.class.getResource("").getPath();
        String packageName = Main.class.getPackage().getName();
        HeaboyMvc.scanner(path,packageName);
    }

    public static void main(String[] args) {
        HeaboyMvc.exec("","");
        HeaboyMvc.exec("test","index1");
        HeaboyMvc.exec("test","index2");
        HeaboyMvc.exec("test","");
        HeaboyMvc.exec("test","dadasdadad");
        HeaboyMvc.exec("","index1");
    }
}

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

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

相关文章

高效前端开发:解密pnpm的存储与链接

什么是pnpm PNPM&#xff08;Performant NPM&#xff09;是一种快速且节省磁盘空间的包管理工具。相较于其他包管理器如NPM和Yarn&#xff0c;PNPM通过独特的存储机制和链接技术解决了许多常见的问题。以下是PNPM如何避免这些问题以及其关键技术的详细介绍。 特性 PNPM Store…

初始redis:在Ubuntu上安装redis

1.先切换到root用户 使用su命令切换到root 2.使用apt命令来搜索redis相关的软件包 命令&#xff1a;apt search redis 3.下载redis 命令&#xff1a; apt install redis 在Ubuntu 20.04中 &#xff0c;下载的redis版本是redis5 4.查看redis状态 命令&#xff1a; netst…

jmeter-beanshell学习5-beanshell加减乘除运算

我用到的场景是计算金额&#xff0c;所以主要以金额为主&#xff0c;感觉这部分有点麻烦&#xff0c;直接写遇到的几个坑&#xff0c;就不演示解决的过程了。 1.最早写了个两数相减&#xff0c;但是小数精度容易出现问题。比如1-0.010.989999997这种情况&#xff0c;随便写的几…

【Java]认识泛型

包装类 在Java中&#xff0c;由于基本类型不是继承自Object&#xff0c;为了在泛型代码中可以支持基本类型&#xff0c;Java给每个基本类型都对应了一个包装类型。 除了 Integer 和 Character&#xff0c; 其余基本类型的包装类都是首字母大写。 泛型 泛型是在JDK1.5引入的…

第一百四十九节 Java数据类型教程 - Java子字符串、字符串转换

Java数据类型教程 - Java子字符串 获取子字符串 我们可以使用substring()方法来获取字符串的子部分。 我们可以将开始索引作为参数&#xff0c;并返回一个从开始索引开始到字符串结尾的子串。 我们还可以将开始索引和结束索引作为参数。 它返回从开始索引开始的子字符串和小…

项目记录:一个用python编写的简易版点餐系统

最近无聊做了一个简易版本的点餐系统&#xff0c;简单记录一下。吐槽一下最近的心情&#xff0c;最近心情较差&#xff0c;应该近期会去南昌玩吧&#xff0c;懂南昌的朋友可以评论区推荐下游玩攻略&#xff0c;非常感谢&#xff01; &#xff08;1&#xff09;相关配置信息&…

基于复旦微V7 690T FPGA +ARM/海光X86+AI的全国产化数据采集人工智能平台

国产化FPGA&#xff1a;JFM7VX690T80主机接口&#xff1a;PCIe Gen3 x88Gbps/lane光纤通道&#xff1a;前面板4路SFP光纤&#xff0c;后面板1路QSFP光纤2组独立的DDR3 SDRAM 缓存&#xff0c;工作时钟频率800MHz2个FMC接口扩展&#xff1a;每个支持16路GTH&#xff0c;线速率10…

Nuxt框架中内置组件详解及使用指南(三)

title: Nuxt框架中内置组件详解及使用指南&#xff08;三&#xff09; date: 2024/7/8 updated: 2024/7/8 author: cmdragon excerpt: 摘要&#xff1a;“Nuxt 3框架中与组件的深度使用教程&#xff0c;包括如何使用这两个组件进行页面导航和加载指示的自定义配置与实战示例…

平安银行秋招攻略,考试内容详解

平安银行秋招简介 在众多的银行招聘中&#xff0c;平安银行的招聘难度相对较低&#xff0c;根据考生的反馈情况来看&#xff0c;仔细的进行准备&#xff0c;平安银行上岸并不是难题&#xff0c;那么平安银行的秋招何时开始&#xff1f; 平安银行的秋招开始时间相对较晚&#…

dependencyManagement的作用、nacos的学习

使用SpringCloudAlibaba注意各组件的版本适配 SpringCloudAlibaba已经包含了适配的各组件&#xff08;nacos、MQ等&#xff09;的版本号&#xff0c;也是一个版本仲裁者&#xff0c;但是可能已经有了父项目Spring-Boot-Starter-Parent这个版本仲裁者&#xff0c;又不能加多个父…

.hmallox勒索病毒:全面防御策略

引言 近年来&#xff0c;随着网络技术的飞速发展&#xff0c;勒索病毒成为网络安全领域的一大威胁&#xff0c;其中.hmallox勒索病毒以其高度的隐蔽性和破坏性&#xff0c;尤为引人注目。这种病毒通过加密用户计算机中的重要文件&#xff0c;并以支付赎金作为解密条件&#xff…

LeetCode——第 405 场周赛

题目 找出加密后的字符串 给你一个字符串 s 和一个整数 k。请你使用以下算法加密字符串&#xff1a; 对于字符串 s 中的每个字符 c&#xff0c;用字符串中 c 后面的第 k 个字符替换 c&#xff08;以循环方式&#xff09;。 返回加密后的字符串。 示例 1&#xff1a; 输入&…

docker部署onlyoffice,开启JWT权限校验Token

原来的部署方式 之前的方式是禁用了JWT&#xff1a; docker run -itd -p 8080:80 --name docserver --network host -e JWT_ENABLEDfalse --restartalways onlyoffice/documentserver:8 新的部署方式 参考文档&#xff1a;https://helpcenter.onlyoffice.com/installation/…

【专项刷题】— 位运算

常见类型介绍&#xff1a; & &#xff1a;有 0 就是 0 | &#xff1a;有 1 就是 1 ^ &#xff1a;相同为 0 &#xff0c;相异为 1 或者 无进位相加给定一个数确定它的二进制位的第x个数是0还是1&#xff1a;将一个数的二进制的第x位改成1&#xff1a;将一个数的二进制的第x…

【Java探索之旅】多态:向上下转型、多态优缺点、构造函数陷阱

文章目录 &#x1f4d1;前言一、向上转型和向下转型1.1 向上转型1.2 向下转型 二、多态的优缺点2.1 多态优点2.2 多态缺陷 三、避免避免构造方法中调用重写的方法四、好的习惯&#x1f324;️全篇总结 &#x1f4d1;前言 在面向对象编程中&#xff0c;向上转型和向下转型是常用…

Redis组建哨兵模式

主172.17.60.131 从172.17.60.130、172.17.60.129 redis部署 [rootlocalhost app]# tar xf redis-6.2.9.tar.gz [rootlocalhost app]# cd redis-6.2.9/ [rootlocalhost redis-6.2.9]# make MALLOClibc [rootlocalhost redis-6.2.9]# make install PREFIX/usr/local/redis…

[ICS] Modbus未授权攻击S7协议漏洞利用

工业控制系统历史 在可编程逻辑控制器(plc)成为标准之前&#xff0c;工厂车间自动化是通过机架和机架的工业继电器&#xff0c;气动柱塞计时器和电磁计数器来控制电机的启动和停止&#xff0c;阀门的打开以及其他与控制相关的过程交互。运行这种设置的控制程序根本不是程序&am…

鲁能巴蜀中学洛谷团队

鲁能巴蜀中学洛谷团队出错了 - 洛谷https://www.luogu.com.cn/team/76926

案例精选 | 聚铭综合日志分析系统为江苏省电子口岸构建高效安全的贸易生态

江苏省电子口岸有限公司&#xff0c;成立于2009年&#xff0c;由江苏省贸促会携手南京海关、江苏检验检疫局及江苏海事局等部门共同出资组建。公司承载着推动江苏乃至长三角地区国际贸易便利化的重大使命&#xff0c;致力于打造一个集先进性、创新性、高效性于一体的电子口岸综…

学习笔记——动态路由——OSPF(认证)

十二、OSPF邻居认证 1、OSPF邻居认证概述 链路是路由器接口的另一种说法&#xff0c;因此OSPF也称为接口状态路由协议。OSPF通过路由器之间通告网络接口的状态来建立链路状态数据库&#xff0c;生成最短路径树&#xff0c;每个OSPF路由器使用这些最短路径构造路由表。 OSPF认…