從零寫一個Java WEB框架(六)Controller層優化

  • 該系列,其實是對《架構探險》這本書的實踐。本人想記錄自己的學習心得所寫下的。
  • 從一個簡單的Servlet項目開始起步。對每一層進行優化,然後形成一個輕量級的框架。
  • 每一篇,都是針對項目的不足點進行優化的。
  • 項目已放上github

本篇

前幾篇的優化都沒有涉及到Controller層。本篇開始將開始實現對Controller層的優化。由於上篇的IOC,創建了類容器。基於這個類容器,就可以很輕鬆地完成對Controller的優化了。
爲了Controller解耦,還是決定使用請求容器(存放請求路徑與處理方法映射關係),建立一個轉換器。根據獲取HttpRequest中的請求路徑和參數,從請求容器裏面去獲取到相對應的方法。達到一個解耦的目的。
本篇主要實現功能:
- 封裝請求信息
- 封裝類和方法信息
- 將請求信息和方法信息形成K-V映射關係存到Map容器中

Controller 層實現目的:
根據Action註解實現請求路徑和方法的綁定。

@Controller
public class CustomerServlet {


//    獲取所有用戶信息
    @Action("get:/customer_show/getList")
    public String getList() {
        //TODO
        return null;
    }


//    根據id獲取用戶信息
    @Action("get:/customer_show/getCustomer")
    public String getList(Integer id) {
        //TODO
        return null;
    }
}

功能實現

Request類 封裝請求信息

/*
*
*   封裝請求信息
*
*   思路:
*   1. 封裝請求的信息, 正常的請求信息是: get:/customer_show
*      需要拆分成 requestMethod = get
*               requestPath  = /customer_show
*
*   2. 因爲需要將請求信息放在Map中,以Request的對象爲key,因爲是對象作爲key,
*       所以重寫hashcode()和equals()方法,主要改變Map判斷key的時候發揮作用。
* */
public class Request {

    /*
     *  請求方法
     * */
    private String requestMethod;

    /*
     *  請求路徑
     * */
    private String requestPath;

    public Request(String requestMethod, String requestPath) {
        this.requestMethod = requestMethod;
        this.requestPath = requestPath;
    }

    public String getRequestMethod() {
        return requestMethod;
    }

    public String getRequestPath() {
        return requestPath;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Request) {
            Request r = (Request) o;
            //進行判斷
            if (r.getRequestMethod().equals(this.requestMethod) &&
                    r.getRequestPath().equals(this.requestPath)) {
                return true;
            }
        }

        return false;

    }


    // 主要思路就是利用兩個變量的hashCode,而不是對象的hashCode。

    @Override
    public int hashCode() {
        return Objects.hash(this.requestPath, this.requestMethod);
    }
}

Handler 類 封裝Action註解的類和方法

/*
*  封裝Action信息
*  封裝類 和方法
* */
public class Handler {

    /*
    *  Controller註解 類
    * */
    private Class<?> controllerClass;

    /*
     *  Action註解的 方法
     * */
    private Method actionMethod;

    public Handler(Class<?> controllerClass, Method actionMethod) {
        this.controllerClass = controllerClass;
        this.actionMethod = actionMethod;
    }

    public Class<?> getControllerClass() {
        return controllerClass;
    }

    public Method getActionMethod() {
        return actionMethod;
    }
}

ControllerHelper 類 建立有個Map容器用來存放request和handler的映射關係

/*
 *  控制類助手類
 * */
public class ControllerHelper {
    /*
     *  思路:
     *  1、遍歷所有Controller 註解的類
     *  2、遍歷每個類中的方法,找出有Action註解的方法
     *  3、從Action 註解中獲取URL映射
     *  4、將URL映射存到Request對象,將該類和方法存到Handler對象
     *  5、存到Map集合中。 key---Request  value---Handler
     * */

    /*
     *  定義一個Map容器,存放Request和Handler的映射關係
     * */
    private final static Map<Request, Handler> ACTION_MAP =
            new HashMap<>();

    static{
        //獲取所有具有Controoler註解的類
        Set<Class<?>> controllerClassSet = ClassHelper.getControllerClassSet();
        if (CollectionUtils.isNotEmpty(controllerClassSet)) {
            //遍歷類
            for (Class<?> c : controllerClassSet) {
                //獲取該類下的所有方法
                Method[] declaredMethods = c.getDeclaredMethods();
                if (declaredMethods != null) {
                    //遍歷方法
                    for (Method m : declaredMethods) {
                        if (m.isAnnotationPresent(Action.class)) {
                            Action action = m.getAnnotation(Action.class);
                            //獲取Action註解中的URL值
                            String mapping = action.value();
                            //驗證URL映射值
                            if (mapping.matches("\\w+:/\\w*")) {
                                //將URL分割成Method 和path
                                String[] split = mapping.split(":");
                                if (split != null && split.length == 2) {
                                    //獲取請求方法與請求路徑
                                    String method=split[0];
                                    String path = split[1];
                                    Request request = new Request(method, path);
                                    Handler handler = new Handler(c, m);
                                    //存進 Map
                                    ACTION_MAP.put(request, handler);
                                }
                            }
                        }
                    }
                }


            }
        }
    }


    public static Handler getHandler(String requestMethod, String requestPath) {
        Request request = new Request(requestMethod, requestPath);
        return ACTION_MAP.get(request);
    }
}

Loader 類
因爲是框架,所以很多都是配置類,需要在項目啓動的時候就需要加載,所以需要寫一個Loader類,只需要調用這麼一個類就可以加載框架的配置類了。

/*
*  加載相應的Helper類
* */
public final class HelperLoader {

    public  static void init() {
       Class<?>[] classList={
               ClassHelper.class,
               BeanHelper.class,
               ConfigHelper.class,
               ControllerHelper.class,
               IOCHelper.class
       };
        for (Class c : classList) {
            ClassUtil.loadClass(c.getName(), true);
        }
    }
}   

總結

一個Action的容器就建立起來了。下一章節就需要建立一個轉發器,根據HttpRequest的請求路徑和參數從Action容器中找到對應的處理方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章