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)-简单示例
目录
相关文章
|
2天前
|
存储 设计模式 数据库
构建高效的安卓应用:探究Android Jetpack架构组件
【4月更文挑战第20天】 在移动开发的世界中,构建一个既高效又可维护的安卓应用是每个开发者追求的目标。随着Android Jetpack的推出,Google为开发者提供了一套高质量的库、工具和指南,以简化应用程序开发流程。本文将深入探讨Jetpack的核心组件之一——架构组件,并展示如何将其应用于实际项目中,以提升应用的响应性和稳定性。我们将通过分析这些组件的设计原则,以及它们如何协同工作,来揭示它们对于构建现代化安卓应用的重要性。
|
2天前
|
存储 SQL 网络协议
C语言C/S架构PACS影像归档和通信系统源码 医院PACS系统源码
医院影像科PACS系统,意为影像归档和通信系统。它是应用在医院影像科室的系统,主要的任务是把日常产生的各种医学影像(包括核磁、CT、超声、各种X光机、各种红外仪、显微仪等设备产生的图像)通过各种接口(模拟、DICOM、网络)以数字化的方式海量保存起来,并在需要的时候在一定授权下能够快速地调回使用。同时,PACS系统还增加了一些辅助诊断管理功能。
40 11
|
2天前
|
存储 开发框架 前端开发
前端框架EXT.NET Dotnet 3.5开发的实验室信息管理系统(LIMS)成品源码 B/S架构
发展历史:实验室信息管理系统(LIMS),就是指通过计算机网络技术对实验的各种信息进行管理的计算机软、硬件系统。也就是将计算机网络技术与现代的管理思想有机结合,利用数据处理技术、海量数据存储技术、宽带传输网络技术、自动化仪器分析技术,来对实验室的信息管理和质量控制等进行全方位管理的计算机软、硬件系统,以满足实验室管理上的各种目标(计划、控制、执行)。
20 1
|
2天前
|
安全 数据管理 中间件
云LIS系统源码JavaScript+B/S架构MVC+SQLSugar医院版检验科云LIS系统源码 可提供演示
检验科云LIS系统源码是医疗机构信息化发展的重要趋势。通过云计算技术实现数据的集中管理和共享可以提高数据利用效率和安全性;通过高效灵活的系统设计和可扩展性可以满足不同医疗机构的需求;通过移动性和智能化可以提高医疗服务的精准度和效率;通过集成性可以实现医疗服务的协同性和效率。因此,多医院版检验科云LIS系统源码将成为未来医疗机构信息化发展的重要方向之一。
27 2
|
1天前
|
Java 关系型数据库 MySQL
java+B/S架构医院绩效考核管理系统源码 医院绩效管理系统4大特点
医院绩效考核管理系统,采用多维度综合绩效考核的形式,针对院内实际情况分别对工作量、KPI指标、科研、教学、管理等进行全面考核。医院可结合实际需求,对考核方案中各维度进行灵活配置,对各维度的权重、衡量标准、数据统计方式进行自定义维护。
10 0
|
2天前
|
前端开发 Java 数据库
MVC架构简述
MVC架构简述
11 4
|
2天前
|
Kubernetes API 调度
Kubernetes学习-核心概念篇(二) 集群架构与组件
Kubernetes学习-核心概念篇(二) 集群架构与组件
|
2天前
|
前端开发 Java 关系型数据库
Java医院绩效考核系统源码B/S架构+springboot三级公立医院绩效考核系统源码 医院综合绩效核算系统源码
作为医院用综合绩效核算系统,系统需要和his系统进行对接,按照设定周期,从his系统获取医院科室和医生、护士、其他人员工作量,对没有录入信息化系统的工作量,绩效考核系统设有手工录入功能(可以批量导入),对获取的数据系统按照设定的公式进行汇算,且设置审核机制,可以退回修正,系统功能强大,完全模拟医院实际绩效核算过程,且每步核算都可以进行调整和参数设置,能适应医院多种绩效核算方式。
31 2
|
2天前
|
存储 前端开发 Java
软件体系结构 - 架构风格(13)MVC架构风格
【4月更文挑战第21天】软件体系结构 - 架构风格(13)MVC架构风格
30 0
|
2天前
|
前端开发 Java PHP
信息系统架构模型(1) MVC
信息系统架构模型(1) MVC
23 0