手搓spring迷你框架之旅-03 Controller实现

手搓spring迷你框架之旅-03 Controller实现

本篇将会实现@Controller注解,以及简单的控制器使用

核心流程

整理一下流程

  • 首先BeanFactory扫描包的时候 不仅要扫描带Component注解的类 也扫描带有Controller注解的类 并放入BeanMap当中

  • 然后进行一系列处理包括扫描带@RequestMapping的注解的方法 这里出现了方法类注解

创建注解

创建两个自定义注解 一个是@Controller注解 一个是@RequestMapping注解

//@RequestMapping注解
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface RequestMapping {
    String value() default "";
//value的值为路径
}
//Controller注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}

第一个注解 需要在Type和Method上都可以用

接着 修改并添加BeanFactory相关代码

新增注册控制器方法以及路径调用方法

private void registerController() throws InstantiationException, IllegalAccessException {
        for (Object bean:beansMap.values()){
            Class<?> clazz = bean.getClass();
            if (clazz.isAnnotationPresent(Controller.class)){
                String basePath="";
                if (clazz.isAnnotationPresent(RequestMapping.class)){
                    RequestMapping requestMapping=clazz.getAnnotation(RequestMapping.class);
                    basePath=requestMapping.value();
                }
                for (Method method:clazz.getDeclaredMethods()){
                    if (method.isAnnotationPresent(RequestMapping.class)){
                        RequestMapping methodsMapping=method.getAnnotation(RequestMapping.class);
                        String fullPath=basePath+methodsMapping.value();
                        requestMappingMethods.put(fullPath, method);
                        System.out.println("Mapped path: " + fullPath + " -> " + method.getName());
                    }
                }

            }
        }

    }
//路径调用
public Object handleRequest(String path){
        //根据fullPath获得方法
        Method method=requestMappingMethods.get(path);
        if (method!=null){
            try {
                Object Controller=beansMap.get(method.getDeclaringClass().getSimpleName());
                return method.invoke(Controller);
            }catch (Exception e){
                System.out.println("出现错误");
            }
        }
        return "404 not found";
    }
}

解释:

registerController()

  • 扫描beanMap当中的对象 将带有@Controller注解的类取出

  • 扫描 将类中带有@RequestMapping注解的方法取出 并且让获得这个注解当中value的值 作为基础路径(默认为空)

  • 对于其中每一个methods 取出methods上面注解的值 与基础路径拼接获得fullPath,并将key为fullpath value为method的键值对放入定义好的RequestMappingMethods的map属性当中去

  • 由此 我们就可以获得一个里面放有路径对应方法的map集合

  • handleRequest(String path)

handleRequest(String path)

  • 根据fullPath参数 获得刚刚存放在map当中的方法实例

  • 然后根据方法所在的类的名 去beanMap当中取Controller实例对象 然后用invoke反射调用这个方法

综上 我们就实现了简单的根据Controller注解与@RequestMapping注解去调用相应的路径下的方法 只需要配置path即可

当然 目前是简单的实现 真正的路径请求会带有参数 传入的参数也会带有json等数据格式 下一步优化就是将参数处理 放在下一篇

对刚刚写的代码进行测试

public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        BeanFactory beanFactory=new BeanFactory("com.dms.shanshan");
       beanFactory.handleRequest("/user/method1");
    }
}
//controller类
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/method1")
   public void userMethod1(){
       System.out.println("userMethod1");
   }
}

测试输出

可以看到 我们成功的根据路径调用路径下的userMethod1方法 实现了简单控制器的基本功能

后记

仓库地址(不断更新):

https://gitee.com/du-mingshen1/hand-rubbing-spring-framework

全系列:杜明珅的手搓spring迷你框架系列

上一篇:手搓spring迷你框架之旅-02 依赖注入的实现

下一篇:手搓spring迷你框架之旅-04 Controller请求参数的实现