代码地址(需要自取):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 {
@RequestMapping
public 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 {
@RequestMapping
public 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 {
// 存放 一级注解-二级注解-方法 的map
private static HashMap<String,HashMap<String, Method>> map_method = new HashMap<>();
// 存放 一级注解-类的实例化对象 的map
private 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.class
path1=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_method
map_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_list
file_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中获取调用。具体详细的解释可以查看代码及其注释。