• 一个servlet处理多个请求方法


    实现思路
    1.进行全局扫描:将项目下所标识有注解的方法进行收集和解析(注意:扫描是一个
    非常消耗性能的操作,这种操作应该只需要进行一次
    2.进行类的解析
    目的:找到哪些类中有哪些方法是标识有注解的,那么这些方法就是用于请求处理的方法,
    解析的过程也是同样消耗性能的,思考一下,是否每次请求都要进行一次相同的解析操作

    3.将解析的结果进行缓存
    这一步非常重要,因为解析的结果将直接为后续的请求服务,在整个项目的运行同期是不能销毁的,
    所以我们需要将这些信息缓存再存入到服务器中


    一、自定义注解类
    package org.nf.framework.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 描述:
     *
     * @author lance
     * 自定义注解
     * @Retention –什么时候使用该注解
     * @Target –注解用于什么地方
     *  RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,
     *  因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
     *  ElementType.METHOD:用于描述方法
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface UrlMapping {
        String value();
    }
    
    

    二、扫描工具类,得到项目中所有的包名和类名

    package org.nf.framework.utils;
    
    import java.io.File;
    import java.net.URLDecoder;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * 扫描工具类,用于扫描指定包下面的所有类,包括子包
     * @author lance
     *
     */
    public class ScanUtil {
        /**
         * 存放所有类的类名
         */
        private static List<String> list = new ArrayList<String>();
    
        /**
         * 扫描
         * @param packagePath
         * @return
         */
        public static List<String> scanPackage(String packages) {
            String[] packs = packages.split(",");
            for (String pack : packs) {
                String path = toPackagePath(pack);
                try {
                    toClassPath(path);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return list;
        }
    
        /**
         * 将路径转换成包名
         * @param packagePath
         * @return
         */
        private static String toPackagePath(String packagePath) {
            packagePath = packagePath.replace(".", File.separator);
            return getRealPath()+packagePath;
        }
        /**
         * 遍历目录将类名存入List中
         * @param classPath
         * @throws Exception
         */
        private static void toClassPath(String classPath) throws Exception {
            classPath = URLDecoder.decode(classPath, "utf-8");
            // listFiles()获取路径下的所有文件或文件夹,返回的是一个File[]数组
            File[] fs = new File(classPath).listFiles();
            if (fs != null) {
                for (File file : fs) {
                    // file.isDirectory()方法判断当前额的file对象是否是一个文件夹
                    if (file.isDirectory()) {
                        // 获取文件夹的绝度路径
                        // 递归调用
                        toClassPath(file.getAbsolutePath());
                    } else {
                        // 将文件名转换成完整类名
                        String path = toClassName(file);
                        if (path != null) 
                            list.add(path);
                    }
                }
            }
        }
    
        /**
         *  将文件名转换成完整类名
         * @param file
         * @return
         * @throws Exception
         */
        private static String toClassName(File file) throws Exception {
            if (file.getName().endsWith(".class")) {
                String path = URLDecoder.decode(getRealPath(), "utf-8");
                path = new File(path).getAbsolutePath() + File.separator;
                path = file.getAbsolutePath().substring(path.length(),
                        file.getAbsolutePath().length());
                String className = path.replace(File.separator, ".");
                className = className.substring(0, className.length() - 6);
                return className;
            } else {
                return null;
            }
        }
        
        /**
         * 获取当前项目的classes目录
         * @return
         */
        private static String getRealPath(){
            return ScanUtil.class.getClassLoader().getResource("").getPath();
        }
    }

    三、servlet总控制器(相当于中央处理器,处理所有的servlet请求,核心)

    package org.nf.framework.web;
    
    import org.nf.framework.annotation.UrlMapping;
    import org.nf.framework.utils.ScanUtil;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 描述:
     * 总控制器
     *
     * @author lance
     * @create 2018-08-31 9:48
                    实现思路
        1.进行全局扫描:将项目下所标识有注解的方法进行收集和解析(注意:扫描是一个
        非常消耗性能的操作,这种操作应该只需要进行一次
    )
        2.进行类的解析
            目的:找到哪些类中有哪些方法是标识有注解的,那么这些方法就是用于请求处理的方法,
        解析的过程也是同样消耗性能的,思考一下,是否每次请求都要进行一次相同的解析操作
    
        3.将解析的结果进行缓存
            这一步非常重要,因为解析的结果将直接为后续的请求服务,在整个项目的运行同期是不能销毁的,
        所以我们需要将这些信息缓存再存入到服务器中
     */
    public class DispatcherServlet extends HttpServlet {
    
        private static final Map<String, Method> mapper = new HashMap<>();
        @Override
        public void init(ServletConfig config) throws ServletException {
            //1.全局的扫描(空代表全局,也可以给某个包的值)
            List<String> className = scan("");
            //2.解析类中有注解的方法
            resolve(className);
            System.out.println("DispatcherServlet初始化完成。。。。");
        }
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取请求的url,这个path其实就对应了mapper中的key
            String path = req.getServletPath();
            //根据key取出相应的method并调用处理请求
            //根据相应的key取出相应method,并调用方法
            invokeTargetMethod(req,resp,mapper.get(path));
        }
    
        /**
         * 进行类扫描
         * */
        private List<String> scan(String packageName){
            return  ScanUtil.scanPackage(packageName);
        }
    
        /**
         * 解析类中的注解方法
         * */
        private void resolve(List<String> className){
            for (String s : className) {
                try {
                    //进行类加载
                    Class<?> clazz= Class.forName(s);
                    //获得类中的所有的方法
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        if(method.isAnnotationPresent(UrlMapping.class)){
                            //获得所有注解方法的上value值,也就是请求url的值
                            String url = method.getAnnotation(UrlMapping.class).value();
                            //缓存到map集合中
                            mapper.put(url,method);
                        }
                    }
    
                } catch (ClassNotFoundException e) {
                   throw new RuntimeException(e.getMessage());
                }
            }
        }
    
        /**
         *调用具体某目标的方法
         * */
        private void invokeTargetMethod(HttpServletRequest request,HttpServletResponse response,Method method){
    
            try {
                //先获得该类中的实例
                Object instance = method.getDeclaringClass().newInstance();
                //回调方法
                method.invoke(instance,request,response);
            } catch (InstantiationException e) {
                throw new RuntimeException(e.getMessage());
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e.getMessage());
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e.getMessage());
            }
    
        }
    }

    四、具体servlet请求实现类

    package org.nf.framework.Test;
    
    import org.nf.framework.annotation.UrlMapping;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 描述:
     * 具体处理请求
     *
     * @author lance
     * @create 2018-08-31 11:16
     */
    
    public class Collectors {
        @UrlMapping("/login")
        public void Login(HttpServletRequest request, HttpServletResponse response){
            String name = request.getParameter("userName");
            String password = request.getParameter("password");
            System.out.println(name);
            System.out.println(password);
            System.out.println("login.....");
        }
        
        @UrlMapping("/regist")
        public void regist(HttpServletRequest request, HttpServletResponse response){
            System.out.println(".....");
        }
    
    }
     

  • 相关阅读:
    Leetcode 283. Move Zeroes
    利用脚本,一键设置java环境变量(默认安装路径)
    'wmic' 不是内部或外部命令,也不是可运行的程序 解决方法
    PowerShell因为在此系统中禁止执行脚本解决方法
    使用VBSCRIPT安装字体
    批处理基本知识以及进阶 V2.0
    Vbs 脚本编程简明教程之一
    用批处理,批量安装字体文件 (Erector.bat)
    windows 7 系统装机优化
    使用批处理替换windows系统中的hosts文件
  • 原文地址:https://www.cnblogs.com/gepuginy/p/9726557.html
Copyright © 2020-2023  润新知