当前位置: 首页 > news >正文

手写简单模拟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

目录结构&#xff1a; 两个注解类&#xff1a; Controller&#xff1a; package com.heaboy.annotation;import java.lang.annotation.*;/*** 注解没有功能只是简单标记* .RUNTIME 运行时还能看到* .CLASS 类里面还有&#xff0c;构建对象久没来了&#xff0c;这个说明…...

【FreeRTOS】同步互斥与通信 FreeRTOS提供的方法

目录 各类方法的对比队列事件组信号量互斥量任务通知 各类方法的本质 使用全局变量可以实现通信&#xff0c;但是使用全局变量会有一些缺陷。 那我们怎么保证通信的正确性呢&#xff1f;&#xff1f;&#xff1f; 我们需要引入很多互斥的方法。除了互斥之外&#xff0c;还需要高…...

Kafka 面试题指南

Kafka 面试题指南 本文档提供了一份详细的 Kafka 面试题指南&#xff0c;涵盖了 Kafka 的核心概念、架构、配置、操作和实际应用场景等方面的内容。希望通过这份指南能够帮助你在 Kafka 面试中取得成功。 目录 Kafka 基础知识 什么是 Kafka&#xff1f;Kafka 的主要特点是什…...

2024年7月5日 (周五) 叶子游戏新闻

老板键工具来唤去: 它可以为常用程序自定义快捷键&#xff0c;实现一键唤起、一键隐藏的 Windows 工具&#xff0c;并且支持窗口动态绑定快捷键&#xff08;无需设置自动实现&#xff09;。 卸载工具 HiBitUninstaller: Windows上的软件卸载工具 《乐高地平线大冒险》为何不登陆…...

热门开源项目推荐:探索开源世界的精彩

热门开源项目推荐 随着开源程序的发展&#xff0c;越来越多的程序员开始关注并加入开源大模型的行列。开源不仅为个人学习和成长提供了绝佳的平台&#xff0c;也为整个技术社区带来了创新和进步。无论你是初学者还是经验丰富的开发者&#xff0c;参与开源项目都能让你受益匪浅…...

Codeforces Round #956 (Div. 2) and ByteRace 2024(A~D题解)

这次比赛也是比较吃亏的&#xff0c;做题顺序出错了&#xff0c;先做的第三个&#xff0c;错在第三个数据点之后&#xff0c;才做的第二个&#xff08;因为当时有个地方没检查出来&#xff09;所以这次比赛还是一如既往地打拉了 那么就来发一下题解吧 A. Array Divisibility …...

基于YOLOv9的脑肿瘤区域检测

数据集 脑肿瘤区域检测&#xff0c;我们直接采用kaggle公开数据集&#xff0c;Br35H 数据中已对医学图像中脑肿瘤位置进行标注 数据集我已经按照YOLO格式配置好&#xff0c;数据内容如下 数据集中共包含700张图像&#xff0c;其中训练集500张&#xff0c;验证集200张 模型训…...

阿里云 ECS 服务器的安全组设置

阿里云 ECS 服务器的安全组设置 缘由安全组多个安全组各司其职一些常见的IP段百度 IP 段华为云 IP 段搜狗蜘蛛 IP 段阿里云 IP 段 。。。 缘由 最近公司规模缩减&#xff0c;原有的托管在 IDC 机房的服务器&#xff0c;都被处理掉了&#xff0c;所有代码都迁移到了阿里云的云服…...

昇思25天学习打卡营第15天|应用实践之ShuffleNet图像分类

基本介绍 今天的应用实践的领域是计算机视觉领域&#xff0c;更确切的说是图像分类任务&#xff0c;不过&#xff0c;与昨日不同的是&#xff0c;今天所使用的模型是ShuffleNet模型。ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一…...

怀庄之醉适合搭配什么食物?

怀庄之醉作为一种独特的佳酿&#xff0c;其丰富的香气和层次感使其能够与多种食物搭配&#xff0c;提升餐饮体验。以下将具体探讨怀庄之醉适合搭配的食物类型&#xff0c;并分析为何这些搭配能够带来卓越的味觉享受。 一、肉类佳肴 怀庄之醉因其浓郁的口感&#xff0c;特别适…...

Java | Leetcode Java题解之第223题矩形面积

题目&#xff1a; 题解&#xff1a; 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) -…...

基于单片机的空调控制器的设计

摘 要 &#xff1a; 以单片机为核心的空调控制器因其体积小 、 成本低 、 功能强 、 简便易行而得到广泛应用 。 本设计通过 &#xff21;&#xff34;&#xff18;&#xff19;&#xff33;&#xff15;&#xff12; 控制&#xff24;&#xff33;&#xff11;&#xff18;&a…...

企业如何利用短视频平台做口碑塑造和品牌营销?

随着短视频平台的不断发展&#xff0c;新型的双微一抖小红书等新媒体平台&#xff0c;正在成为网民聚集的核心平台&#xff0c;小马识途营销顾问认为越来越多的企业应该利用这些平台进行品牌营销和宣传。其中&#xff0c;抖音和小红书作为短视频平台的代表&#xff0c;吸引了大…...

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架构的概念&#xff1a; 领域驱动设计&#xff08;Domain-Driven Design, DDD&#xff09;是一种软件设计方法&#xff0c;旨在将软件系统的设计和开发焦点集中在领域模型上&#xff0c;以解决复杂业务问题 2.DDD架构解决了什么问题: 在以前的mvc架构种&#xff0c;三层结…...

Open3D KDtree的建立与使用

目录 一、概述 1.1kd树原理 1.2kd树搜索原理 1.3kd树构建示例 二、常见的领域搜索方式 2.1K近邻搜索&#xff08;K-Nearest Neighbors, KNN Search&#xff09; 2.2半径搜索&#xff08;Radius Search&#xff09; 2.3混合搜索&#xff08;Hybrid Search&#xff09; …...

C语言编程3:运算符,运算符的基本用法

C语言3&#x1f525;&#xff1a;运算符&#xff0c;运算符的基本用法 一、运算符&#x1f33f; &#x1f387;1.1 定义 运算符是指进行运算的动作&#xff0c;比如加法运算符"“&#xff0c;减法运算符”-" 算子是指参与运算的值&#xff0c;这个值可能是常数&a…...

如何通过SPI机制去实现读取配置文件并动态加载对应实现类

最近写完鱼皮的RPC项目后&#xff0c;打算整理出来一些编程技巧的模版。 有两种实现&#xff1a;1.ServiceLoader 2.SpiLoader 一、直接使用java.util下的ServiceLoader 首先在resource目录下创建 META-INF/services 目录&#xff0c;并且创一个名称为对应要实现的接口的包…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分&#xff1a; 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...