MVC框架封装笔记contextListener(12.29)

1.在web项目配置全局监听器,监听器写在框架下

  <!-- 配置全局监听器 -->
  <listener>
    <listener-class>com.qfedu.mvc.framwork.listener.ContextListener</listener-class>
  </listener>

2.框架启动首先找到AppConfig在哪里

反射
Class clazz = getConfigClazz(sce);
 /**
     * 找到config类的clazz对象
     * @param sce
     */
    private Class getConfigClazz(ServletContextEvent sce) {
        //:读取全局的配置文件
        ServletContext servletContext = sce.getServletContext();
        String config = servletContext.getInitParameter("config");
        if (StringUtils.isEmpty(config)){
            //说明为配置config这个类
            throw new MvcException("未配置Config类");
        }
        //配置了Config类读取出来,转化成class对象
        Class<?> configClazz=null;
        try {
            configClazz = Class.forName(config);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new MvcException("Config类的路径有误无法实施反射");
        }
        return configClazz;
    }

3.找到AppConfig之后找注解的地址

//说明有对象
String value = getComponentScanPath(clazz);
 private String getComponentScanPath(Class clazz) {
        ComponentScan componentScan = (ComponentScan) clazz.getAnnotation(ComponentScan.class);
        if(null==componentScan){
            //说明为配置注解
            throw new MvcException("未配置ComponentScan这个注解...");
        }
        //程序执行到这里,说明配置了注解
        //取出控制器的扫描路径
        String value = componentScan.value();
        if(StringUtils.isEmpty(value)){
            //说明未配置这个扫描路径
            throw  new MvcException("未配置这个控制器的扫描路径");
        }
        return value;
    }

package com.qfedu.aunt.commons.config;

import com.qfedu.mvc.framwork.annotation.ComponentScan;

@ComponentScan("com.qfedu.aunt.commons.controller")//告诉程序需要找到的控制器的路径
public class AppConfig {

}

4.找到项目控制器controller的绝对路径的地址(项目部署绝对路径)

 //获取到文件绝对路径:不是代码路径,而是项目部署路径
 String absolutePath = getAbsolutePath(sce,value);
 /**
     * 获取部署的绝对路径
     * @param sce
     * @param value
     * @return
     */
    private String getAbsolutePath(ServletContextEvent sce,String value){
        String realPath = sce.getServletContext().getRealPath("/");
        value = value.replace(".","\\");
        realPath=realPath+"WEB-INF\\classes\\"+value;
        System.out.println("项目部署的根路径是:"+realPath);
        return realPath;
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o5fLYW7h-1672318285598)(新建文本文档 (2)].assets/1672314828485.png)

5.继续找到Controller控制器下面的所有文件

 //找到这个绝对路径下的所有文件
 getFileByPath(absolutePath);
//递归方法找到所有的非文件夹文件
private void getFileByPath(String absolutePath) {
        File file = new File(absolutePath);
        File[] files = file.listFiles();
        for (File f:files){
            if(f.isFile()){
                listFile.add(f);
            }else {
                getFileByPath(f.getAbsolutePath());
            }
        }
    }

6.再找到所有的.class文件

//找到所有的class文件
List<File> classFile = getClassFileByListFile(listFile);
/**
     * 通过所有遍历出来的文件,找到所有的class文件
     * @param listFile
     * @return
     */
    private List<File> getClassFileByListFile(List<File> listFile) {
        List<File> classFile = new ArrayList<File>();
        //遍历找到的每一个文件
        for (File f:listFile) {
            //获取这个文件的绝对路径
            String fileName = f.getName();
            //判断这个文件名的结尾是不是 .class
            if(fileName.endsWith(".class")){
                classFile.add(f);
            }
        }
        return classFile;
    }

7.将所有的.class文件转换为class对象

为了找到controller注解
 List<Class> clazzList = getClassFromClassFile(classFile,sce);
 /**
     * 通过class文件找到class所对应的clazz对象
     * @param classFile
     * @return
     */
    private List<Class> getClassFromClassFile(List<File> classFile,ServletContextEvent sce) throws ClassNotFoundException {
        List<Class> classList = new ArrayList<Class>();
        //遍历文件,找到每一个class文件的包
        for (File f:classFile) {
            //找到文件的绝对路径
            String absolutePath = f.getAbsolutePath();
            //这个绝对路径要和谐掉前面的部署路径
            //所有要去点部署路径
            String realPath = sce.getServletContext().getRealPath("/");
            //处理路径问题
            realPath=realPath+"WEB-INF\\classes\\";
            //在整个路径中要去掉这个部署的路径
            //最终路径
            String replace = absolutePath.replace(realPath, "");
            //接下来去掉.class
            replace = replace.substring(0,replace.lastIndexOf(".class"));
            //将路径中的/换成我们的 .
            String classPath = replace.replace("\\",".");
            //ClassPath的路径直接反射获取class对象
            Class<?> clazz = Class.forName(classPath);
            classList.add(clazz);
        }

        return classList;
    }

