一個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(".....");
    }

}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM