MVC架构探究及其源码实现(5)-相关组件实现-阿里云开发者社区

开发者社区> james_zhan> 正文

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

简介:
+关注继续查看

博学,切问,近思--詹子知(http://blog.csdn.net/zhiqiangzhan)

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

URLHandlerMapping,利用request中包含的url信息,找到对应Handler对象,URLHandlerMapping是最典型的映射方式。 package com.google.mvc.web.servlet.handler; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Logger; import com.google.mvc.web.context.WebApplicationContext; import com.google.mvc.web.context.WebApplicationContextAware; import com.google.mvc.web.servlet.HandlerMapping; import com.google.mvc.web.servlet.mvc.Controller; import com.google.mvc.web.servlet.mvc.HttpRequestHandler; public class URLHandlerMapping implements HandlerMapping, WebApplicationContextAware{ private static final Logger LOGGER = Logger.getLogger(URLHandlerMapping.class); private WebApplicationContext wac; private Map<String, Object> handlerMap = new ConcurrentHashMap<String, Object>(); private AtomicBoolean initialize = new AtomicBoolean(false); @Override public void setWebApplicationContext(WebApplicationContext wac) { this.wac = wac; } @Override public Object getHandler(HttpServletRequest request) throws Exception { if(LOGGER.isDebugEnabled()){ LOGGER.debug("Find handler for request " + request.getServletPath()); } if(initialize.compareAndSet(false, true)){ Map<String, HttpRequestHandler> map1 = wac.beansOfType(HttpRequestHandler.class); for(String key : map1.keySet()){ handlerMap.put(key, map1.get(key)); } Map<String, Controller> map2 = wac.beansOfType(Controller.class); for(String key : map2.keySet()){ handlerMap.put(key, map2.get(key)); } } Object handler = handlerMap.get(getHandlerName(request)); if(handler == null){ handler = handlerMap.get("404"); } return handler; } protected String getHandlerName(HttpServletRequest request){ String path = request.getServletPath(); int index = path.lastIndexOf('/'); String handleName = path.substring(index + 1, path.length()); return handleName; } }

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

  1. Controller:用于处理用户的业务逻辑,并返回具体ModelAndView对象,具体接口定义如下 package com.google.mvc.web.servlet.mvc; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.mvc.web.servlet.ModelAndView; public interface Controller { ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; }
  2. HttpRequestHandler:用于处理简单的HTTP请求。接口定义如下 package com.google.mvc.web.servlet.mvc; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public interface HttpRequestHandler { void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; } 我们来看一下HandlerFor404的简单实现。 package com.google.mvc.web.servlet.mvc; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HandlerFor404 implements HttpRequestHandler { @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { response.sendRedirect("404.html"); } }
我们需要为每一种不同的Handler类型指定一种HandlerAdapter,但这不是必须的。
ControllerHandlerAdapter package com.google.mvc.web.servlet.mvc; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.mvc.web.servlet.HandlerAdapter; import com.google.mvc.web.servlet.ModelAndView; public class ControllerHandlerAdapter implements HandlerAdapter{ public boolean supports(Object handler) { return (handler instanceof Controller); } public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); } public long getLastModified(HttpServletRequest request, Object handler) { return -1L; } } HttpRequestHandlerAdapter package com.google.mvc.web.servlet.mvc; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.mvc.web.servlet.HandlerAdapter; import com.google.mvc.web.servlet.ModelAndView; public class HttpRequestHandlerAdapter implements HandlerAdapter { @Override public long getLastModified(HttpServletRequest request, Object handler) { return 0; } @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler) handler).handleRequest(request, response); return null; } @Override public boolean supports(Object handler) { return (handler instanceof HttpRequestHandler); } }