8.转换为class对象之后需要处理类映射关系

 //处理映射关系
 handlerrequestMapping(clazzList);
/**
     * 处理映射关系
     * @param clazzList
     */
    private void handlerrequestMapping(List<Class> clazzList) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        //需要遍历类是否拥有Controller注解
        for (Class clazz:clazzList){
            Annotation annotation = clazz.getAnnotation(Controller.class);
            if(annotation==null){
                //说明是个普通类不需要解析
                continue;
            }
            //类需要解析
            //看类是否拥有@RequestMapping注解
            RequestMapping requestMapping = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
            String reqPathAll = null;
            if(requestMapping!=null){
                //配置了注解
                reqPathAll = requestMapping.value();
            }
            //找到类中的所有方法,判断这个方法是否拥有RequestMapping注解
            Method[] declaredMethods = clazz.getDeclaredMethods();
            //封装类的描述对象
            Beandefinition beandefinition = new Beandefinition();
            //设置类名
            beandefinition.setTypeName(clazz.getName());
            //类对象是谁
            beandefinition.setObj(clazz.newInstance());
            //类上的路径
            beandefinition.setRegPath(reqPathAll);
            if(requestMapping!=null){
                beandefinition.setRequestMappingOrNot(true);
            }

            handlerMethodrequestMapping(reqPathAll,declaredMethods,beandefinition);
        }
    }
处理类方法的映射关系
/**
     * 处理这个方法的映射关系
     * @param reqPathAll
     * @param declaredMethods
     */
    private void handlerMethodrequestMapping(String reqPathAll,
                                             Method[] declaredMethods,
                                             Beandefinition beandefinition1) throws InvocationTargetException, IllegalAccessException {
        //遍历这个类中的所有方法,找到这个方法是否拥有@RequestMapping这个注解
        for (Method m:declaredMethods){
            //TODO 进行深拷贝
            Beandefinition beandefinition = new Beandefinition();
            //做一个属性的拷贝
            BeanUtils.copyProperties(beandefinition,beandefinition1);
            //判断方法上是否拥有requestMapping注解
            RequestMapping requestMapping = m.getAnnotation(RequestMapping.class);
            if(requestMapping==null){
                continue;
            }
            //执行说明拥有RequestMapping注解
            String reqPath = requestMapping.value();
            //类上的RequestMapping注解可以没有值,方法必须有,否则就报错
            if(StringUtils.isEmpty(reqPath)){
                throw new MvcException("方法上的RequestMapping必须有值,不能默认...");
            }
            //执行这里说明有值,组装最终的请求地址
            String path = (reqPathAll+reqPath).trim();
            //描述方法
            BeanMethodDefinition beanMethodDefinition=new BeanMethodDefinition();
            beanMethodDefinition.setMethod(m);
            //设置方法参数的个数
            beanMethodDefinition.setParameterCount(m.getParameterCount());
            //方法上的请求路径
            beanMethodDefinition.setReqPath(reqPath);
            //将方法的描述放到类的描述中去
            beandefinition.setBeanMethodDefinition(beanMethodDefinition);
            //解决方法中参数的映射问题
            //引用传递
            handlerMethodParameterMapping(beanMethodDefinition,m);
            //最终就可以把描述信息放到容器中去了
            //找到容器
            ConcurrentHashMap<String, Beandefinition> container = RquestMappingContainer.getContainer();
            //向容器中写入数据
            container.put(path,beandefinition);
        }
    }
处理参数的映射关系
 /**
     * 处理参数的映射关系
     * @param beanMethodDefinition
     * @param m
     */
    private void handlerMethodParameterMapping(BeanMethodDefinition beanMethodDefinition, Method m) {
        List<BeanParameterDefinition> beanParameterDefinitions = new ArrayList<>();
        Parameter[] parameters = m.getParameters();
        for (Parameter p:parameters) {
            BeanParameterDefinition beanParameterDefinition = new BeanParameterDefinition();
            beanParameterDefinition.setName(p.getName());
            beanParameterDefinition.setType(p.getType().getName());
            beanParameterDefinitions.add(beanParameterDefinition);
        }
        beanMethodDefinition.setBeanParameterDefinitions(beanParameterDefinitions);

    }

;
beanParameterDefinition.setName(p.getName());
beanParameterDefinition.setType(p.getType().getName());
beanParameterDefinitions.add(beanParameterDefinition);
}
beanMethodDefinition.setBeanParameterDefinitions(beanParameterDefinitions);

}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值