[SpringMVC]仿写SpringMVC(注解开发)

news2024/11/26 15:45:39

文章目录

  • 前提:
  • 1、代码结构
  • 2、核心:YhzMVC
  • 3、初始化步骤是:
  • 4、执行

前提:

当前版本无接受网络请求功能,不喜勿喷🙏🙏
本文将对代码核心进行讲解,源码已上传到gitee仓库

1、代码结构

在这里插入图片描述
如果对反射有些忘记了,可以先移步到这里,对反射进行了详解

如果对注解有些忘记了,可以先移步到这里,对注解进行了详解

2、核心:YhzMVC

package Test.mvc;

import Test.Test;
import Test.annotation.Controller;
import Test.annotation.RequestMapping;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @BelongsProject: 3.9.demo
 * @Author: yhz
 * @CreateTime: 2023-07-22  14:36
 * @Description: TODO
 * @Version: 1.0
 */
public class YhzMVC {
    //存的是该项目文件夹中所有.java结尾文件的全限定名
    public static List<String>arr= new ArrayList<>();

    //存的是每个controller上requestmapping的value以及该controller下所有的requestmapping的value以及所属方法
    public static HashMap<String, Map<String, Method>> map=new HashMap<>();

    //controller的requestmapping的value值以及controller对象
    public static Map<String,Object>controllerMap = new HashMap<>();




