天天看點

自定義一個簡單的SpringMVC架構

思路分析

  • 在伺服器啟動時,就掃描包下所有類:得到有注解

    @Controller

    的類
    • 反射生成這個類的執行個體對象:

      object

    • 周遊類裡所有的方法,得到方法對象:

      method

    • 擷取每個方法上

      @RequestMapping

      配置的映射路徑:

      mappingPath

    • 把方法對象

      method

      和類執行個體對象

      object

      ,封裝成對象:

      MvcMethod

    • mappingPath

      為key,

      MvcMethod

      對象為value,儲存到一個Map中
  • 當用戶端請求到

    DispatcherServlet

    • 擷取請求的資源路徑:path
    • 從Map容器中找到對應的

      MvcMethod

    • 反射執行

      MvcMethod

      中的方法對象

實作

@Controller

注解
package com.lily.SpringMVC_02;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)  //運作在類上
@Retention(RetentionPolicy.RUNTIME)   //存活到運作
public @interface Controller {
}
           

@RequestMapping

package com.lily.SpringMVC_02;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 功能描述:〈用在業務控制器的方法上,用來聲明 方法的路徑〉
 */
@Target(ElementType.METHOD)             //元注解: 表示在方法總運作
@Retention(RetentionPolicy.RUNTIME)   //元注解: 表示保留到運作階段
public @interface RequestMapping {
    String value();                     //配置的映射路徑
}
           

MvcMethod

package com.lily.SpringMVC_02;/*
@Author:李正铠
@Date:2020年03月02日21時13分
*/
import java.lang.reflect.Method;
public class MvcMethod {
    private Method method;
    private Object object;

    public MvcMethod() {
    }

    public MvcMethod(Method method, Object object) {
        this.method = method;
        this.object = object;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }
}
           

DispatcherServlet

/**
package com.lily.SpringMVC_02;/*
@Author:李正铠
@Date:2020年03月02日22時26分
*/

import com.lily.util.ClassScannerUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@WebServlet(urlPatterns = "*.do", loadOnStartup = 1)
public class DispatcherServlet extends HttpServlet {
    /**
     * 功能描述:〈重寫init方法,配置注解:loadOnStartup,當值是整數,代表伺服器啟動時執行init方法〉
     */
    private Map<String, MvcMethod> map = new HashMap<>();

    @Override
    public void init() throws ServletException {
        try {
            List<Class<?>> classsFromPackage = ClassScannerUtils.getClasssFromPackage("com.lily.web");
            for (Class<?> clazz : classsFromPackage) {
                boolean isController = clazz.isAnnotationPresent(Controller.class);
                if (!isController) {
                    System.out.println(clazz + "類沒有Controller注解");
                    continue;
                }
                Object object = clazz.newInstance();
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    boolean isRequestMapping = method.isAnnotationPresent(RequestMapping.class);
                    if (isRequestMapping) {
                        RequestMapping getRequestMapping = method.getAnnotation(RequestMapping.class);
                        String MappingPath = getRequestMapping.value();
                        MvcMethod mvcMethod = new MvcMethod(method, object);
                        map.put(MappingPath, mvcMethod);
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String uri = request.getRequestURI();
        String contextPath = request.getContextPath();
        String substring = uri.substring(contextPath.length(), uri.lastIndexOf("."));
        MvcMethod mvcMethod = map.get(substring);
        try {
            mvcMethod.getMethod().invoke(mvcMethod.getObject(), request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

           

ClassScannerUtils

package com.lily.util;

import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;


public class ClassScannerUtils {

    /**
     * 獲得包下面的所有的class
     *
     * @param
     * @return List包含所有class的執行個體
     */
    public static List<Class<?>> getClasssFromPackage(String packageName) {
        List clazzs = new ArrayList<>();
        // 是否循環搜尋子包
        boolean recursive = true;
        // 包名對應的路徑名稱
        String packageDirName = packageName.replace('.', '/');
        Enumeration<URL> dirs;

        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {

                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    findClassInPackageByFile(packageName, filePath, recursive, clazzs);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazzs;
    }

    /**
     * 在package對應的路徑下找到所有的class
     */
    public static void findClassInPackageByFile(String packageName, String filePath, final boolean recursive,
                                                List<Class<?>> clazzs) {
        File dir = new File(filePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 在給定的目錄下找到所有的檔案,并且進行條件過濾
        File[] dirFiles = dir.listFiles(new FileFilter() {

            public boolean accept(File file) {
                boolean acceptDir = recursive && file.isDirectory();// 接受dir目錄
                boolean acceptClass = file.getName().endsWith("class");// 接受class檔案
                return acceptDir || acceptClass;
            }
        });

        for (File file : dirFiles) {
            if (file.isDirectory()) {
                findClassInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, clazzs);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    clazzs.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


}

           

繼續閱讀