代码地址(需要自取):mvc_Imitation: 简单仿写实现MVC (gitee.com)
项目目录
先把架子搭好
Controller注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @ interface Controller {
}
RequestMapping
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface RequestMapping {/**** @return*/String value() default "";
}
HydController
@Controller
@RequestMapping("hyd")
public class HydController {@RequestMappingpublic String index(){System.out.println("RequestMapping为“hyd, ”的方法已执行");return "";}@RequestMapping("hyd2")public String index1(){System.out.println("RequestMapping为“hyd,hyd2”的方法已执行");return "";}
}
indexController
@Controller
@RequestMapping
public class IndexController {@RequestMappingpublic void index() {System.out.println("RequestMapping为“ , ”的方法已执行");}
}
Main
public class Main {static {
// 获取Main的路径String path = Main.class.getResource("").getPath();
// 获取Main的包名String packageName = Main.class.getPackage().getName();HydMVC.scanner(path, packageName);}public static void main(String[] args) {HydMVC.mehtod_go("","");HydMVC.mehtod_go("hyd","");HydMVC.mehtod_go("hyd","hyd2");HydMVC.mehtod_go("232323","23131");HydMVC.mehtod_go("hyd","23131");}}
HydMVC
public class HydMVC {
// 存放 一级注解-二级注解-方法 的mapprivate static HashMap<String,HashMap<String, Method>> map_method = new HashMap<>();
// 存放 一级注解-类的实例化对象 的mapprivate static HashMap<String, Object> map_object = new HashMap<>();/*** 方法执行函数* @param first_path 第一路径* @param second_path 第二路径*/public static void mehtod_go(String first_path,String second_path){
// 如果map_object中没有fisrt_path,则不存在该注解的类if (map_object.get(first_path)==null){System.out.println("没有一个类有"+first_path+"注解");}else {if (map_method.get(first_path).get(second_path)==null){System.out.println(first_path+"下没有"+second_path+"注解"+"的方法");}else{try {map_method.get(first_path).get(second_path).invoke(map_object.get(first_path));} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}}/*** 扫描获取类实例化对象以及方法* @param path* @param packageName 包名*/public static void scanner(String path,String packageName){
// 扫描当前所有的文件List<String> paths = traverseFolder2(path);
// 遍历拿到的文件路径for (String path1 : paths) {
// path1为:C:\ttt\imitating_spring_mvc\out\production\imitating_spring_mvc\com\heaboy\IndexController.class
// 先拿到文件名 例:IndexController.classpath1=path1.substring(path.length()-1);try{// 构建类名
// 因为可能存在多级路径,例如:www/IndexController.class,所以还需要进行一些小处理,不能直接拼接
// File.separator代表文件分隔符
// Matcher.quoteReplacement确保了文件分隔符在替换过程中被正确地转义,以防包含任何正则表达式的特殊字符。它返回一个适合用于正则表达式替换的字符串。String ClassName = packageName + "." + path1.replaceAll(Matcher.quoteReplacement(File.separator),".");
// 去掉文件名中的.class后缀String load_className = ClassName.replace(".class","");
// 通过类加载器加载类Class<?> cl = ClassLoader.getSystemClassLoader().loadClass(load_className);
// 用写好的检查注解方法(isController)判断cl是否有Controller注解if(isController(cl)){
// 用写好的检查注解方法(isRequestMapping)判断cl是否有RequestMapping注解if (isRequestMapping(cl)){
// 如果有就获取类上RequestMapping注解的实例RequestMapping requestMapping_first = getRequestMapping(cl);
// 判断map_method中是否已经存在了该一级注解if (map_method.containsKey(requestMapping_first.value())){
// 已经存在该一级注解,则抛出异常throw new RuntimeException("包含多个注解:"+requestMapping_first.value());}else {
// 不存在,添加至map_method中map_method.put(requestMapping_first.value(),new HashMap<>());
// 添加类的实例化对象到map_object.put(requestMapping_first.value(),cl.newInstance());}
// 获取类中所有的方法Method[] declareMethods = cl.getDeclaredMethods();
// 遍历所有方法for (Method method : declareMethods) {if (isRequestMapping(method)){RequestMapping requestMapping_second = getRequestMapping(method);
// 判断该二级注解是否已经存在if (map_method.get(requestMapping_first.value()).containsKey(requestMapping_second.value())){
// 存在抛出错误throw new RuntimeException("方法注解已经存在:"+requestMapping_second.value());}else {
// 不存在就将方法放入map_methodmap_method.get(requestMapping_first.value()).put(requestMapping_second.value(),method);}}}}else{throw new RuntimeException("该类有没RequestMapping注解");}}}catch (Exception e){System.out.println(e);}}}/*** 扫描文件* @param path 绝对路径* @return List<String> 文件绝对路径集合* C:\ttt\imitating_spring_mvc\out\production\imitating_spring_mvc\com\heaboy\IndexController.class*/private static List<String> traverseFolder2(String path) {
// 当前路径下的文件和文件夹File file = new File(path);
// 返回的文件集合List<String> file_list = new ArrayList<>();if (file.exists()){
// 放文件夹LinkedList<File> list = new LinkedList<>();// 存储过程中要处理的文件File[] files = file.listFiles();for (File file1 : files) {
// 如果当前文件是文件夹就把它放到list里面if (file1.isDirectory()){list.add(file1);}else { //不是就将该文件的绝对路径放到返回列表中file_listfile_list.add(file1.getAbsolutePath());}}
// 申请一个临时变量File file_temp;
// 当存放文件夹的队列不为空时,执行以下操作while (!list.isEmpty()){
// 取出第一个文件夹来处理file_temp=list.removeFirst();
// 使用上面申请的FIle[]来存放file_temp中的文件files=file_temp.listFiles();
// 处理files中的文件,同上,文件夹放到list中,文件放到file_list中for (File file1 : files) {if (file1.isDirectory()){list.add(file1);}else {file_list.add(file1.getAbsolutePath());}}}}else{
// 如果没有任何文件,则不做处理}return file_list;}// 判断类是否有Controller注解private static boolean isController(Class cl){Annotation annotation = cl.getAnnotation(Controller.class);if(annotation!=null){return true;}return false;}// 判断类是否有RequestMapping注解private static boolean isRequestMapping(Class cl){Annotation annotation = cl.getAnnotation(RequestMapping.class);if(annotation!=null){return true;}return false;}
// 获取类的RequestMapping注解的实例private static RequestMapping getRequestMapping(Class<?> cl) {Annotation annotation = cl.getAnnotation(RequestMapping.class);if (annotation instanceof RequestMapping){return (RequestMapping) annotation;}return null;}// 判断方法是否有RequestMapping注解private static boolean isRequestMapping(Method method) {Annotation annotation = method.getAnnotation(RequestMapping.class);if (annotation!=null){return true;}return false;}
// 获取方法上的RequestMapping注解的实例private static RequestMapping getRequestMapping(Method method) {Annotation annotation = method.getAnnotation(RequestMapping.class);if (annotation instanceof RequestMapping){return (RequestMapping) annotation;}return null;}}
整体思路流程,先对路径下的文件进行扫描,拿到.class后缀的文件,然后根据不同的注解进行不同的操作,将实例化对象和方法都存到map中,再从map中获取调用。具体详细的解释可以查看代码及其注释。