手写简单模拟mvc

时间:2024-07-09 07:11:44

目录结构:

 两个注解类:

@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 {
    @RequestMapping
    public 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 {
    @RequestMapping
    public 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为一个新的HashMap
                            objMap.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) {
            // 如果注解对象不为null
            return true;
            // 返回true,表示类为控制器
        }
        return false;
        // 返回false,表示类不是控制器
    }

    private static boolean isRequestMapping(Class cl) {
        // 定义一个私有的静态方法,用于检查类是否包含RequestMapping注解
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        // 获取类的RequestMapping注解对象
        if (annotation != null) {
            // 如果注解对象不为null
            return true;
            // 返回true,表示类包含RequestMapping注解
        }
        return false;
        // 返回false,表示类不包含RequestMapping注解
    }

    private static boolean isRequestMapping(Method method) {
        // 定义一个私有的静态方法,用于检查方法是否包含RequestMapping注解
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        // 获取方法的RequestMapping注解对象
        if (annotation != null) {
            // 如果注解对象不为null
            return 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");
    }
}