仿写SpringMVC中的注解和方法映射功能

news2024/10/5 21:19:22

本项目已开源,欢迎各位大佬访问并指正:仿写SpringMVC中的注解和方法映射功能


文章目录

    • 一、仿写流程
      • 1、初始化
      • 2、测试
    • 二、代码实现
      • 1、自定义注解Controller和RequestMapping
      • 2、扫描本项目下Controller下所有的java文件
      • 3、识别注解,完成映射
      • 4、编写Controller,准备测试
      • 5、初始化并编写main方法,开始测试
      • 6、执行,测试结果

一、仿写流程

1、初始化

  • 通过扫描某路径下的文件夹和文件 通过字符串处理得到全限定名
    • 传入指定包的地址
    • 输出 List 里边的所有java文件(”.java")
  • 反射创建对象
    • url->对象 Map<String,Object>
  • 识别是否有我们所需的注解,并获取注解内的值
    • 识别类上的注解Controller
    • 识别类上的注解RequestMapping,并获取value值
    • 识别该类中方法上的注解RequestMapping,并获取value值
  • 需要构建 每个类每个方法对应url的映射结构

2、测试

  • 编写自定义注解和测试类
  • 编写测试main方法,传入请求访问路径和方法,执行

二、代码实现

1、自定义注解Controller和RequestMapping

有关知识请直接点我借一步说话

  • Controller
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
	//类型+名称+默认值
    String value() default "user";
}
  • RequestMapping
@Target(value ={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
	String value() default "index";
}

2、扫描本项目下Controller下所有的java文件

有关知识请移步

public class GetAllFiles {
	static int count = 0;
	public static List<String> getAllFiles(String path) {
		System.out.println(path);
		List<String> qualifiedPaths = new ArrayList<String>();
		String fileType = ".java";// 指定文件类型
        File file = new File(path);
        
        long start = System.currentTimeMillis();
        listAllFiles(file, fileType, qualifiedPaths);
        long end = System.currentTimeMillis();
        System.out.println("共花费:" + (end - start) + "毫秒");
        System.out.println("有" + count + "个文件");
        return qualifiedPaths;
	}
	public static void listAllFiles(File file, String fileType, List<String> qualifiedPaths){
        if (file.isFile()){
            count++;
            System.out.println(file);

            String path = file.getPath().replace('\\', '.');
            int begin = path.indexOf("Controller");
            int end = path.indexOf(".java");
            String qualifiedPath = path.substring(begin, end);
            qualifiedPaths.add(qualifiedPath);
            System.out.println(qualifiedPath);
        } else {
            if (file.exists() && file.isDirectory()){
                File[] files = file.listFiles();
                for (File file1 : files){
                    listAllFiles(file1, fileType,qualifiedPaths);
                }
            }
        }
    }
}

3、识别注解,完成映射

public class SpringMVC {
	//设置mapobj,key:拥有Controller注解的类的RequestMapping值,value:拥有Controller注解的类的class类实例
	//记录注解value值和Controller类的class实例的映射
	private static Map<String, Object> mapobj = new HashMap<String, Object>();
	//设置map,key:Controller类的RequestMapping的vaule值,
	//value:记录RequestMapping的value值和对应方法的映射
	private static Map<String, HashMap<String, Method>> map = new HashMap<>();
	
	//模拟服务器中DispatherServlet对前端传来的请求路径进行转发给各个Controller
	 public static void exec(String classPath,String methodPath){
	        if(mapobj.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(mapobj.get(classPath));
	            } catch (IllegalAccessException e) {
	                e.printStackTrace();
	            } catch (InvocationTargetException e) {
	                e.printStackTrace();
	            }
	        }
	    }
	
	}
	public static void springmvc(String path) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		path = "D:\\appdata\\ssm-workspace\\Spring\\src\\Controller";
		
		List<String> classNames = GetAllFiles.getAllFiles(path);

		for (String className:classNames) {
			Class cl = Class.forName(className);
			//System.out.println(cl.getName());
			
			//观察该类的所有注解,没鸟用,纯闲的
			Annotation[] annotations = cl.getAnnotations();
	        for (Annotation annotation : annotations) {
	            System.out.println(annotation);
	        }
	        
	        //判断java文件是否是Controller
	        Controller controller = (Controller) cl.getAnnotation(Controller.class);
	        if (controller!=null) {
	        	//如果是Controller,找到注解在该类上的RequestMapping中的value值,将映射加入到mapobj,将value值加入到map的key中
	        	RequestMapping mapping = (RequestMapping) cl.getAnnotation(RequestMapping.class);
	        	mapobj.put(mapping.value(), cl.newInstance());
	        	map.put(mapping.value(), new HashMap<String, Method>());
	        	//遍历其中的所有方法,将每一个方法上的RequestMapping注解的value值和该方法完成映射绑定
	        	Method[] methods = cl.getDeclaredMethods(); 
				for (Method m:methods) {
					Annotation[] annotations_m = m.getAnnotations();
					for (Annotation annotation : annotations_m) {
			            RequestMapping requestMapping = (RequestMapping) m.getAnnotation(RequestMapping.class);
			            map.get(mapping.value()).put(requestMapping.value(), m);
			        }
				}
	        }
		}
		//System.out.println(map.size());
		System.out.println("映射结果:");
		//1. 使用keySet方法遍历key,再通过key获取value
        for(String key:map.keySet()){  
            System.out.println(key+" "+map.get(key));
        }
		
	}
}

