1. 程式人生 > >從零寫一個Java WEB框架(七)Controller層轉換器

從零寫一個Java WEB框架(七)Controller層轉換器

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

本篇

上一篇已經為轉換器準備了幾個bean類,例如:ParamView,Data 類。本篇就真正的開始寫轉換器了。

什麼是轉換器呢?

我的理解就是:繼承HttpServlet類,重寫裡面的init()方法Service 方法。
init()方法是建立Servlet容器的時候,會呼叫該方法進行初始化,我們將用這個方法來載入我們的Helper方法。
Service

方法,轉換器的核心方法。因為,每當有請求,都會呼叫這個類來進行對請求頭的處理,其實在HttpServlet類也是充當一個轉發的角色,因為在Service會判斷請求頭的請求方法,然後選擇呼叫的是doGet()還是doPost()方法。

程式碼實現

DispatcherServlet 轉換器實現

        /*
*  請求轉發器
* */

@WebServlet(urlPatterns = "/*",loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
    private static
Logger log = LoggerFactory.getLogger(DispatcherServlet.class); /* * 思路: * 1. 在初始化Servlet容器的時候,載入相關的Helper類,Jsp路徑,靜態資源路徑. * 2. 從request獲取到請求方法和路徑 * -》根據請求方法和路徑去Controller容器獲取封裝了類和方法的Handler物件 * -》從Handler物件裡拿到類名,然後從Bean容器裡獲取到該類的例項 * -》從request獲取引數,將所有引數存到Param物件裡面 * -》從Handler物件拿到方法名,通過ReflectionUtil工具類呼叫方法(傳入物件,方法名,引數) * -》從呼叫方法返回的結果判斷是View型別的就進行View處理,返回JSP頁面,如果是Data型別的就返回JSON資料。 * * */
@Override public void init(ServletConfig config) throws ServletException { //初始化相關的Helper HelperLoader.init(); //獲取ServletContext 物件 ServletContext servletContext = config.getServletContext(); //註冊JSP路徑 ServletRegistration jsp = servletContext.getServletRegistration("jsp"); jsp.addMapping(ConfigHelper.getAppJspPath() + "*"); //註冊處理靜態資源的預設Servlet ServletRegistration def = servletContext.getServletRegistration("default"); def.addMapping(ConfigHelper.getAppAssetPath() + "*"); log.info("Init() success"); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //獲取到請求方法和路徑 String method = req.getMethod().toLowerCase(); //getPathInfo() 和getRequestURI() 去區別就是 // getPathInfo 是從Servlet配置路徑開始獲取額外路徑的。 // getRequestURI 則是從埠號開始獲取路徑的 String pathInfo = req.getPathInfo(); //獲取Handler物件 Handler handler = ControllerHelper.getHandler(method, pathInfo); if (handler != null) { //獲取類 Class<?> controllerClass = handler.getControllerClass(); //獲取例項物件 Object bean = BeanHelper.getBean(controllerClass); //從request獲取引數 Enumeration<String> parameterNames = req.getParameterNames(); Map<String, Object> paramMap = new HashMap<>(); while (parameterNames.hasMoreElements()) { String s = parameterNames.nextElement(); String parameter = req.getParameter(s); paramMap.put(s, parameter); } //獲取方法名 Method actionMethod = handler.getActionMethod(); Param param = new Param(paramMap); log.info("呼叫方法名: "+ actionMethod.getName()); //呼叫方法 Object result = ReflectionUtil.invokeMethod(bean, actionMethod, param); //判斷是否是View if (result instanceof View) { View view = (View) result; String path = view.getPath(); if (StringUtils.isNotEmpty(path)) { //如果是/開頭,則是重定向 if (path.startsWith("/")) { resp.sendRedirect(req.getContextPath() + path); } else { //轉發 Map<String, Object> map = view.getModel(); for (Map.Entry<String, Object> m : map.entrySet()) { req.setAttribute(m.getKey(),m.getValue()); log.info("key "+ m.getKey()); } req.getRequestDispatcher(ConfigHelper.getAppJspPath()+path).forward(req,resp); } } else if (result instanceof Data) { //返回JSON資料 Data data = (Data) result; Object model = data.getModel(); if (model != null) { resp.setContentType("application/json"); resp.setCharacterEncoding("utf-8"); PrintWriter writer = resp.getWriter(); String s = JsonUtil.toJson(model); writer.write(s); writer.flush(); writer.close(); } } } } } }

CustomerController 層實現

@Controller
public class CustomerController {

    @Inject
    private CustomerService customerService;

    /*
     *  進入客戶列表介面
     * */
    @Action("get:/customer")
    public View index(Param param) {
        List<Customer> customerList = customerService.getCustomerList();
        return new View("customer.jsp").addModel("customerList", customerList);
    }

    /*
     *  顯示客戶基本資訊
     * */
    @Action("get:/customer_show")
    public View show(Param param) {
        long id = param.getLong("id");
        Customer customer = customerService.getCustomer(id);
        return new View("customer_show.jsp").addModel("customer", customer);
    }


    /*
     *  進入建立客戶介面
     * */
    @Action("get:/customer_create")
    public View create(Param param) {
        return new View("customer_create.jsp");
    }

    /*
     *  處理建立客戶請求
     * */
    @Action("post:/customer_create")
    public Data createSubmit(Param param) {
        Map<String, Object> map = param.getMap();
        boolean result = customerService.createCustomer(map);
        return new Data(result);
    }

    /*
     *  進入編輯客戶 介面
     * */
    @Action("get:/customer_edit")
    public View edit(Param param) {
        long id = param.getLong("id");
        Customer customer = customerService.getCustomer(id);
        return new View("customer_edit.jsp").addModel("customer", customer);
    }

    /*
    *  處理編輯客戶請求
    * */
    //TODO


    /*
    *  處理刪除客戶請求
    * */
    //TODO
}

效果圖
image.png

總結

一個輕量級的框架就這樣完成了。從Controller層到Service層,再到Dao層。我覺得框架的雛形已經是出現了,但是我覺得在這麼輕便的框架,我們可以實現很多想法。
下一篇,就是講框架程式碼和業務程式碼分離開。完成一個真正的框架。