`

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

 

分享到:
评论

相关推荐

    Spring技术内幕:深入解析Spring架构与设计原理(第2部分)

    你不仅能从木书中参透Spring框架的优秀架构和设计思想,而且还能从Spring优雅的实现源码中一窥Java语言的精髓。此外,《Spring技术内幕:深入解析Spring架构与设计原理》还展示了阅读源代码的卓越方法,不仅授你以鱼...

    Spring技术内幕:深入解析Spring架构与设计原理

    你不仅能从木书中参透spring框架的优秀架构和设计思想,而且还能从spring优雅的实现源码中一窥java语言的精髓。此外,本书还展示了阅读源代码的卓越方法,不仅授你以鱼,而且还授你以渔!..  如果你以一种淡定的...

    Spring技术内幕:深入解析Spring架构与设计原理 1/2

    你不仅能从木书中参透spring框架的优秀架构和设计思想,而且还能从spring优雅的实现源码中一窥java语言的精髓。此外,本书还展示了阅读源代码的卓越方法,不仅授你以鱼,而且还授你以渔!..  如果你以一种淡定的心态...

    Spring技术内幕:深入解析Spring架构与设计原理(第1部分)

    你不仅能从木书中参透Spring框架的优秀架构和设计思想,而且还能从Spring优雅的实现源码中一窥Java语言的精髓。此外,《Spring技术内幕:深入解析Spring架构与设计原理》还展示了阅读源代码的卓越方法,不仅授你以鱼...

    Spring技术内幕:深入解析Spring架构与设计原理(第一部分)

    你不仅能从木书中参透Spring框架的优秀架构和设计思想,而且还能从Spring优雅的实现源码中一窥Java语言的精髓。此外,《Spring技术内幕:深入解析Spring架构与设计原理》还展示了阅读源代码的卓越方法,不仅授你以鱼...

    Spring技术内幕:深入解析Spring架构与设计原理 2/2

    你不仅能从木书中参透spring框架的优秀架构和设计思想,而且还能从spring优雅的实现源码中一窥java语言的精髓。此外,本书还展示了阅读源代码的卓越方法,不仅授你以鱼,而且还授你以渔!..  如果你以一种淡定的...

    SPRING3技术内幕

    你不仅能从木书中参透Spring框架的优秀架构和设计思想,而且还能从Spring优雅的实现源码中一窥Java语言的精髓。此外,《Spring技术内幕:深入解析Spring架构与设计原理》还展示了阅读源代码的卓越方法,不仅授你以鱼...

    SPRING3技术内幕.z01

    你不仅能从木书中参透Spring框架的优秀架构和设计思想,而且还能从Spring优雅的实现源码中一窥Java语言的精髓。此外,《Spring技术内幕:深入解析Spring架构与设计原理》还展示了阅读源代码的卓越方法,不仅授你以鱼...

    Spring技术内幕

    你不仅能从木书中参透Spring框架的优秀架构和设计思想,而且还能从Spring优雅的实现源码中一窥Java语言的精髓。此外,本书还展示了阅读源代码的卓越方法,不仅授你以鱼,而且还授你以渔!, 如果你以一种淡定的心态...

Global site tag (gtag.js) - Google Analytics