文章目录
- 前提:
- 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、初始化步骤是:
- 定义3个静态集合,arr装遍历到的所有java文件的全类名、controllerMap装controller的url与controller的映射结构、map装每个controller的url与每个controller里每个方法的url与方法的map的映射结构
- 通过给getFilePath(File file)方法传入源代码根目录,对项目中所有以.java结尾的java文件进行搜索,对每个java文件的路径进行字符串处理,得到文件的全限定名(包名+类名),然后将全限定名装入list中,用于反射(Class.forName(String className))。
例如:
- 对每个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、执行
- 传入的两个字符串参数,一个controller的url:classPath,一个方法的url:methodPath
- 先判断controllerMap中是否包含classPath这个key,如果不包含则认为没有这个类;如果包含,再判断map的classPath对用的value里是否包含methodPath,如果不包含,则认为这个类里没有这个方法;如果包含,则通过反射执行该方法(method.invoke(Object obj, Object… args))