前面與你們分享了幾篇在 Smart 中有關數據持久層的重構解決方案,今天咱們把目光集中到 MVC 框架上來吧。衆所周知,Smart 是一款看起來還不錯的輕量級 Java Web 框架,若是連 MVC 框架都很差用或者不容易擴展,那豈不是本身給本身找麻煩嗎?前端
當我剛說完上面這句話時,咱們團隊中的一名帥哥 快槍手 同窗,他指出了我在 Smart MVC 上的嚴重問題,請容許我再次感謝個人小夥伴快槍手,感謝他深厚的功力與犀利的言語!解救我於水火之中,讓我學到了不少,受益不淺。java
咱們先來看看 Smart MVC 中一個很是重要的類 —— 前端控制器,它就是 DispatcherServlet
,重構前是這樣的:git
<!-- lang: java --> @WebServlet(urlPatterns = "/*", loadOnStartup = 0) public class DispatcherServlet extends HttpServlet { private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class); @Override public void init(ServletConfig config) throws ServletException { // 初始化相關配置 ServletContext servletContext = config.getServletContext(); UploadHelper.init(servletContext); } @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 設置請求編碼方式 request.setCharacterEncoding(FrameworkConstant.UTF_8); // 獲取當前請求相關數據 String currentRequestMethod = request.getMethod(); String currentRequestPath = WebUtil.getRequestPath(request); logger.debug("[Smart] {}:{}", currentRequestMethod, currentRequestPath); // 將「/」請求重定向到首頁 if (currentRequestPath.equals("/")) { WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response); return; } // 去掉當前請求路徑末尾的「/」 if (currentRequestPath.endsWith("/")) { currentRequestPath = currentRequestPath.substring(0, currentRequestPath.length() - 1); } // 定義幾個變量(在下面的循環中使用) ActionBean actionBean = null; Matcher requestPathMatcher = null; // 獲取並遍歷 Action 映射 Map<RequestBean, ActionBean> actionMap = ActionHelper.getActionMap(); for (Map.Entry<RequestBean, ActionBean> actionEntry : actionMap.entrySet()) { // 從 RequestBean 中獲取 Request 相關屬性 RequestBean requestBean = actionEntry.getKey(); String requestMethod = requestBean.getRequestMethod(); String requestPath = requestBean.getRequestPath(); // 正則表達式 // 獲取請求路徑匹配器(使用正則表達式匹配請求路徑並從中獲取相應的請求參數) requestPathMatcher = Pattern.compile(requestPath).matcher(currentRequestPath); // 判斷請求方法與請求路徑是否同時匹配 if (requestMethod.equalsIgnoreCase(currentRequestMethod) && requestPathMatcher.matches()) { // 獲取 ActionBean 及其相關屬性 actionBean = actionEntry.getValue(); // 若成功匹配,則終止循環 break; } } // 若未找到 Action,則跳轉到 404 頁面 if (actionBean == null) { WebUtil.sendError(HttpServletResponse.SC_NOT_FOUND, "", response); return; } // 初始化 DataContext DataContext.init(request, response); try { // 調用 Action 方法 invokeActionMethod(request, response, actionBean, requestPathMatcher); } catch (Exception e) { // 處理 Action 異常 handleActionException(request, response, e); } finally { // 銷燬 DataContext DataContext.destroy(); } } private void invokeActionMethod(HttpServletRequest request, HttpServletResponse response, ActionBean actionBean, Matcher requestPathMatcher) throws Exception { // 獲取 Action 相關信息 Class<?> actionClass = actionBean.getActionClass(); Method actionMethod = actionBean.getActionMethod(); // 從 BeanHelper 中建立 Action 實例 Object actionInstance = BeanHelper.getBean(actionClass); // 獲取 Action 方法參數 List<Object> paramList = createParamList(request, actionBean, requestPathMatcher); Class<?>[] paramTypes = actionMethod.getParameterTypes(); if (paramTypes.length != paramList.size()) { throw new RuntimeException("因爲參數不匹配,沒法調用 Action 方法!"); } // 調用 Action 方法 actionMethod.setAccessible(true); // 取消類型安全檢測(可提升反射性能) Object actionMethodResult = actionMethod.invoke(actionInstance, paramList.toArray()); // 處理 Action 方法返回值 handleActionMethodReturn(request, response, actionMethodResult); } private List<Object> createParamList(HttpServletRequest request, ActionBean actionBean, Matcher requestPathMatcher) throws Exception { // 定義參數列表 List<Object> paramList = new ArrayList<Object>(); // 獲取 Action 方法參數類型 Class<?>[] actionParamTypes = actionBean.getActionMethod().getParameterTypes(); // 添加路徑參數列表(請求路徑中的帶佔位符參數) paramList.addAll(createPathParamList(requestPathMatcher, actionParamTypes)); // 分兩種狀況進行處理 if (UploadHelper.isMultipart(request)) { // 添加 Multipart 請求參數列表 paramList.addAll(UploadHelper.createMultipartParamList(request)); } else { // 添加普通請求參數列表(包括 Query String 與 Form Data) Map<String, Object> requestParamMap = WebUtil.getRequestParamMap(request); if (MapUtil.isNotEmpty(requestParamMap)) { paramList.add(new Params(requestParamMap)); } } // 返回參數列表 return paramList; } private List<Object> createPathParamList(Matcher requestPathMatcher, Class<?>[] actionParamTypes) { // 定義參數列表 List<Object> paramList = new ArrayList<Object>(); // 遍歷正則表達式中所匹配的組 for (int i = 1; i <= requestPathMatcher.groupCount(); i++) { // 獲取請求參數 String param = requestPathMatcher.group(i); // 獲取參數類型(支持四種類型:int/Integer、long/Long、double/Double、String) Class<?> paramType = actionParamTypes[i - 1]; if (paramType.equals(int.class) || paramType.equals(Integer.class)) { paramList.add(CastUtil.castInt(param)); } else if (paramType.equals(long.class) || paramType.equals(Long.class)) { paramList.add(CastUtil.castLong(param)); } else if (paramType.equals(double.class) || paramType.equals(Double.class)) { paramList.add(CastUtil.castDouble(param)); } else if (paramType.equals(String.class)) { paramList.add(param); } } // 返回參數列表 return paramList; } private void handleActionMethodReturn(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult) { // 判斷返回值類型 if (actionMethodResult != null) { if (actionMethodResult instanceof Result) { // 分兩種狀況進行處理 Result result = (Result) actionMethodResult; if (UploadHelper.isMultipart(request)) { // 對於 multipart 類型,說明是文件上傳,須要轉換爲 HTML 格式並寫入響應中 WebUtil.writeHTML(response, result); } else { // 對於其它類型,統一轉換爲 JSON 格式並寫入響應中 WebUtil.writeJSON(response, result); } } else if (actionMethodResult instanceof View) { // 轉發 或 重定向 到相應的頁面中 View view = (View) actionMethodResult; if (view.isRedirect()) { // 獲取路徑 String path = view.getPath(); // 重定向請求 WebUtil.redirectRequest(path, request, response); } else { // 獲取路徑 String path = FrameworkConstant.JSP_PATH + view.getPath(); // 初始化請求屬性 Map<String, Object> data = view.getData(); if (MapUtil.isNotEmpty(data)) { for (Map.Entry<String, Object> entry : data.entrySet()) { request.setAttribute(entry.getKey(), entry.getValue()); } } // 轉發請求 WebUtil.forwardRequest(path, request, response); } } } } private void handleActionException(HttpServletRequest request, HttpServletResponse response, Exception e) { // 判斷異常緣由 Throwable cause = e.getCause(); if (cause instanceof AccessException) { // 分兩種狀況進行處理 if (WebUtil.isAJAX(request)) { // 跳轉到 403 頁面 WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response); } else { // 重定向到首頁 WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response); } } else if (cause instanceof PermissionException) { // 跳轉到 403 頁面 WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response); } else { // 跳轉到 500 頁面 logger.error("執行 Action 出錯!", e); WebUtil.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, cause.getMessage(), response); } } }
代碼量雖然不算太多,可是你們能夠發現,這個類犯了一個嚴重的錯誤,或許應該說是編程中的一個大忌! —— 嚴重違反了「單一職責原則」。正則表達式
當快槍手指出這個問題時,我彷彿被一根針狠狠紮了一下,瞬間就清醒過來了,本身果真是犯了錯誤。編程
正所謂「知錯能改,善莫大焉」,因此我虛心地向快槍手請教,因而他開始舞弄筆墨,只需一分鐘就幫我畫了一張草圖:緩存
這貌似哪裏見過呀,沒錯,Spring MVC 就長這樣子!安全
可見結構很是清晰:app
DispatcherServlet
(前端控制器)DispatcherServlet
調用 HandlerMapping
接口,獲取 Handler
對象(該對象是對 Action 方法的抽象)DispatcherServlet
調用 HandlerInvoker
接口,調用具體的 Action 方法(同時須要獲取 Action 參數)HandlerInvoker
調用 ViewResolver
接口,進行視圖解析(視圖能夠是 JSP、HTML 或 Velocity 模板等)DispatcherServlet
調用 HandlerExceptionResolver
接口,進行相關的異常處理(可能會跳轉到相應的錯誤頁面)你們可能會問:爲何要使用如此之多的接口呢?框架
由於在每一個成功接口的背後,總會有一個默默支持它的實現,而這些實現都是 Smart 框架內部提供的默認實現,開發人員能夠根據實際須要進行定製,此時就須要與 InstanceFactory
打交道了。ide
<!-- lang: java --> /** * 實例工廠 * * @author huangyong * @since 2.3 */ public class InstanceFactory { /** * 用於緩存對應的實例 */ private static final Map<String, Object> cache = new ConcurrentHashMap<String, Object>(); ... /** * HandlerMapping */ private static final String HANDLER_MAPPING = "smart.framework.custom.handler_mapping"; /** * HandlerInvoker */ private static final String HANDLER_INVOKER = "smart.framework.custom.handler_invoker"; /** * HandlerExceptionResolver */ private static final String HANDLER_EXCEPTION_RESOLVER = "smart.framework.custom.handler_exception_resolver"; /** * ViewResolver */ private static final String VIEW_RESOLVER = "smart.framework.custom.view_resolver"; ... /** * 獲取 HandlerMapping */ public static HandlerMapping getHandlerMapping() { return getInstance(HANDLER_MAPPING, DefaultHandlerMapping.class); } /** * 獲取 HandlerInvoker */ public static HandlerInvoker getHandlerInvoker() { return getInstance(HANDLER_INVOKER, DefaultHandlerInvoker.class); } /** * 獲取 HandlerExceptionResolver */ public static HandlerExceptionResolver getHandlerExceptionResolver() { return getInstance(HANDLER_EXCEPTION_RESOLVER, DefaultHandlerExceptionResolver.class); } /** * 獲取 ViewResolver */ public static ViewResolver getViewResolver() { return getInstance(VIEW_RESOLVER, DefaultViewResolver.class); } @SuppressWarnings("unchecked") public static <T> T getInstance(String cacheKey, Class<T> defaultImplClass) { // 若緩存中存在對應的實例,則返回該實例 if (cache.containsKey(cacheKey)) { return (T) cache.get(cacheKey); } // 從配置文件中獲取相應的接口實現類配置 String implClassName = ConfigHelper.getString(cacheKey); // 若實現類配置不存在,則使用默認實現類 if (StringUtil.isEmpty(implClassName)) { implClassName = defaultImplClass.getName(); } // 經過反射建立該實現類對應的實例 T instance = ObjectUtil.newInstance(implClassName); // 若該實例不爲空,則將其放入緩存 if (instance != null) { cache.put(cacheKey, instance); } // 返回該實例 return instance; } }
好比說,當開發者想提供本身的 HandlerInvoker 實現,怎麼作到呢?
他只須要在 smart.properties
配置文件中,添加以下配置項:
<!-- lang: java --> smart.framework.custom.handler_invoker=本身的 HandlerInvoker 實現類
abel533 同窗就實現了一個更強大的 HandlerInvoker,他的代碼地址以下:
http://git.oschina.net/free/Args/tree/smart_plugin_args/
很是感謝他的貢獻!
說到這裏,你們應該火燒眉毛想看看,快槍手這位大神到底是如何定義這些接口的。別急,下面的纔是精華!
這是 HandlerMapping
接口:
<!-- lang: java --> /** * 處理器映射 * * @author huangyong * @since 2.3 */ public interface HandlerMapping { /** * 獲取 Handler * * @param currentRequestMethod 當前請求方法 * @param currentRequestPath 當前請求路徑 * @return Handler */ Handler getHandler(String currentRequestMethod, String currentRequestPath); }
這是 HandlerInvoker
接口:
<!-- lang: java --> /** * Handler 調用器 * * @author huangyong * @since 2.3 */ public interface HandlerInvoker { /** * 調用 Handler * * @param request 請求對象 * @param response 響應對象 * @param handler Handler * @throws Exception 異常 */ void invokeHandler(HttpServletRequest request, HttpServletResponse response, Handler handler) throws Exception; }
這是 ViewResolver
接口:
<!-- lang: java --> /** * 視圖解析器 * * @author huangyong * @since 2.3 */ public interface ViewResolver { /** * 解析視圖 * * @param request 請求對象 * @param response 響應對象 * @param actionMethodResult Action 方法返回值 */ void resolveView(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult); }
這是 HandlerExceptionResolver
接口:
<!-- lang: java --> /** * Handler 異常解析器 * * @author huangyong * @since 2.3 */ public interface HandlerExceptionResolver { /** * 解析 Handler 異常 * * @param request 請求對象 * @param response 響應對象 * @param e 異常 */ void resolveHandlerException(HttpServletRequest request, HttpServletResponse response, Exception e); }
可見,每一個接口中只包含一個方法,充分作到了「單一職責」,並且接口方法的參數很是簡單。
其中有一個 Handler
類須要說明一下,它就是曾經的 ActionBean
,這裏只是把它改了一個名字,讓它看起來更加的專業,說白了,Handler
就是 Action 方法,沒什麼神奇的。
此外,快槍手建議將之前的 RequestBean
重命名爲 Requestor
,用於封裝請求對象的相關信息。
有必要再對 Handler
的代碼說明一下:
<!-- lang: java --> /** * 封裝 Action 方法相關信息 * * @author huangyong * @since 1.0 */ public class Handler { private Class<?> actionClass; private Method actionMethod; private Matcher requestPathMatcher; public Handler(Class<?> actionClass, Method actionMethod) { this.actionClass = actionClass; this.actionMethod = actionMethod; } public Class<?> getActionClass() { return actionClass; } public Method getActionMethod() { return actionMethod; } public Matcher getRequestPathMatcher() { return requestPathMatcher; } public void setRequestPathMatcher(Matcher requestPathMatcher) { this.requestPathMatcher = requestPathMatcher; } }
該類中包括三個成員變量:
Class<?> actionClass
:表示該 Handler 所在的 Action 類Method actionMethod
:表示當前的 Action 方法Matcher requestPathMatcher
:表示請求路徑的正則表達式匹配器(用於根據請求 URL 匹配 Action 方法)準備工做現已就緒,下面就來看看這些接口的默認實現吧。
接口定義清楚了,重構猶如複製粘貼,下面根據以上 MVC 相關接口的出現順序,分別展現具體的實現代碼。
這是 HandlerMapping
接口的默認實現:
<!-- lang: java --> /** * 默認處理器映射 * * @author huangyong * @since 2.3 */ public class DefaultHandlerMapping implements HandlerMapping { /** * 用於緩存 Handler 實例 */ private static final Map<String, Handler> cache = new ConcurrentHashMap<String, Handler>(); @Override public Handler getHandler(String currentRequestMethod, String currentRequestPath) { // 若緩存中存在對應的實例,則返回該實例 String cacheKey = currentRequestMethod + ":" + currentRequestPath; if (cache.containsKey(cacheKey)) { return cache.get(cacheKey); } // 定義一個 Handler Handler handler = null; // 獲取並遍歷 Action 映射 Map<Requestor, Handler> actionMap = ActionHelper.getActionMap(); for (Map.Entry<Requestor, Handler> actionEntry : actionMap.entrySet()) { // 從 Requestor 中獲取 Request 相關屬性 Requestor requestor = actionEntry.getKey(); String requestMethod = requestor.getRequestMethod(); String requestPath = requestor.getRequestPath(); // 正則表達式 // 獲取請求路徑匹配器(使用正則表達式匹配請求路徑並從中獲取相應的請求參數) Matcher requestPathMatcher = Pattern.compile(requestPath).matcher(currentRequestPath); // 判斷請求方法與請求路徑是否同時匹配 if (requestMethod.equalsIgnoreCase(currentRequestMethod) && requestPathMatcher.matches()) { // 獲取 Handler 及其相關屬性 handler = actionEntry.getValue(); // 設置請求路徑匹配器 if (handler != null) { handler.setRequestPathMatcher(requestPathMatcher); } // 若成功匹配,則終止循環 break; } } // 若該實例不爲空,則將其放入緩存 if (handler != null) { cache.put(cacheKey, handler); } // 返回該 Handler return handler; } }
這是 HandlerInvoker
接口的默認實現:
<!-- lang: java --> /** * 默認 Handler 調用器 * * @author huangyong * @since 2.3 */ public class DefaultHandlerInvoker implements HandlerInvoker { private ViewResolver viewResolver = InstanceFactory.getViewResolver(); @Override public void invokeHandler(HttpServletRequest request, HttpServletResponse response, Handler handler) throws Exception { // 獲取 Action 相關信息 Class<?> actionClass = handler.getActionClass(); Method actionMethod = handler.getActionMethod(); // 從 BeanHelper 中建立 Action 實例 Object actionInstance = BeanHelper.getBean(actionClass); // 建立 Action 方法的參數列表 List<Object> actionMethodParamList = createActionMethodParamList(request, handler); // 檢查參數列表是否合法 checkParamList(actionMethod, actionMethodParamList); // 調用 Action 方法 Object actionMethodResult = invokeActionMethod(actionMethod, actionInstance, actionMethodParamList); // 解析視圖 viewResolver.resolveView(request, response, actionMethodResult); } public List<Object> createActionMethodParamList(HttpServletRequest request, Handler handler) throws Exception { // 定義參數列表 List<Object> paramList = new ArrayList<Object>(); // 獲取 Action 方法參數類型 Class<?>[] actionParamTypes = handler.getActionMethod().getParameterTypes(); // 添加路徑參數列表(請求路徑中的帶佔位符參數) paramList.addAll(createPathParamList(handler.getRequestPathMatcher(), actionParamTypes)); // 分兩種狀況進行處理 if (UploadHelper.isMultipart(request)) { // 添加 Multipart 請求參數列表 paramList.addAll(UploadHelper.createMultipartParamList(request)); } else { // 添加普通請求參數列表(包括 Query String 與 Form Data) Map<String, Object> requestParamMap = WebUtil.getRequestParamMap(request); if (MapUtil.isNotEmpty(requestParamMap)) { paramList.add(new Params(requestParamMap)); } } // 返回參數列表 return paramList; } private List<Object> createPathParamList(Matcher requestPathMatcher, Class<?>[] actionParamTypes) { // 定義參數列表 List<Object> paramList = new ArrayList<Object>(); // 遍歷正則表達式中所匹配的組 for (int i = 1; i <= requestPathMatcher.groupCount(); i++) { // 獲取請求參數 String param = requestPathMatcher.group(i); // 獲取參數類型(支持四種類型:int/Integer、long/Long、double/Double、String) Class<?> paramType = actionParamTypes[i - 1]; if (ClassUtil.isInt(paramType)) { paramList.add(CastUtil.castInt(param)); } else if (ClassUtil.isLong(paramType)) { paramList.add(CastUtil.castLong(param)); } else if (ClassUtil.isDouble(paramType)) { paramList.add(CastUtil.castDouble(param)); } else if (ClassUtil.isString(paramType)) { paramList.add(param); } } // 返回參數列表 return paramList; } private Object invokeActionMethod(Method actionMethod, Object actionInstance, List<Object> actionMethodParamList) throws IllegalAccessException, InvocationTargetException { // 經過反射調用 Action 方法 actionMethod.setAccessible(true); // 取消類型安全檢測(可提升反射性能) return actionMethod.invoke(actionInstance, actionMethodParamList.toArray()); } private void checkParamList(Method actionMethod, List<Object> actionMethodResult) { // 判斷 Action 方法參數的個數是否匹配 Class<?>[] actionMethodParameterTypes = actionMethod.getParameterTypes(); if (actionMethodParameterTypes.length != actionMethodResult.size()) { throw new RuntimeException("因爲參數不匹配,沒法調用 Action 方法!"); } } }
這是 ViewResolver
接口的默認實現:
<!-- lang: java --> /** * 默認視圖解析器 * * @author huangyong * @since 2.3 */ public class DefaultViewResolver implements ViewResolver { @Override public void resolveView(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult) { if (actionMethodResult != null) { // Action 返回值可爲 View 或 Result if (actionMethodResult instanceof View) { // 若爲 View,則需考慮兩種視圖類型(重定向 或 轉發) View view = (View) actionMethodResult; if (view.isRedirect()) { // 獲取路徑 String path = view.getPath(); // 重定向請求 WebUtil.redirectRequest(path, request, response); } else { // 獲取路徑 String path = FrameworkConstant.JSP_PATH + view.getPath(); // 初始化請求屬性 Map<String, Object> data = view.getData(); if (MapUtil.isNotEmpty(data)) { for (Map.Entry<String, Object> entry : data.entrySet()) { request.setAttribute(entry.getKey(), entry.getValue()); } } // 轉發請求 WebUtil.forwardRequest(path, request, response); } } else { // 若爲 Result,則需考慮兩種請求類型(文件上傳 或 普通請求) Result result = (Result) actionMethodResult; if (UploadHelper.isMultipart(request)) { // 對於 multipart 類型,說明是文件上傳,須要轉換爲 HTML 格式並寫入響應中 WebUtil.writeHTML(response, result); } else { // 對於其它類型,統一轉換爲 JSON 格式並寫入響應中 WebUtil.writeJSON(response, result); } } } } }
這是 HandlerExceptionResolver
接口的默認實現:
<!-- lang: java --> /** * 默認 Handler 異常解析器 * * @author huangyong * @since 2.3 */ public class DefaultHandlerExceptionResolver implements HandlerExceptionResolver { @Override public void resolveHandlerException(HttpServletRequest request, HttpServletResponse response, Exception e) { // 判斷異常緣由 Throwable cause = e.getCause(); if (cause instanceof AccessException) { // 分兩種狀況進行處理 if (WebUtil.isAJAX(request)) { // 跳轉到 403 頁面 WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response); } else { // 重定向到首頁 WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response); } } else if (cause instanceof PermissionException) { // 跳轉到 403 頁面 WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response); } else { // 跳轉到 500 頁面 WebUtil.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, cause.getMessage(), response); } } }
代碼量雖然有增無減,但這樣的結構更加清晰了,職責更加分明,便於往後的擴展與維護。看來快槍手真不是通常的神人啊!
這些實現類的代碼都來自於重構前的 DispatcherServlet
,這裏只是根據職責進行了分類,那麼如今的 DispatcherServlet
又是啥樣子呢?
最後給你們奉上重構後的 DispatcherServlet
:
<!-- lang: java --> /** * 前端控制器 * * @author huangyong * @since 1.0 */ @WebServlet(urlPatterns = "/*", loadOnStartup = 0) public class DispatcherServlet extends HttpServlet { private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class); private HandlerMapping handlerMapping = InstanceFactory.getHandlerMapping(); private HandlerInvoker handlerInvoker = InstanceFactory.getHandlerInvoker(); private HandlerExceptionResolver handlerExceptionResolver = InstanceFactory.getHandlerExceptionResolver(); @Override public void init(ServletConfig config) throws ServletException { // 初始化相關配置 ServletContext servletContext = config.getServletContext(); UploadHelper.init(servletContext); } @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 設置請求編碼方式 request.setCharacterEncoding(FrameworkConstant.UTF_8); // 獲取當前請求相關數據 String currentRequestMethod = request.getMethod(); String currentRequestPath = WebUtil.getRequestPath(request); logger.debug("[Smart] {}:{}", currentRequestMethod, currentRequestPath); // 將「/」請求重定向到首頁 if (currentRequestPath.equals("/")) { WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response); return; } // 去掉當前請求路徑末尾的「/」 if (currentRequestPath.endsWith("/")) { currentRequestPath = currentRequestPath.substring(0, currentRequestPath.length() - 1); } // 獲取 Handler Handler handler = handlerMapping.getHandler(currentRequestMethod, currentRequestPath); // 若未找到 Action,則跳轉到 404 頁面 if (handler == null) { WebUtil.sendError(HttpServletResponse.SC_NOT_FOUND, "", response); return; } // 初始化 DataContext DataContext.init(request, response); try { // 調用 Handler handlerInvoker.invokeHandler(request, response, handler); } catch (Exception e) { // 處理 Action 異常 handlerExceptionResolver.resolveHandlerException(request, response, e); } finally { // 銷燬 DataContext DataContext.destroy(); } } }
此時,只需在 DispatcherServlet
中調用 InstanceFactory
的相關方法,即可獲取相應的接口,代碼看起來也輕鬆了許多。
重構是一個永恆的話題,也是一件永無休止的事情,好代碼毫不是一開始就寫得出來的,必定是通過了反覆的重構,將不合理的地方變成更合理,之後有機會再與你們分享重構的心得與體會。
歡迎下載 Smart 源碼:
http://git.oschina.net/huangyong/smart
歡迎閱讀 Smart 博文: