本篇将会实现@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方法 实现了简单控制器的基本功能
后记
仓库地址(不断更新):
全系列:杜明珅的手搓spring迷你框架系列