看完这篇文章,你也能手写MVC

项目结构

Main类

public class Main {
    //类一加载就执行这个静态块
    static {
        //当前类所在目录
        String path = Main.class.getResource("").getPath();
        //当前类所在包名
        String packageName = Main.class.getPackage().getName();
        Mvc.scanner(path,packageName);
    }

    public static void main(String[] args) {
        Mvc.exec("","");
        Mvc.exec("test","index1");
        Mvc.exec("test","");
        System.out.println("Hello World!");
    }
}

我们执行程序从这个类开始,类加载的时候,先执行静态块(扫描所有的文件,把类文件的实例和类文件的方法 用HashMap存起来)

main方法中的exec是模拟调用接口,第一个参数是类的@RequestMapping的value值,第二个参数是方法的@ReqeustMapping的value值

MVC

package com.test.mvc;

import com.test.annotation.Controller;
import com.test.annotation.RequestMapping;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;

/**
 * @author sangyinghao
 * mvc类
 */
public class Mvc {
    //存类的方法
    private static HashMap<String, Map<String,Method>> map=new HashMap<>();
    //存类的实例
    private static HashMap<String, Object> objMap=new HashMap<>();
    public static void exec(String classPath,String methodPath){
        if(objMap.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(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<?> cl = ClassLoader.getSystemClassLoader().loadClass(replace);
                //判断是Controller吗
                if(isController(cl)){
                    //判断是否加RequestMapping
                    if(isRequestMapping(cl)){
                        //拿到注解
                        RequestMapping requestMapping = getRequestMapping(cl);
                        //判断注解中的值是否有重复
                        if(map.containsKey(requestMapping.value())){
                            throw  new RuntimeException("类多注解值:"+requestMapping.value());
                        }else {
                            //没有重复就把类放两个map进去
                            map.put(requestMapping.value(),new HashMap<>());
                            objMap.put(requestMapping.value(),cl.newInstance());
                        }
                        //拿到类中的方法
                        Method[] declaredMethods = cl.getDeclaredMethods();
                        //遍历类中的方法
                        for (Method declaredMethod : declaredMethods) {
                            if(isRequestMapping(declaredMethod)){
                                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();
            }
        }


    }

    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;
    }
    private static List<String> traverseFolder2(String path) {
        //路径转为文件
        File file = new File(path);

        List<String> classFiles=new ArrayList<>();
        if (file.exists()) {
            //新建list用来存放文件夹
            LinkedList<File> list = new LinkedList<File>();
            File[] files = file.listFiles();
            //遍历
            for (File file2 : files) {
                //只要是文件夹就添加进list
                if (file2.isDirectory()) {
                    list.add(file2);
                } else {
                    //不是文件夹就放到clssFiles中
                    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 {

        }
        //获得了所有的文件的路径
        return classFiles;
    }
}

 大致思想:

  • 先扫包,如果是文件夹就放到list中,如果不是文件夹就是文件就放到classFiles中,判断list是否为空,如果不为空就把存进的文件夹的文件展示出来继续遍历,同时把此文件夹从list中取出,经过几次之后,就可以获得所有得到类文件的路径  
  • 遍历classFiles,拿到包名,对遍历出的类文件的路径进行替换和截取,获得了类的全限定名,判断加没加@Controller注解,再判断加没加@RequestMapping注解,判断@RequeatMapping注解中的value是否重复,如果不重复就把此value存起来,并对此类中的方法进行遍历,如果方法加了@RequestMapping,就用map把方法的value也存起来
    //存类的方法
    //第一个String是类的@RequestMapping中的value值,第二个String是方法的@RequestMapping中的value值
    private static HashMap<String, Map<String,Method>> map=new HashMap<>();
        
    //存类的实例
    private static HashMap<String, Object> objMap=new HashMap<>();

注解

Controller注解

/**
 * test 的controller声明
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @ interface Controller {
}

 RequestMapping注解

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

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

  

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值