仿写SpringMVC

news2024/9/27 9:28:30

1.创建简单的注解

1.1 Controller

package com.heaboy.annotation;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @ interface Controller {
}

1.2 RequestMapping

package com.heaboy.annotation;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface RequestMapping {
    String value() default "";
}

2.创建controller类

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 "";
    }
}
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");
    }
}

3.SpingMVC实现类

package com.heaboy.mvc;

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

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.channels.ClosedSelectorException;
import java.sql.SQLOutput;
import java.util.*;
import java.util.regex.Matcher;

public class HeaboyMvc {
    private static HashMap<String, Map<String,Method>> map=new HashMap<>();
    private static HashMap<String,Object> objMap=new HashMap<>();
    public static void scanner(String path,String packageName)  {
        //扫描main所在包中的类以及子包中的类的绝对路径
        List<String> paths=traverseFolder2(path);
        for (String p : paths) {
            p=p.substring(path.length()-1);
            //遍历每一个类文件的绝对路径,并且处理只剩下对main的相对路径
            try {
                String className=packageName+"."+p.replaceAll(Matcher.quoteReplacement(File.separator),".");
                //包名加相对路径,把相对路径的/换成.
                String replace=className.replace(".class","");
                //去掉.class后缀
                Class<?> cl=Class.forName(replace);
                //获取改类的class对象
                if (isController(cl)){
                    //是否有controller注解
                    if (isRequestMapping(cl)){
                        //是否有requestMapping注解
                        RequestMapping requestMapping=getRequestMapping(cl);
                        //获取requestmapping注解
                        if (map.containsKey(requestMapping.value())){
                            throw new RuntimeException("类多注解值:"+requestMapping.value());
                            //跟之前扫描的名字冲突报错
                        }else {
                            map.put(requestMapping.value(),new HashMap<>());
                            //类的requestMapping注解值和map字典放入字典中
                            objMap.put(requestMapping.value(),cl.newInstance());
                            //类的注解值和类对象放入字典中
                        }
                        Method[] declaredMethods=cl.getDeclaredMethods();
                        //获取该对象的每一个方法对象
                        for (Method declaredMethod : declaredMethods) {
                            //遍历方法对象
                            if (isRequestMapping(declaredMethod)){
                                //判断该方法是否有requesting注解
                                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);
                                    //没有就添加map对应类的方法字典中
                                }
                            }
                        }
                    }else {
                        throw new RuntimeException("类无requestMapping");
                    }
                }

            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    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){
                //判断该类中是否有该方法
                System.out.println("没有这个方法 404");
            }else {
                try {
                    //获取该类的该方法并且执行
                    map.get(classPath).get(methodPath).invoke(objMap.get(classPath));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    private static List<String> traverseFolder2(String path){
        //创建main所在文件夹对象
        File file=new File(path);
        ArrayList<String> classPaths=new ArrayList<>();
        //创建数组,存放类路径
        if (file.exists()){
            //文件夹存在执行
            LinkedList<File> list=new LinkedList<>();
            //存放子文件夹路径以及子子文件夹数量
            File[] files=file.listFiles();
            //把main所在文件夹下的子文件夹和文件放入数组
            for (File file1 : files) {
                //遍历
                if (file1.isDirectory()){
                    //判断是不是文件夹
                    list.add(file1);
                    //是放入子文件夹集合
                }else {
                    classPaths.add(file1.getAbsolutePath());
                    //文件则放入文件集合
                }
            }
            while (!list.isEmpty()){
                //子文件夹集合不为空,一直遍历,直到空为止
                File directory=list.removeFirst();
                //弹出第一个子文件夹对象
                File[] files1=directory.listFiles();
                for (File file1 : files1) {
                    if (file1.isDirectory()){
                        list.add(file1);
                        //判断是否为文件夹,是则放入集合
                    }else {
                        classPaths.add(file1.getAbsolutePath());
                        //文件则放入类集合
                    }
                }
            }
        }
        return classPaths;
    }
    private static boolean isController(Class cl){
        Annotation annotation=cl.getAnnotation(Controller.class);
        if (annotation!=null){
            return true;
        }
        return false;
    }
    private static boolean isRequestMapping(Class cl){
        Annotation annotation=cl.getAnnotation(RequestMapping.class);
        if (annotation!=null){
            return true;
        }
        return false;
    }
    private static boolean isRequestMapping(Method method){
        Annotation annotation=method.getAnnotation(RequestMapping.class);
        if (annotation!=null){
            return true;
        }
        return false;
    }
    private static RequestMapping getRequestMapping(Class cl){
        Annotation annotation=cl.getAnnotation(RequestMapping.class);
        if (annotation instanceof RequestMapping){
            return (RequestMapping) annotation;
        }
        return null;
    }
    private static RequestMapping getRequestMapping(Method method){
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }
}

4.启动类

package com.heaboy;

import com.heaboy.mvc.HeaboyMvc;

import java.util.Stack;

public class Main {
    static {
        String path=Main.class.getResource("").getPath();
        //获取main方法的路径
        String packageName=Main.class.getPackage().getName();
        //获取main方法所在包的路径
        HeaboyMvc.scanner(path,packageName);
        //扫描main所在包中的类以及子包中的类
    }

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

5.结果展示

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

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

相关文章

喜讯|华院钢铁行业大模型入选“2024全国企业新质生产力赋能典型案例”

7月2日&#xff0c;由中国科学院主管、科学出版社主办的商业周刊《互联网周刊》&#xff08;CIW&#xff09;联合德本咨询&#xff08;DBC&#xff09;、中国社会科学院信息化研究中心&#xff08;CIS&#xff09;发布了“2024全国企业新质生产力赋能典型案例”。华院计算技术&…

基于FPGA的千兆以太网设计(1)----大白话解释什么是以太网

1、什么是以太网? 还记得初学以太网的时候,我就被一大堆专业名词给整懵了:什么以太网,互联网,MAC,IP,局域网,万维网,网络分层模型等等等等。慢着!我学的不是以太网吗?怎么出来这么一大堆东西? 啊!以太网究竟是什么?别急,我接下来就尽量用通俗的大白话来给你解释…

香港优才计划多少分获批成功率高?一文看懂各分数段获批情况!

有留意香港优才计划的朋友&#xff0c;应该都了解过&#xff0c;申请优才计划采用打分制&#xff0c;得分多少与最终获批有密不可分的关系。但有一点要提前清楚&#xff0c;申请优才不是得分越高就一定能获批&#xff0c;也不是得分低就一定没希望。 香港优才计划能否获批成功…

将直流电转换为交流电:逆变器的基本原理

什么是逆变器&#xff1f; 大多数电源设计都包括一个称为整流器的部分&#xff0c;该整流器将输入的交流波转换为不稳定的直流电压。但是&#xff0c;我们不能总是依赖来自建筑物主电源的交流输入到我们的系统中。 逆变器是一种将直流电 &#xff08;DC&#xff09; 转换为交…

前端javascript中的排序算法之冒泡排序

冒泡排序&#xff08;Bubble Sort&#xff09;基本思想&#xff1a; 经过多次迭代&#xff0c;通过相邻元素之间的比较与交换&#xff0c;使值较小的元素逐步从后面移到前面&#xff0c;值较大的元素从前面移到后面。 大数据往上冒泡&#xff0c;小数据往下沉&#xff0c;也就是…

Docker-安装MongoDB、RabbitMQ、ActiveMQ、Portainer(保姆篇图示详解)

文章目录 MongoDB 安装RabbitMQ 安装ActiveMQ 安装Portainer 安装 更多相关内容可查看 MongoDB 安装 1.拉取镜像&#xff08;默认为最新版本&#xff0c;也可指定版本&#xff09; docker pull mongo:版本号2.根据镜像 运行容器实例 &#xff08;暴露端口 数据挂载 用户密码设…

【NLP】利用 RAG 模分块技术提升文档处理效能

将大型文档划分为较小的部分是一项至关重要但又复杂的任务&#xff0c;它对检索增强生成 (RAG) 系统的性能有重大影响。这些系统旨在通过结合基于检索和基于生成的方法&#xff0c;提高输出的质量和相关性。有效的分块&#xff0c;即将文档拆分为可管理的片段的过程&#xff0c…

百度Feed业务数仓建模实践

作者 | XY 导读 Feed&#xff0c;即个性化推荐信息流&#xff0c;是百度 App 上承载各种类型内容&#xff08;如文章、视频、图集等&#xff09;的重要 topic。本文概要讲述了随着业务发展&#xff0c;移动生态数据研发部在 Feed 数据宽表建模上的演进过程以及一些实践&#xf…

LeetCode67(二进制求和[位运算,大数运算])

二进制求和 题目要求: 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 这道题其实有几种解法.我们先来介绍简单的方法. 我们可以将两个字符串的二进制转成十进制,获取对应值相加之后,我们可以不断对2取余,获取尾数拼接即可.也就是像我们平常求一…

记一次线上流量突增问题排查

一.问题 接流量告警出现获取 xx 信息接口调用次数同比往年大促活动猛涨.扩大至 10 倍之多.心里顿时咯噔一下.最近各种严打,顶风作案.某不是摸到电门了.一下子要把自己带走.从此走向求职之路.一时间脑子哇哇的思绪万千. 202x.5.20 大促开门红的调用.这个是往年活动的时候的调用…

01-引论-操作系统的目标和作用

操作系统的目标 1.方便性 2.有效性 3.可扩充性 4.开放性 操作系统的目标与应用环境有关 在不同的应用环境下&#xff0c;操作系统的重点和功能可能会有所不同。例如&#xff0c;对于桌面操作系统&#xff0c;用户界面的友好性和多媒体功能可能是重点&#xff1b;对于服务…

Qt/C++项目积累: 2.主机监控器 - 2.1 项目介绍

修改记录 序号日期说明对应软件版本号120240709对预期功能和已完成功能进行新增无 一&#xff1a;项目主体编写背景 在观察程序的运行状态时&#xff0c;其对系统的CPU&#xff0c;内存&#xff0c;硬盘占用无疑是几项重要参考指标&#xff0c;而现有的监控软件&#xff0c;搜…

2024-07-08 base SAS programming学习笔记10(read data)

1.读入SAS 数据集 格式如下&#xff1a; data sas-data-set; set sas-data-set; run; sas-data-set 是数据集名称&#xff0c;可以是libname.filename的形式 举例如下&#xff1a; 2.在DATA步使用BY 语句 BY variable语句使用方法&#xff1a; a.必须在PROC SORT里面进行排序…

国产芯片四大流派,你最看好哪一条?

曾经&#xff0c;我们以为“地球村”是大势所趋&#xff0c;大家取长补短&#xff0c;合作共赢。 然而&#xff0c;2018年开始的那一场断供&#xff0c;让芯片自主从一个产业的隐忧变成了我国的一个“明伤”。近几年“卡脖子”事件屡屡上演&#xff0c;“缺芯”、“芯痛”成为…

Redis连接Resp图形化工具和springboot

Redis连接Resp图形化工具和springboot 1.redis配置1.1 备份、修改conf文件1.2 Redis的其它常见配置&#xff1a;1.3 启动Redis&#xff1a;1.4 停止服务&#xff1a;1.5 开机自启&#xff1a; 2. resp的安装、配置和连接&#xff1a;2.1 GitHub上下载2.2 开始连接redis ![在这里…

【Dison夏令营 Day 13】使用 Python 创建扫雷游戏

在本文中&#xff0c;我们将介绍如何使用 Python 语言创建自己的基于终端的扫雷程序。 关于游戏 1992年4月6日&#xff0c;扫雷和纸牌、空当接龙等小游戏搭载在Windows 3.1系统中与用户见面&#xff0c;主要目的是让用户训练使用鼠标。扫雷是一款单人游戏&#xff0c;这个游戏…

单例模式(大话设计模式)C/C++版本

单例模式 C 饿汉 /* HM hungry man 饿汉 */ #include <iostream> using namespace std; class Singleton { private:Singleton() { cout << "单例对象创建&#xff01;" << endl; };Singleton(const Singleton &);Singleton &operator(c…

app: 和 android:的区别

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

如何切换手机的ip地址

在数字时代的浪潮中&#xff0c;智能手机已成为我们日常生活中不可或缺的一部分。然而&#xff0c;随着网络安全问题的日益凸显&#xff0c;保护个人隐私和数据安全变得尤为重要。其中&#xff0c;IP地址作为网络身份的重要标识&#xff0c;其安全性与隐私性备受关注。本文将详…

百度旋转验证码

声明(lianxi a15018601872) 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 前言(lianxi a…