4、编写Controller,准备测试

  • 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 "";
    }
}
  • TestController2类
@Controller
@RequestMapping("test2")
public class TestController2 {
	@RequestMapping("index2")
	public void index2() {
		System.out.println("test2->index2");
	}
}

5、初始化并编写main方法,开始测试

public class Main {

	static {
		String path = Main.class.getResource("").getPath();
        String packageName = Main.class.getPackage().getName();
        String scannerPath = path.replaceAll(packageName, "Controller");
        try {
			SpringMVC.springmvc(scannerPath);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		System.out.println("测试结果:");
		SpringMVC.exec("test", "index");
		SpringMVC.exec("test", "index1");
		SpringMVC.exec("test2", "index2");
	}

}

6、执行,测试结果

在这里插入图片描述
可以看到完整的映射结果,几个样例的执行也没有问题,扣一波牛波一!!!

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

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

相关文章

【算组合数】CF1833 F

少见地秒了这道1700&#xff0c;要是以后都这样就好了.... Problem - F - Codeforces 题意&#xff1a; 给定一个数列&#xff0c;让你在这个数列里找一个大小为M的子集&#xff0c;使得极差不超过M 思路&#xff1a; 子集&#xff0c;不是子序列&#xff0c;说明和顺序无…

【算法与数据结构】101、LeetCode对称二叉树

文章目录 一、题目二、递归法三、迭代法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、递归法 思路分析&#xff1a;这道题目标就是要对比左右两半的树是否对称&#xff0c;因此对比不是左右节点是否相等&…

ThreadPoolExecutor自定义线程池|拒绝策略|线程工厂|统一捕获异常

线程池的7大参数含义介绍 corePoolSize&#xff1a;池中一直保持的线程的数量。 maximumPoolSize&#xff1a;池中允许的最大的线程数。 keepAliveTime&#xff1a;当线程数大于核心线程数的时候&#xff0c;线程在最大多长时间没有接到新任务就会终止释放&#xff0c; 最终…

点击加号添加新的输入框

实现如上图的效果 html部分&#xff1a; <el-form-item class"forminput" v-for"(item,index) in formdata.description" :key"index" :label"描述(index1)" prop"description"><el-input v-model"formdata…

STM32入门之创建工程模板

1.STM32固件库的结构图如下。从图中可以看出&#xff0c;我们在配置STM32的固件库时需要配置用户层、CMSIS层的文件。配置库文件即正确的配置这些函数的文件。CMSIS(Cortex Microcontroller Software Interface Standard)是ARM公司提供的微控制器软件接口标准&#xff0c;所有使…

栈和队列(基础知识和基本操作)

栈&#xff1a; 1.栈&#xff1a;在表尾进行插入和删除的操作受限的线性表。 2.逻辑结构&#xff1a;线性结构【一对一的关系】 3.存储结构&#xff1a;顺序存储【顺序栈】、链式存储【链栈】 4.栈的特点&#xff1a;先进后出【first in last out FILO表】 后进先出【last…

消息队列 CKafka 跨洋数据同步性能优化

导语 本文主要介绍了 CKafka 在跨洋场景中遇到的一个地域间数据同步延时大的问题&#xff0c;跨地域延时问题比较典型&#xff0c;所以详细记录下来做个总结。 一. 背景 为了满足客户跨地域容灾、冷备的诉求&#xff0c;消息队列 CKafka 通过连接器功能&#xff0c;提供了跨…

5.4.tensorRT基础(2)-学习第一个插件的编写

目录 前言1. 插件2. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 基础-学习第一个插件的编写 课程大…

python sorted函数

python列表排序 简单记一下python中List的sort方法&#xff08;或者sorted内建函数&#xff09;的用法。 关键字&#xff1a; python列表排序 python字典排序 sorted List的元素可以是各种东西&#xff0c;字符串&#xff0c;字典&#xff0c;自己定义的类等。 sorted函数用法如…

【项目 进程6】 2.13 匿名管道通信案例 2.14管道的读写特点和管道设置为非阻塞

文章目录 2.13 匿名管道通信案例匿名管道的使用实现 ps aux | grep xxx 父子进程间通信 2.14管道的读写特点和管道设置为非阻塞管道的读写特点&#xff1a;总结设置管道非阻塞 2.13 匿名管道通信案例 匿名管道的使用 一般匿名管道不推荐父进程与子进程交叉读写数据&#xff0c…

nginx 配置 wss加密访问 mqtt

1. 在服务器上部署mqtt服务 2.在宝塔上配置域名证书 3.nginx配置websocket server {listen 80;listen 443 ssl http2;server_name ws-xx.example.com;index index.php index.html index.htm default.php default.htm default.html;root /www/wwwroot/ws-xx.example.com;loca…

金融软件技术:创新与安全并行驶

随着科技的迅速发展&#xff0c;金融行业正经历着一场前所未有的数字化转型。金融机构需要不断创新和提升效率&#xff0c;以满足客户需求&#xff0c;并保持竞争优势。在这个数字时代中&#xff0c;金融软件技术成为了实现这一目标的关键要素。本文将从两个方面探讨金融软件技…

fastadmin采坑之富文本编辑器

整了好久才弄好&#xff0c;后缀为content&#xff0c;类型为text 或者longtext类型&#xff0c;这样做命令行才能成功

Python教程(5)——Python的第一个程序

python的环境以及IDE都准备好之后&#xff0c;我们就可以开始Python之旅了。Python的第一个程序通常是打印输出"Hello, World!"&#xff0c;非常简单。以下是一个示例&#xff1a; print("Hello, World!")运行python代码 首先必须明白python是一门动态语…

Asp.net Core配置CORS 跨域无效(记录一下)

问题 学习老杨的英语网站项目&#xff0c;运行项目时&#xff0c;发现出现了跨域的问题。 然后自己建一项目&#xff0c;进行配置&#xff0c;测试&#xff0c;发现配置CORS 跨域时&#xff0c;发现跨域的配置无效&#xff0c;依旧报错。 解决 网上找了一天&#xff0c;然后…

【Uniapp,Vue】阻止父元素事件覆盖子元素事件

有个需求&#xff0c;点击一个元素&#xff0c;让弹出框显示&#xff0c;点击弹出框以外的区域&#xff0c;就关闭弹出框&#xff0c;如下代码所示。 但是这样有个问题&#xff0c;就是当弹出框显示以后&#xff0c;点击弹出框的区域也会触发父元素的点击事件&#xff0c;使得i…

【多模态】17、CORA | 将 CLIP 使用到开集目标检测

文章目录 一、背景二、方法2.1 总体结构2.2 region prompting2.3 anchor pre-matching 三、效果 论文&#xff1a;CORA: Adapting CLIP for Open-Vocabulary Detection with Region Prompting and Anchor Pre-Matching 代码&#xff1a;https://github.com/tgxs002/CORA 出处…

小程序路由跳转页面重复问题

目标&#xff1a;想要某个页面在历史中&#xff08;页面栈&#xff09;只显示一次 什么是页面栈&#xff1a; 在小程序开发中&#xff0c;页面栈是指小程序当前打开的页面的层级关系堆栈。每当打开一个新页面时&#xff0c;它会被放置在页面栈的顶部&#xff0c;而当前页面就位…

如何实现外网远程访问路由内部服务器主机端口应用?

路由器是上网常见的设备。在我们开通网络接入带宽时&#xff0c;或需要进行管理路由网络操作时&#xff0c;就需要登录路由后台设置配置相关操作。 我们在涉及路由管理方面经常会遇到一些常见的问题。路由管理入口地址是什么&#xff1f;如何配置路由有线网络或无线网络或分配…

uniapp开启消息通知/提示(使用uniPush)

亲爱的小伙伴们&#xff0c;最近对uniPush有稍许研究&#xff0c;当前研究出一些心得&#xff0c;现在分项给大家&#xff0c;希望对大家的uniapp之路有所帮助。本次的教程是教会你如何使用uniPush自定义消息通知&#xff0c;同时还附带添加消息提示音添加&#xff0c;多的不说…