手写简单模拟mvc
目录结构:

两个注解类:
@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 {@RequestMappingpublic 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 {@RequestMappingpublic 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为一个新的HashMapobjMap.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) {// 如果注解对象不为nullreturn true;// 返回true,表示类为控制器}return false;// 返回false,表示类不是控制器}private static boolean isRequestMapping(Class cl) {// 定义一个私有的静态方法,用于检查类是否包含RequestMapping注解Annotation annotation = cl.getAnnotation(RequestMapping.class);// 获取类的RequestMapping注解对象if (annotation != null) {// 如果注解对象不为nullreturn true;// 返回true,表示类包含RequestMapping注解}return false;// 返回false,表示类不包含RequestMapping注解}private static boolean isRequestMapping(Method method) {// 定义一个私有的静态方法,用于检查方法是否包含RequestMapping注解Annotation annotation = method.getAnnotation(RequestMapping.class);// 获取方法的RequestMapping注解对象if (annotation != null) {// 如果注解对象不为nullreturn 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");}
}
相关文章:
手写简单模拟mvc
目录结构: 两个注解类: Controller: package com.heaboy.annotation;import java.lang.annotation.*;/*** 注解没有功能只是简单标记* .RUNTIME 运行时还能看到* .CLASS 类里面还有,构建对象久没来了,这个说明…...
【FreeRTOS】同步互斥与通信 FreeRTOS提供的方法
目录 各类方法的对比队列事件组信号量互斥量任务通知 各类方法的本质 使用全局变量可以实现通信,但是使用全局变量会有一些缺陷。 那我们怎么保证通信的正确性呢??? 我们需要引入很多互斥的方法。除了互斥之外,还需要高…...
Kafka 面试题指南
Kafka 面试题指南 本文档提供了一份详细的 Kafka 面试题指南,涵盖了 Kafka 的核心概念、架构、配置、操作和实际应用场景等方面的内容。希望通过这份指南能够帮助你在 Kafka 面试中取得成功。 目录 Kafka 基础知识 什么是 Kafka?Kafka 的主要特点是什…...
2024年7月5日 (周五) 叶子游戏新闻
老板键工具来唤去: 它可以为常用程序自定义快捷键,实现一键唤起、一键隐藏的 Windows 工具,并且支持窗口动态绑定快捷键(无需设置自动实现)。 卸载工具 HiBitUninstaller: Windows上的软件卸载工具 《乐高地平线大冒险》为何不登陆…...
热门开源项目推荐:探索开源世界的精彩
热门开源项目推荐 随着开源程序的发展,越来越多的程序员开始关注并加入开源大模型的行列。开源不仅为个人学习和成长提供了绝佳的平台,也为整个技术社区带来了创新和进步。无论你是初学者还是经验丰富的开发者,参与开源项目都能让你受益匪浅…...
Codeforces Round #956 (Div. 2) and ByteRace 2024(A~D题解)
这次比赛也是比较吃亏的,做题顺序出错了,先做的第三个,错在第三个数据点之后,才做的第二个(因为当时有个地方没检查出来)所以这次比赛还是一如既往地打拉了 那么就来发一下题解吧 A. Array Divisibility …...
基于YOLOv9的脑肿瘤区域检测
数据集 脑肿瘤区域检测,我们直接采用kaggle公开数据集,Br35H 数据中已对医学图像中脑肿瘤位置进行标注 数据集我已经按照YOLO格式配置好,数据内容如下 数据集中共包含700张图像,其中训练集500张,验证集200张 模型训…...
阿里云 ECS 服务器的安全组设置
阿里云 ECS 服务器的安全组设置 缘由安全组多个安全组各司其职一些常见的IP段百度 IP 段华为云 IP 段搜狗蜘蛛 IP 段阿里云 IP 段 。。。 缘由 最近公司规模缩减,原有的托管在 IDC 机房的服务器,都被处理掉了,所有代码都迁移到了阿里云的云服…...
昇思25天学习打卡营第15天|应用实践之ShuffleNet图像分类
基本介绍 今天的应用实践的领域是计算机视觉领域,更确切的说是图像分类任务,不过,与昨日不同的是,今天所使用的模型是ShuffleNet模型。ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型,和MobileNet, SqueezeNet等一…...
怀庄之醉适合搭配什么食物?
怀庄之醉作为一种独特的佳酿,其丰富的香气和层次感使其能够与多种食物搭配,提升餐饮体验。以下将具体探讨怀庄之醉适合搭配的食物类型,并分析为何这些搭配能够带来卓越的味觉享受。 一、肉类佳肴 怀庄之醉因其浓郁的口感,特别适…...
Java | Leetcode Java题解之第223题矩形面积
题目: 题解: class Solution {public int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) {int area1 (ax2 - ax1) * (ay2 - ay1), area2 (bx2 - bx1) * (by2 - by1);int overlapWidth Math.min(ax2, bx2) -…...
基于单片机的空调控制器的设计
摘 要 : 以单片机为核心的空调控制器因其体积小 、 成本低 、 功能强 、 简便易行而得到广泛应用 。 本设计通过 AT89S52 控制DS18&a…...
企业如何利用短视频平台做口碑塑造和品牌营销?
随着短视频平台的不断发展,新型的双微一抖小红书等新媒体平台,正在成为网民聚集的核心平台,小马识途营销顾问认为越来越多的企业应该利用这些平台进行品牌营销和宣传。其中,抖音和小红书作为短视频平台的代表,吸引了大…...
SQL INSERT批量插入方式
1、常规INSERT写法 INSERT INTO ... VALUES (...);INSERT INTO 表名( 字段1, 字段2) VALUES (字段1的值, 字段2的值);2、SELECT语句返回值INSERT INSERT INTO ...VALUES (..., (select ...));INSERT INTO 表名1(字段1, 字段2) VALUES (字段1的值, (select 查询字段 from 表名2 …...
2.5 C#视觉程序开发实例1----IO_Manager实现切换程序
2.5 C#视觉程序开发实例1----IO_Manager实现切换程序 1 IO_Manager中输入实现 1.0 IO_Manager中输入部分引脚定义 // 设定index 目的是为了今后可以配置这些参数、 // 输入引脚定义 private int index_trig0 0; // trig index private int index_cst 7; //cst index priva…...
【入门篇】STM32寻址范围(更新中)
写在前面 STM32的寻址范围涉及存储器映射和32位地址线的使用。并且STM32的内存地址访问是按字节编址的,即每个存储单元是1字节(8位)。 一、寻址大小与范围 地址线根数 地址编号(二进制) 地址编号数(即内存大小) <...
DDD架构
1.DDD架构的概念: 领域驱动设计(Domain-Driven Design, DDD)是一种软件设计方法,旨在将软件系统的设计和开发焦点集中在领域模型上,以解决复杂业务问题 2.DDD架构解决了什么问题: 在以前的mvc架构种,三层结…...
Open3D KDtree的建立与使用
目录 一、概述 1.1kd树原理 1.2kd树搜索原理 1.3kd树构建示例 二、常见的领域搜索方式 2.1K近邻搜索(K-Nearest Neighbors, KNN Search) 2.2半径搜索(Radius Search) 2.3混合搜索(Hybrid Search) …...
C语言编程3:运算符,运算符的基本用法
C语言3🔥:运算符,运算符的基本用法 一、运算符🌿 🎇1.1 定义 运算符是指进行运算的动作,比如加法运算符"“,减法运算符”-" 算子是指参与运算的值,这个值可能是常数&a…...
如何通过SPI机制去实现读取配置文件并动态加载对应实现类
最近写完鱼皮的RPC项目后,打算整理出来一些编程技巧的模版。 有两种实现:1.ServiceLoader 2.SpiLoader 一、直接使用java.util下的ServiceLoader 首先在resource目录下创建 META-INF/services 目录,并且创一个名称为对应要实现的接口的包…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