    public static void exec(String classPath,String methodPath){
        if(controllerMap.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(controllerMap.get(classPath));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public static void getFilePath(File file) {
        File[] fs = file.listFiles();
        for (File f : fs) {
            if (f.isDirectory()){
                getFilePath(f);
            }
            if (f.isFile()) {
                String filepath = f.toString();
                filepath = filepath.split("src")[1];
                filepath = filepath.substring(1,filepath.length());
                if( filepath.endsWith(".java")) {
                    //把是.java文件的全类名放到arr中
                    arr.add(filepath.replace("\\", ".").replace(".java", ""));
                }
            }
        }
    }

    //查找所有controller,并创建对象装入Map里(“url”:Object)
    public static void chooseController() {
        for(String file: arr){
            try {
                Class<?> aClass = Class.forName(file);
                //如果有Controller注解
                if(aClass.isAnnotationPresent(Controller.class)){
                    //如果有RequestMapping注解
                    if(aClass.isAnnotationPresent(RequestMapping.class)){
                        RequestMapping requestMapping = getRequestMapping(aClass);
                        //如果之前已经有了一样的  不同controller的requestmapping的值,说明有冲突。
                        if(map.containsKey(requestMapping.value())){
                            throw  new RuntimeException("类多注解值:"+requestMapping.value());
                        }else {
                            map.put(requestMapping.value(),new HashMap<>());
                            controllerMap.put(requestMapping.value(),aClass.newInstance());
                        }
                        Method[] declaredMethods = aClass.getDeclaredMethods();
                        for (Method declaredMethod : declaredMethods) {
                            if(declaredMethod.isAnnotationPresent(RequestMapping.class)){
                                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);
                                }
                            }
                        }

                    }else {
                        throw  new RuntimeException("类无requestMapping注解");
                    }
                }
            }catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
    //Java基础 : 方法的重载。
    public static RequestMapping getRequestMapping(Class cl){
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }
    public static RequestMapping getRequestMapping(Method method){
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }
}

3、初始化步骤是:

  1. 定义3个静态集合,arr装遍历到的所有java文件的全类名、controllerMap装controller的url与controller的映射结构、map装每个controller的url与每个controller里每个方法的url与方法的map的映射结构
  2. 通过给getFilePath(File file)方法传入源代码根目录,对项目中所有以.java结尾的java文件进行搜索,对每个java文件的路径进行字符串处理,得到文件的全限定名(包名+类名),然后将全限定名装入list中,用于反射(Class.forName(String className))。
    例如:
    在这里插入图片描述
  3. 对每个java文件进行遍历,通过反射识别类上是否有我们所需的注解,找到带有@Controller注解和@RequestMapping注解的类,如果只有@Controller,没有@RequestMapping,那么抛出一个运行时异常(类无requestMapping注解)。通过反射获取类上的@RequestMapping注解内的值,先对值进行判断,是否map里已经存在了这个值,如果存在,抛出一个运行时异常(类多注解值:"+requestMapping.value());如果不存在,向map中添加(controller的url,new HashMap)(这个new 的HashMap,用来装controller里的方法上的url与方法的映射结构)、向controllerMap中添加(controller的url,controller的实例)。对类操作完,接下来对类里的方法进行遍历,先判断方法上是否带有@RequestMapping注解,如果有,再判断,这个方法上@RequestMapping注解的值是否已经存在了,如果存在,抛出一个运行时异常(“方法多注解值:”+mapping.value());如果当前值是唯一的,则获取到map中当前controller类的url对应的HashMap,将方法的url与方法的映射结构装入得到的HashMap。

4、执行

  1. 传入的两个字符串参数,一个controller的url:classPath,一个方法的url:methodPath
  2. 先判断controllerMap中是否包含classPath这个key,如果不包含则认为没有这个类;如果包含,再判断map的classPath对用的value里是否包含methodPath,如果不包含,则认为这个类里没有这个方法;如果包含,则通过反射执行该方法(method.invoke(Object obj, Object… args))

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

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

相关文章

SpringBoot集成Druid实现数据库连接池

一、引入依赖 完整的pom文件如下所示: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http…

第四讲:MySQL中DDL一些基本数据类型及表的创建、查询

目录 1、创建表:2、DDL一些基本数据类型&#xff1a; 1、创建表: 部分单词及解析&#xff1a; 1、tables:表 2、comment:评论&#xff0c;解释 3、gender:性别 4、neighbor&#xff1a;邻居 1、创建表&#xff1a;&#xff08;注&#xff1a;在自定义数据库操作&#xff0c;…

Vue--》打造个性化医疗服务的医院预约系统(二)

今天开始使用 vue3 + ts 搭建一个医院预约系统的前台页面,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关…

分布式锁:Redis、Zookeeper

1.基于Redis实现分布式锁&#xfeff; Redis分布式锁原理如上图所示&#xff0c;当有多个Set命令发送到Redis时&#xff0c;Redis会串行处理&#xff0c;最终只有一个Set命令执行成功&#xff0c;从而只有一个线程加锁成功 2.SetNx命令加锁 利用Redis的setNx命令在Redis数据库…

01 openEuler操作系统介绍

文章目录 01 openEuler操作系统介绍1.1 发布件1.2 最小硬件要求1.3 硬件兼容性1.4 关键特性1.4.1 openEuler 22.03-LTS基于 Linux Kernel 5.10 内核构建, 在进程调度、内存管理等方面带来10余处创新1.4.2 新介质文件系统1.4.3 内存分级扩展1.4.4 用户态协议栈1.4.5 云原生调度增…

【人工智能】深度优先搜索、代价一致搜索、深度有限搜索、迭代深度优先搜索、图搜索

【人工智能】无信息搜索—BFS 、代价一致、DFS、深度受限、迭代深入深度优先、图搜索 什么是搜索 搜索问题是指既不能通过数学建模解决,又没有其他算法可以套用或者非遍历所有情况才能得出正确结果。这时就需要采用搜索算法来解决问题。搜索就是一种通过穷举所有解的状态,来…

【车载开发系列】AUTOSAR DemDTCAttributes

【车载开发系列】AUTOSAR DemDTCAttributes 【车载开发系列】AUTOSAR DemDTCAttributes 【车载开发系列】AUTOSAR DemDTCAttributes一. DemDTCAttributes概念二. DemAgingCycleCounterThreshold三. DemAgingAllowed四. DemDTCPriority五. DemImmediateNvStorage六. DemMaxNumbe…

BatchNorm, LayerNorm, InstanceNorm和GroupNorm

1. 介绍 Batch Norm: 对NHW计算归一化参数(均值和方差)&#xff0c;总共得到C组归一化参数, 相当于对每个channel进行归一化。BN主要缺点是对batchsize的大小比较敏感&#xff0c;由于每次计算均值和方差是在一个batch上&#xff0c;所以如果batchsize太小&#xff0c;则计算的…

idea2021.安装pojie教程

1、下载ideaIU-2021.3应用包&#xff0c;点击finish 2、先关闭idea窗口&#xff0c;等会激活了脚本再运行打开。 3、双击运行install-current-user.vbs&#xff0c;等待一会会提示运行成功。 4、运行后&#xff0c;在文件中会多出一条配置 5、打开运行idea,输入激活码&#x…

iPhone 开机停留在苹果logo画面(已解决)

一、问题 如下图&#xff0c;开不了机&#xff1a; 标题 二、根因 存储空间满了。 三、解决方法 方法一 用苹果数据线&#xff08;最好是原装&#xff09;连接Mac电脑&#xff0c;在装有 macOS Catalina 10.15 或更高版本的 Mac 上&#xff0c;打开“访达”。在装有 macOS…

Vue-组件高级(上)

一、目标 能够掌握watch侦听器的基本使用能够知道vue中常用的生命周期函数能够知道如何实现组件之间的数据共享能够知道如何在vue3.x的项目中全局配置axios 二、目录 watch侦听器 1.什么是watch侦听器 watch侦听器允许开发之监视数据的变化&#xff0c;从而针对数据的变化做…

什么小程序需要商家自营相关类目?

1、百货&#xff1a;小程序主体公司综合零售商&#xff0c;在线售卖多种日用品&#xff0c;需补充商家自营-百货类目。预包装食品定义&#xff1a; 预包装食品&#xff0c;指预先定量包装或者制作在包装材料和容器中的食品&#xff1b;包括预先定量包装以及预先定量制作在包装…

微信小程序中如何携带参数跳转到tabBar页面

在小程序中使用了tabBar组件之后就不能用wx.navigateTo跳转到tabBar页面了 , 能跳转到tabBar页面的方法有以下两种 但是使用第一种方法时,会因为这种方法在路径后不能携带参数,所以行不通 那么就只能用第二种方法 , 用wx.reLaunch进行跳转 , 地址后跟上自己想要的参数 , 或者用…

使用Vue+elementUI实现CRUD

文章目录 前言一、简介二、使用Vue-Cli搭建Vue项目1. vue-cli 介绍2.axios.js 介绍3.Element-Ul 介绍4.moment.js 介绍5.搭建项目6.添加main.js配置7.修改App.vue8. 将moment.js 格式 Date 类型引入9. 加入分页10. 实现删除11. 实现添加12. 实现修改 总结 前言 最近了解了一下…

Qt 模态 非模态对话框 半模态 不阻塞对话框

Part1&#xff1a; 什么是模态和非模态对话框 对话框分为模态对话框和非模态对话框。 所谓模态对话框 所谓模态对话框&#xff0c;会阻塞同一应用程序中其它窗口的输入。同时会阻塞当前线程&#xff1b;程序不再下执行&#xff1b; 关闭 窗口&#xff0c;执行下面的代码&a…

从Nginx学习如何获取时间

最近因为工作接触到Nginx的学习&#xff0c;我就把Nginx的源代码下载下来&#xff0c;然后对其进行了分析。发现Nginx的性能强大离不开作者编码的苦心&#xff0c;作者将C的性能发挥到了极致&#xff0c;每个变量都用得非常出神入化。有如此强大的功能&#xff0c;才支撑了全球…

React:从 npx开始

使用 npm 来创建第一个 recat 文件&#xff08; react-demo 是文件名&#xff0c;可以自定义&#xff09; npx create-react-app react-demo npx是 npm v5.2 版本新添加的命令&#xff0c;用来简化 npm 中工具包的使用 原始&#xff1a; 全局安装npm i -g create-react-app 2 …

格式工厂5.10.0版本安装

目前格式工厂有很多&#xff0c;大多都可以进行视频转换 之前遇到一个用ffmpeg拉流保存的MP4在vlc和迅雷都无法正常播放的问题&#xff0c;发现视频长度不对&#xff0c;声音也不对&#xff0c;最后换到了格式工厂的格式播放器是可以正常播放的 格式工厂下载之家的地址 http…

【历史上的今天】7 月 20 日:人类登上月球;数据仓库之父诞生;Mac OS X Lion 发布

整理 | 王启隆 透过「历史上的今天」&#xff0c;从过去看未来&#xff0c;从现在亦可以改变未来。 今天是 2023 年 7 月 20 日&#xff0c;在 2005 年的今天&#xff0c;时任微软全球副总裁的李开复加盟谷歌担任谷歌全球副总裁及中国区总裁。谷歌公司在发布聘请李开复消息的同…

ffplay播放器剖析(5)----视频输出剖析

文章目录 1.视频输出模块1.1 视频输出初始化1.1.1 视频输出初始化主要流程1.1.2 calculate_display_rect初始化显示窗口大小 1.2 视频输出逻辑1.2.1 event_loop开始处理SDL事件1.2.2 video_refresh1.2.2.1 计算上一帧显示时长,判断是否还要继续上一帧1.2.2.2 估算当前帧显示时长…