ViewResolver用于指定View的生成方式,我们先来看下AbstractView的定义 package com.google.mvc.web.servlet.mvc; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.google.mvc.web.servlet.View; public abstract class AbstractView implements View { private static final Logger LOGGER = Logger.getLogger(AbstractView.class); public static final String INCLUDE_REQUEST_URI_ATTRIBUTE = "javax.servlet.include.request_uri"; public static final String FORWARD_REQUEST_URI_ATTRIBUTE = "javax.servlet.forward.request_uri"; public static final String FORWARD_CONTEXT_PATH_ATTRIBUTE = "javax.servlet.forward.context_path"; public static final String FORWARD_SERVLET_PATH_ATTRIBUTE = "javax.servlet.forward.servlet_path"; public static final String FORWARD_PATH_INFO_ATTRIBUTE = "javax.servlet.forward.path_info"; public static final String FORWARD_QUERY_STRING_ATTRIBUTE = "javax.servlet.forward.query_string"; public static final String DEFAULT_CONTENT_TYPE = "text/html;charset=ISO-8859-1"; private String contentType = DEFAULT_CONTENT_TYPE; private boolean alwaysInclude = false; @Override public String getContentType() { return contentType; } protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request){ Iterator<Entry<String, Object>> it = model.entrySet().iterator(); while (it.hasNext()) { Entry<String, Object> entry = it.next(); String modelName = entry.getKey(); Object modelValue = entry.getValue(); if (modelValue != null) { request.setAttribute(modelName, modelValue); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() + "] to request in view with name '" + this + "'"); } } else { request.removeAttribute(modelName); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Removed model object '" + modelName + "' from request in view with name '" + this + "'"); } } } } protected boolean useInclude(HttpServletRequest request, HttpServletResponse response) { return (this.alwaysInclude || request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE) != null || response .isCommitted()); } protected void exposeForwardRequestAttributes(HttpServletRequest request) { exposeRequestAttributeIfNotPresent(request, FORWARD_REQUEST_URI_ATTRIBUTE, request.getRequestURI()); exposeRequestAttributeIfNotPresent(request, FORWARD_CONTEXT_PATH_ATTRIBUTE, request.getContextPath()); exposeRequestAttributeIfNotPresent(request, FORWARD_SERVLET_PATH_ATTRIBUTE, request.getServletPath()); exposeRequestAttributeIfNotPresent(request, FORWARD_PATH_INFO_ATTRIBUTE, request.getPathInfo()); exposeRequestAttributeIfNotPresent(request, FORWARD_QUERY_STRING_ATTRIBUTE, request.getQueryString()); } private void exposeRequestAttributeIfNotPresent(ServletRequest request, String name, Object value) { if (request.getAttribute(name) == null) { request.setAttribute(name, value); } } public void setContentType(String contentType) { this.contentType = contentType; } public boolean isAlwaysInclude() { return alwaysInclude; } public void setAlwaysInclude(boolean alwaysInclude) { this.alwaysInclude = alwaysInclude; } } 在这里我们仅实现一种View类型,也就是对jsp页面的简单处理。 package com.google.mvc.web.servlet.mvc; import java.io.IOException; import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; public class InternalResourceView extends AbstractView { private static final Logger LOGGER = Logger.getLogger(InternalResourceView.class); private String url; @Override public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Rendering view with name '" + this + "' with model " + model); } if(model != null){ exposeModelAsRequestAttributes(model, request); } RequestDispatcher rd = request.getRequestDispatcher(url); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + getUrl() + "]: check that this file exists within your WAR"); } if (useInclude(request, response)) { response.setContentType(getContentType()); rd.include(request, response); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Included resource [" + getUrl() + "] in InternalResourceView '" + url + "'"); } }else { exposeForwardRequestAttributes(request); rd.forward(request, response); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Forwarded to resource [" + getUrl() + "] in InternalResourceView '" + url + "'"); } } } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String toString(){ return this.url; } } 好了,到这里,我们再来看看ViewResolver类的实现 package com.google.mvc.web.servlet.mvc; import org.apache.log4j.Logger; import com.google.mvc.web.servlet.View; import com.google.mvc.web.servlet.ViewResolver; public class DefaultViewResolver implements ViewResolver { private static final Logger LOGGER = Logger.getLogger(DefaultViewResolver.class); private String prefix = ""; private String suffix = ""; private Class<View> viewClass; @Override public View resolveViewName(String viewName) throws Exception { View view = viewClass.newInstance(); if(view instanceof InternalResourceView){ ((InternalResourceView)view).setUrl(prefix + viewName + suffix); } return view; } public void setViewClass(String viewClass){ try { this.viewClass = (Class<View>) this.getClass().getClassLoader().loadClass(viewClass); } catch (ClassNotFoundException e) { LOGGER.error("Can't load view class " + viewClass, e); } } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getSuffix() { return suffix; } public void setSuffix(String suffix) { this.suffix = suffix; } }

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

相关文章:

  1. MVC架构探究及其源码实现(1)-理论基础
  2. MVC架构探究及其源码实现(2)-核心组件定义
  3. MVC架构探究及其源码实现(3)-WebApplicationContext
  4. MVC架构探究及其源码实现(4)-前端控制器
  5. MVC架构探究及其源码实现(6)-简单示例

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
《圣殿祭司的ASP.NET4.0专家技术手册》---- 1-14 项目同时使用C# 与VB语言及多组件的技巧
早期VS.NET 2002及VS.NET 2003的Visual Studio工具不支持多个组件文件(Assembly),也就是项目编译后只会产生一个dll组件,而一个组件只允许包含一种语言(因为系统会调用对应C#或VB编译程序进行编译),因此在同一个项目中要使用两种语言是办不到的;但在VS 2010中,因为项目支持多个组件,所以利用这个特性就可以同时使用两种以上的语言(如C#与VB),因此.cs或.vb的类别在项目中就可以直接拿来使用,直接就可以new instance,不需要先编译成dll文件再加以引用。
1418 0
Spring Boot中@ConfigurationProperties注解实现原理源码解析
本文简述@ConfigurationProperties注解实现原理源码及源码解析
1128 0
flash中扣头像组件
http://files.cnblogs.com/nasa/make_size.zip
494 0
[动态代理三部曲:下] - 从动态代理,看Retrofit的源码实现
前言 关于动态代理的系列文章,到此便进入了最后的“一出好戏”。前俩篇内容分别展开了:从源码上,了解JDK实现动态代理的原理;以及从动态代理切入,学会看class文件结构的含义。
1139 0
蚂蚁金服分布式链路跟踪组件 SOFATracer 中 Disruptor 实践(含源码)
本文对 SOFATracer 中使用 Disruptor 来进行日志输出的代码进行了简单的分析。
364 0
+关注
james_zhan
全栈工程师,程序设计语言控
34
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载