自己實現一個簡易的SpringMVC

上回實現了一個簡易的Spring,那就順便實現一些SpringMVC吧。由於有了上回的基礎,這回實現比較快,晚飯前架構了一下,一晚上就寫得差不多了。自己實現的架構比較簡單,下面簡單介紹一下。

源碼下載:http://download.csdn.net/detail/jobsandczj/9844308

實現思路及工作流程

定義一個DispatcherServlet,用來做請求入口。初始化時,去讀取配置文件,獲得Controller的包,然後“注入”Controller。SpringMVC它本身是有自己的IoC容器的,用來注入Controller以及它的組件,但IoC我在Spring裏玩過了,這回就沒有寫依賴注入。但完事後發現其實也沒省多少功夫,終歸還是要掃包,解析的。

得到Controller後就構建Handler。讓每個Handler與一個請求路徑對應,我只定義了兩種類型的Handler,一個是處理頁面轉發的,一個是返回Json數據的。每種Handler都有它的適配器,這就讓Controller的方法設置參數少了很多約束,只要是request,response,session這仨傢伙就行。

最後初始化適配器列表,以便在接收到請求後適配。


下面是Handler抽象類:

package MySpringMVC.springmvc;

import java.lang.reflect.Method;

/**
 * Created by 10033 on 2017/5/16.
 */
public abstract class Handler {
    protected Method method;
    protected Object controller;
    protected Class[] params;
    protected RequestMethod requestMethod;

    public Handler(Method method, Object controller, Class[] params, RequestMethod requestMethod) {
        this.method = method;
        this.controller = controller;
        this.params = params;
        this.requestMethod = requestMethod;
    }

    public Method getMethod() {
        return method;
    }

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

    public Object getController() {
        return controller;
    }

    public void setController(Object controller) {
        this.controller = controller;
    }

    public Class[] getParams() {
        return params;
    }

    public void setParams(Class[] params) {
        this.params = params;
    }

    public RequestMethod getRequestMethod() {
        return requestMethod;
    }

    public void setRequestMethod(RequestMethod requestMethod) {
        this.requestMethod = requestMethod;
    }
}

下面這個是操作工具類,進行方法參數適配和適配器列表初始化

package MySpringMVC.utils;

import MySpringMVC.springmvc.ClasspathPackageScanner;
import MySpringMVC.springmvc.HandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

/**
 * Created by 10033 on 2017/5/16.
 */
public class OperationUtil {
    private static final Logger logger = LoggerFactory.getLogger(OperationUtil.class);
    private static final String ADAPTER_PACKAGE="MySpringMVC.springmvc";
    public static int makeObjectsByClasses
            (Class[] classes, Object[] objects, HttpServletRequest request, HttpServletResponse response) throws Exception {
        int cou=0;
        for(Class cla:classes) {
            if(cla==HttpServletRequest.class) {
                objects[cou++]=request;
            } else if(cla==HttpServletResponse.class) {
                objects[cou++]=response;
            } else if(cla==HttpSession.class) {
                objects[cou++]=request.getSession();
            } else {
                throw new Exception("控制器參數錯誤");
            }
        }
        return cou;
    }

    public static void initHandlerAdapterList(List<HandlerAdapter> list) {
        try {
            List<String> classStringList=new ClasspathPackageScanner(ADAPTER_PACKAGE).getFullyQualifiedClassNameList();
            for(String s:classStringList) {
                Class cla=Class.forName(s);

                //實現了HandlerAdapter接口
                if (HandlerAdapter.class.isAssignableFrom(cla)) {
                    Object obj=cla.newInstance();
                    list.add((HandlerAdapter) obj);
                }

            }
        } catch (IOException e) {
            logger.error(e.getMessage());
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage());
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage());
        } catch (InstantiationException e) {
            logger.error(e.getMessage());
        }
    }

}
這是DispatcherServlet類,進行初始化和控制器調度,爲了管理靜態資源要進行servlet註冊。

package MySpringMVC.springmvc;

import MySpringMVC.utils.OperationUtil;
import MySpringMVC.utils.PropertiesReaderUtil;
import MySpringMVC.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by 10033 on 2017/5/16.
 */
public class DispatcherServlet extends HttpServlet {

    private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);
    private String configName;
    private Map<String, String> configMap;
    private static final String SCAN_PACK="scan.package";
    private static final String VIEWPATH_STATIC="viewpath.static";
    private HandlerMap handleMap;
    private List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();

    //初始化
    public void init(String configName) throws ServletException {
        super.init();
//        configName=getInitParameter("contextConfigLocationName");
        configMap= PropertiesReaderUtil.getProperties(configName);

        String packages=configMap.get(SCAN_PACK);//獲得掃描包
        DispatchHelper.setMap(configMap);

        try {
            List<String> list=new ClasspathPackageScanner(packages).getFullyQualifiedClassNameList();
            handleMap=new HandlerMap(list);
        } catch (IOException e) {
            logger.error(e.getMessage());
        }

        OperationUtil.initHandlerAdapterList(handlerAdapters);

    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        init(config.getInitParameter("contextConfigLocationName"));
        ServletContext servletContext=config.getServletContext();
        /*ServletRegistration servletRegistration = servletContext.getServletRegistration("jsp");
        servletRegistration.addMapping("/WEB-INF/jsps*//*");*/

        ServletRegistration servletRegistration2 = servletContext.getServletRegistration("default");
        String[] staticString=configMap.get(VIEWPATH_STATIC).split(";");

        for(int i=0;i<staticString.length;i++) {
            servletRegistration2.addMapping(staticString[i].toLowerCase()+"/*");
        }

    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //獲取請求路徑
        String requestUrl=StringUtil.getRequestURL(req);

        Handler handler=handleMap.getHandler(requestUrl,req.getMethod());
        if(null!=handler) {
            for(HandlerAdapter handlerAdapter:handlerAdapters) {
                if(handlerAdapter.support(handler)) {
                    handlerAdapter.setHandler(handler);
                    handlerAdapter.execute(req,resp);
                    break;
                }
            }
        }else {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
        }

    }
}

這回還是有一些不足的,一是沒實現IoC,當然這是自己偷懶。但還有一個不足就是,由於前端只支持JSP,所以View,Model這些也都沒管。

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