`

MVC架构探究及其源码实现(5)-相关组件实现

 
阅读更多

 

本文将讨论HandlerMapping,HandlerAdapter,ViewResolver组件类的具体实现。

URLHandlerMapping,利用request中包含的url信息,找到对应Handler对象,URLHandlerMapping是最典型的映射方式。

[java] view plaincopy
  1. package com.google.mvc.web.servlet.handler;  
  2.   
  3. import java.util.Map;  
  4. import java.util.concurrent.ConcurrentHashMap;  
  5. import java.util.concurrent.atomic.AtomicBoolean;  
  6.   
  7. import javax.servlet.http.HttpServletRequest;  
  8.   
  9. import org.apache.log4j.Logger;  
  10.   
  11. import com.google.mvc.web.context.WebApplicationContext;  
  12. import com.google.mvc.web.context.WebApplicationContextAware;  
  13. import com.google.mvc.web.servlet.HandlerMapping;  
  14. import com.google.mvc.web.servlet.mvc.Controller;  
  15. import com.google.mvc.web.servlet.mvc.HttpRequestHandler;  
  16.   
  17. public class URLHandlerMapping implements HandlerMapping, WebApplicationContextAware{  
  18.   
  19.     private static final Logger LOGGER = Logger.getLogger(URLHandlerMapping.class);  
  20.     private WebApplicationContext wac;  
  21.     private Map<String, Object> handlerMap = new ConcurrentHashMap<String, Object>();  
  22.     private AtomicBoolean initialize = new AtomicBoolean(false);  
  23.   
  24.     @Override  
  25.     public void setWebApplicationContext(WebApplicationContext wac) {  
  26.         this.wac = wac;               
  27.     }  
  28.   
  29.     @Override  
  30.     public Object getHandler(HttpServletRequest request) throws Exception {   
  31.         if(LOGGER.isDebugEnabled()){  
  32.             LOGGER.debug("Find handler for request " + request.getServletPath());  
  33.         }  
  34.                   
  35.         if(initialize.compareAndSet(falsetrue)){  
  36.             Map<String, HttpRequestHandler> map1 = wac.beansOfType(HttpRequestHandler.class);  
  37.             for(String key : map1.keySet()){  
  38.                 handlerMap.put(key, map1.get(key));  
  39.             }  
  40.             Map<String, Controller> map2 = wac.beansOfType(Controller.class);  
  41.             for(String key : map2.keySet()){  
  42.                 handlerMap.put(key, map2.get(key));  
  43.             }  
  44.         }         
  45.         Object handler = handlerMap.get(getHandlerName(request));  
  46.         if(handler == null){  
  47.             handler = handlerMap.get("404");  
  48.         }  
  49.         return handler;  
  50.     }  
  51.       
  52.     protected String getHandlerName(HttpServletRequest request){  
  53.         String path = request.getServletPath();  
  54.         int index = path.lastIndexOf('/');  
  55.         String handleName = path.substring(index + 1, path.length());  
  56.         return handleName;  
  57.     }  
  58.   
  59. }  

 

HandlerAdapter用于把不同的Handler对象处理的结果封装成一个统一的对象ModelAndView,以达到逻辑上的一致处理。在这里,我们定义两种Handler类型

  1. Controller:用于处理用户的业务逻辑,并返回具体ModelAndView对象,具体接口定义如下
    [java] view plaincopy
    1. package com.google.mvc.web.servlet.mvc;  
    2.   
    3. import javax.servlet.http.HttpServletRequest;  
    4. import javax.servlet.http.HttpServletResponse;  
    5.   
    6. import com.google.mvc.web.servlet.ModelAndView;  
    7.   
    8. public interface Controller {  
    9.       
    10.     ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;  
    11. }  
  2. HttpRequestHandler:用于处理简单的HTTP请求。接口定义如下
    [java] view plaincopy
    1. package com.google.mvc.web.servlet.mvc;  
    2.   
    3. import javax.servlet.http.HttpServletRequest;  
    4. import javax.servlet.http.HttpServletResponse;  
    5.   
    6.   
    7. public interface HttpRequestHandler {  
    8.       
    9.     void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;  
    10.   
    11. }  
    我们来看一下HandlerFor404的简单实现。
    [java] view plaincopy
    1. package com.google.mvc.web.servlet.mvc;  
    2.   
    3. import javax.servlet.http.HttpServletRequest;  
    4. import javax.servlet.http.HttpServletResponse;  
    5.   
    6. public class HandlerFor404 implements HttpRequestHandler {  
    7.   
    8.     @Override  
    9.     public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {  
    10.         response.sendRedirect("404.html");  
    11.     }  
    12.   
    13. }  

我们需要为每一种不同的Handler类型指定一种HandlerAdapter,但这不是必须的。
ControllerHandlerAdapter

[java] view plaincopy
  1. package com.google.mvc.web.servlet.mvc;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpServletResponse;  
  5.   
  6. import com.google.mvc.web.servlet.HandlerAdapter;  
  7. import com.google.mvc.web.servlet.ModelAndView;  
  8.   
  9.   
  10. public class ControllerHandlerAdapter implements HandlerAdapter{  
  11.       
  12.     public boolean supports(Object handler) {  
  13.         return (handler instanceof Controller);  
  14.     }  
  15.   
  16.     public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
  17.             throws Exception {  
  18.   
  19.         return ((Controller) handler).handleRequest(request, response);  
  20.     }  
  21.   
  22.     public long getLastModified(HttpServletRequest request, Object handler) {  
  23.       
  24.         return -1L;  
  25.     }  
  26.   
  27. }  

HttpRequestHandlerAdapter

[java] view plaincopy
  1. package com.google.mvc.web.servlet.mvc;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpServletResponse;  
  5.   
  6. import com.google.mvc.web.servlet.HandlerAdapter;  
  7. import com.google.mvc.web.servlet.ModelAndView;  
  8.   
  9. public class HttpRequestHandlerAdapter implements HandlerAdapter {  
  10.   
  11.     @Override  
  12.     public long getLastModified(HttpServletRequest request, Object handler) {         
  13.         return 0;  
  14.     }  
  15.   
  16.     @Override  
  17.     public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
  18.             throws Exception {  
  19.         ((HttpRequestHandler) handler).handleRequest(request, response);  
  20.         return null;  
  21.     }  
  22.   
  23.     @Override  
  24.     public boolean supports(Object handler) {         
  25.         return (handler instanceof HttpRequestHandler);  
  26.     }  
  27. }  

 

ViewResolver用于指定View的生成方式,我们先来看下AbstractView的定义

[java] view plaincopy
  1. package com.google.mvc.web.servlet.mvc;  
  2.   
  3. import java.util.Iterator;  
  4. import java.util.Map;  
  5. import java.util.Map.Entry;  
  6.   
  7. import javax.servlet.ServletRequest;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10.   
  11. import org.apache.log4j.Logger;  
  12.   
  13. import com.google.mvc.web.servlet.View;  
  14.   
  15. public abstract class AbstractView implements View {  
  16.       
  17.     private static final Logger LOGGER = Logger.getLogger(AbstractView.class);  
  18.       
  19.     public static final String INCLUDE_REQUEST_URI_ATTRIBUTE = "javax.servlet.include.request_uri";  
  20.     public static final String FORWARD_REQUEST_URI_ATTRIBUTE = "javax.servlet.forward.request_uri";  
  21.     public static final String FORWARD_CONTEXT_PATH_ATTRIBUTE = "javax.servlet.forward.context_path";  
  22.     public static final String FORWARD_SERVLET_PATH_ATTRIBUTE = "javax.servlet.forward.servlet_path";  
  23.     public static final String FORWARD_PATH_INFO_ATTRIBUTE = "javax.servlet.forward.path_info";  
  24.     public static final String FORWARD_QUERY_STRING_ATTRIBUTE = "javax.servlet.forward.query_string";  
  25.     public static final String DEFAULT_CONTENT_TYPE = "text/html;charset=ISO-8859-1";     
  26.     private String contentType = DEFAULT_CONTENT_TYPE;    
  27.     private boolean alwaysInclude = false;    
  28.   
  29.     @Override  
  30.     public String getContentType() {          
  31.         return contentType;  
  32.     }     
  33.       
  34.     protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request){  
  35.         Iterator<Entry<String, Object>> it = model.entrySet().iterator();  
  36.         while (it.hasNext()) {  
  37.             Entry<String, Object> entry = it.next();  
  38.               
  39.             String modelName = entry.getKey();  
  40.             Object modelValue = entry.getValue();  
  41.             if (modelValue != null) {  
  42.                 request.setAttribute(modelName, modelValue);  
  43.                 if (LOGGER.isDebugEnabled()) {  
  44.                     LOGGER.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +  
  45.                             "] to request in view with name '" + this + "'");  
  46.                 }  
  47.             } else {  
  48.                 request.removeAttribute(modelName);  
  49.                 if (LOGGER.isDebugEnabled()) {  
  50.                     LOGGER.debug("Removed model object '" + modelName + "' from request in view with name '"   
  51.                             + this + "'");  
  52.                 }  
  53.             }  
  54.         }  
  55.           
  56.     }  
  57.   
  58.     protected boolean useInclude(HttpServletRequest request, HttpServletResponse response) {  
  59.         return (this.alwaysInclude || request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE) != null || response  
  60.                 .isCommitted());  
  61.     }  
  62.       
  63.     protected void exposeForwardRequestAttributes(HttpServletRequest request) {  
  64.         exposeRequestAttributeIfNotPresent(request, FORWARD_REQUEST_URI_ATTRIBUTE, request.getRequestURI());  
  65.         exposeRequestAttributeIfNotPresent(request, FORWARD_CONTEXT_PATH_ATTRIBUTE, request.getContextPath());  
  66.         exposeRequestAttributeIfNotPresent(request, FORWARD_SERVLET_PATH_ATTRIBUTE, request.getServletPath());  
  67.         exposeRequestAttributeIfNotPresent(request, FORWARD_PATH_INFO_ATTRIBUTE, request.getPathInfo());  
  68.         exposeRequestAttributeIfNotPresent(request, FORWARD_QUERY_STRING_ATTRIBUTE, request.getQueryString());  
  69.     }  
  70.       
  71.     private void exposeRequestAttributeIfNotPresent(ServletRequest request, String name, Object value) {  
  72.         if (request.getAttribute(name) == null) {  
  73.             request.setAttribute(name, value);  
  74.         }  
  75.     }  
  76.   
  77.     public void setContentType(String contentType) {  
  78.         this.contentType = contentType;  
  79.     }  
  80.       
  81.     public boolean isAlwaysInclude() {  
  82.         return alwaysInclude;  
  83.     }  
  84.   
  85.     public void setAlwaysInclude(boolean alwaysInclude) {  
  86.         this.alwaysInclude = alwaysInclude;  
  87.     }  
  88. }  

在这里我们仅实现一种View类型,也就是对jsp页面的简单处理。

[java] view plaincopy
  1. package com.google.mvc.web.servlet.mvc;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Map;  
  5.   
  6. import javax.servlet.RequestDispatcher;  
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10.   
  11. import org.apache.log4j.Logger;  
  12.   
  13. public class InternalResourceView extends AbstractView {  
  14.   
  15.     private static final Logger LOGGER = Logger.getLogger(InternalResourceView.class);  
  16.     private String url;  
  17.       
  18.     @Override  
  19.     public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {          
  20.         if (LOGGER.isDebugEnabled()) {  
  21.             LOGGER.debug("Rendering view with name '" + this + "' with model " + model);  
  22.         }     
  23.           
  24.         if(model != null){  
  25.             exposeModelAsRequestAttributes(model, request);       
  26.         }  
  27.           
  28.         RequestDispatcher rd = request.getRequestDispatcher(url);  
  29.         if (rd == null) {  
  30.             throw new ServletException("Could not get RequestDispatcher for ["   
  31.                     + getUrl() + "]: check that this file exists within your WAR");  
  32.         }  
  33.           
  34.         if (useInclude(request, response)) {  
  35.             response.setContentType(getContentType());  
  36.             rd.include(request, response);  
  37.             if (LOGGER.isDebugEnabled()) {  
  38.                 LOGGER.debug("Included resource [" + getUrl() + "] in InternalResourceView '" + url + "'");  
  39.             }  
  40.         }else {  
  41.             exposeForwardRequestAttributes(request);  
  42.             rd.forward(request, response);  
  43.             if (LOGGER.isDebugEnabled()) {  
  44.                 LOGGER.debug("Forwarded to resource [" + getUrl() + "] in InternalResourceView '" + url + "'");  
  45.             }  
  46.         }         
  47.     }     
  48.       
  49.     public String getUrl() {  
  50.         return url;  
  51.     }  
  52.   
  53.     public void setUrl(String url) {  
  54.         this.url = url;  
  55.     }  
  56.       
  57.     public String toString(){  
  58.         return this.url;  
  59.     }  
  60.   
  61. }  

好了,到这里,我们再来看看ViewResolver类的实现

[java] view plaincopy
  1. package com.google.mvc.web.servlet.mvc;  
  2.   
  3. import org.apache.log4j.Logger;  
  4.   
  5. import com.google.mvc.web.servlet.View;  
  6. import com.google.mvc.web.servlet.ViewResolver;  
  7.   
  8. public class DefaultViewResolver implements ViewResolver  
  9. {  
  10.     private static final Logger LOGGER = Logger.getLogger(DefaultViewResolver.class);  
  11.     private String prefix = "";  
  12.     private String suffix = "";  
  13.     private Class<View> viewClass;  
  14.   
  15.     @Override  
  16.     public View resolveViewName(String viewName) throws Exception {  
  17.         View view = viewClass.newInstance();  
  18.         if(view instanceof InternalResourceView){  
  19.             ((InternalResourceView)view).setUrl(prefix + viewName + suffix);  
  20.         }  
  21.         return view;  
  22.     }  
  23.       
  24.     public void setViewClass(String viewClass){  
  25.         try {  
  26.             this.viewClass = (Class<View>) this.getClass().getClassLoader().loadClass(viewClass);  
  27.         } catch (ClassNotFoundException e) {              
  28.             LOGGER.error("Can't load view class " + viewClass, e);  
  29.         }  
  30.     }  
  31.   
  32.     public String getPrefix() {  
  33.         return prefix;  
  34.     }  
  35.   
  36.     public void setPrefix(String prefix) {  
  37.         this.prefix = prefix;  
  38.     }  
  39.   
  40.     public String getSuffix() {  
  41.         return suffix;  
  42.     }  
  43.   
  44.     public void setSuffix(String suffix) {  
  45.         this.suffix = suffix;  
  46.     }  
  47. }  

 

到这里,我们在整个MVC架构的源码实现已经完成了,下一篇,我们将介绍一个基于我们这个MVC架构的Demo。

文章来源:http://blog.csdn.net/zhiqiangzhan/article/details/4768172

 

分享到:
评论

相关推荐

    MVC经典后台管理系统源码-经典必备

    1. **架构设计**:了解整体架构,如MVC组件间的交互方式,以及系统是如何组织和划分职责的。 2. **路由机制**:研究如何通过URL映射到相应的控制器和方法,理解请求的处理流程。 3. **模板引擎**:查看视图层是...

    struts-2.1.8.1源码和struts-2.3.15.1源码

    通过对比这两个版本的源码,开发者可以深入了解Struts 2框架的设计理念,学习如何实现Action、Interceptor、Result等核心组件,以及如何利用OGNL进行数据绑定。同时,分析版本间的差异有助于理解框架的发展趋势和...

    企业Java企业进销存管理系统源码-jxc-j

    1. **源代码文件夹**:包括了系统的所有Java源代码,这些代码可能按照MVC(Model-View-Controller)架构组织,分为模型、视图和控制器三个部分,用于实现业务逻辑、数据展示和用户交互。 2. **数据库脚本**:系统...

    官方原版源码spring-framework-5.1.2.RELEASE.zip

    5. **Spring的事件驱动模型**:了解Spring如何通过ApplicationEvent和ApplicationListener实现组件间的异步通信。 6. **Spring的模块化设计**:研究不同模块(如core-container、data-access、web)之间的依赖关系...

    官方原版源码spring-framework-5.1.13.RELEASE.zip

    官方原版源码spring-framework-5.1.13.RELEASE.zip为我们提供了深入了解这一框架的机会,让我们能够探究其内部工作机制,提升开发技能。 1. **Spring Framework概述** Spring Framework是Java应用程序开发的一个...

    官方源码spring-framework-5.0.15.RELEASE.zip

    特别地,Spring MVC是Spring用于构建Web应用的重要组件,它通过DispatcherServlet、HandlerMapping、ViewResolver等机制实现了请求的路由和视图的渲染。 四、模块扩展 - Spring Framework 5.0引入了Reactive编程...

    PHP经典源码-餐饮小程序 V5.8.0.rar

    1. 架构设计:了解整体架构,包括MVC(模型-视图-控制器)模式的应用,以及各模块间的交互。 2. 数据库设计:查看数据库表结构,理解如何存储和管理菜单、订单、用户信息等数据。 3. API接口:研究与第三方支付平台...

    官方原版源码spring-framework-5.0.13.RELEASE.zip

    5. **Web模块**:提供了MVC(Model-View-Controller)架构,用于构建Web应用程序。 三、源码结构分析 在解压后的文件中,我们看到三个主要的子文件: - **spring-framework-5.0.13.RELEASE-dist.zip**:包含...

    官方原版源码spring-framework-5.1.14.RELEASE.zip

    《深入剖析Spring Framework 5.1.14源码》 Spring Framework作为Java开发领域中的基石,其核心...通过阅读和学习源码,我们可以深入探究DI、AOP、Web MVC、数据访问等核心概念,提升我们的编程技巧和解决问题的能力。

    IOS应用源码之cesarvargas00-NoSoEnchantedForest-63e08b3.zip

    这个项目的名称可能暗示着它是一个基于森林主题的游戏或者互动故事应用,但具体的功能和设计,我们需要通过源码来深入探究。 首先,我们要明白iOS应用的基本构建块。一个标准的iOS应用通常由多个部分组成,包括...

    Vue 技术栈 带你探究 vue-router 源码 手写vue-router

    Vue.js 是一款流行的前端框架,Vue Router 是 Vue.js 生态中的官方路由库,它负责管理单页应用(SPA,...随着对 Vue Router 源码的深入探究,我们也将对前端架构有更深刻的认识,为未来的项目开发打下坚实的基础。

    spring源码注释中文

    Spring MVC 提供了一个灵活的架构,支持多种视图技术,如 JSP、FreeMarker 和 Velocity。 4. **AOP(面向切面编程)**:Spring 的 AOP 模块提供了面向切面编程的实现,允许开发者定义方法拦截器和切入点,以实现如...

    Android 新浪微博客户端源码.rar

    这份源码提供了实现一个完整的社交媒体应用的实际案例,让我们有机会探究其背后的架构设计、功能实现以及优化策略。下面,我们将对这个项目进行详细的分析。 1. **整体架构** - **MVC/MVVM模式**:源码可能采用了...

    spring-framework4.2x源码

    - **MVC(Model-View-Controller)**:Spring MVC是Web开发的重要部分,源码中涉及DispatcherServlet、HandlerMapping、ViewResolver等组件,理解它们的工作原理对于Web应用的开发至关重要。 - **事务管理**:...

    spring-framework-2.5.4源码.rar

    这个压缩包"spring-framework-2.5.4源码.rar"包含了Spring框架的核心组件和相关源代码,特别是"src"目录下的文件,这将使我们有机会探究Spring如何处理IoC(Inversion of Control)、AOP(Aspect Oriented ...

    dist-flatboard-v1.2 源码

    AngularJS通过MVC(模型-视图-控制器)架构模式,实现了数据绑定和依赖注入,极大地提高了Web应用的开发效率。在dist-flatboard-v1.2中,AngularJS被用来管理应用的状态,实现动态数据渲染和交互功能。通过双向数据...

    backbone 源码+API

    学习Backbone.js,开发者需要理解MVC架构的原理,掌握事件驱动编程和数据绑定的概念。同时,对JavaScript原型链、闭包以及异步操作的理解也是必不可少的。通过阅读源码和API文档,开发者可以学习到如何有效地组织...

    spring源码下载

    5. **注解驱动编程**:探究@Component、@Service、@Repository和@Controller等注解的解析过程,以及Autowired和Qualifier的工作原理。 6. **事务管理**:研究PlatformTransactionManager接口和相关的事务策略,理解...

    基于Java+JSP的病历管理系统毕业设计实现+源码毕业设计实现+源码.rar

    3. **MVC(Model-View-Controller)架构**: 常见于Web应用开发,用于分离业务逻辑、数据模型和用户界面。在这个系统中,Model处理数据,View展示信息,Controller协调Model和View的交互。 4. **Servlet**: 虽然未...

    教你阅读Spring源码资源.zip

    同时,结合JDK库的使用,可以深入探究Spring如何利用Java的特性来实现其强大的功能。 总的来说,这个压缩包为学习Spring源码提供了一套完整的资源。从IoC到AOP,从数据访问到Web开发,通过调试代码和实例,我们可以...

Global site tag (gtag.js) - Google Analytics