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月前
|
消息中间件 Java Kafka
Java 事件驱动架构设计实战与 Kafka 生态系统组件实操全流程指南
本指南详解Java事件驱动架构与Kafka生态实操,涵盖环境搭建、事件模型定义、生产者与消费者实现、事件测试及高级特性,助你快速构建高可扩展分布式系统。
157 7
|
6月前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
204 5
|
3月前
|
运维 安全 数据可视化
采用PHP+Vue技术架构的不良事件管理系统(源码)
本系统为医院安全(不良)事件管理工具,支持快速上报、流程化处理与多维度分析,助力识别风险、优化管理。采用PHP+Vue技术架构,功能涵盖事件上报、追踪整改、数据统计及PDCA改进等。
121 0
|
3月前
|
JSON 前端开发 Java
Spring MVC 核心组件与请求处理机制详解
本文解析了 Spring MVC 的核心组件及请求流程,核心组件包括 DispatcherServlet(中央调度)、HandlerMapping(URL 匹配处理器)、HandlerAdapter(执行处理器)、Handler(业务方法)、ViewResolver(视图解析),其中仅 Handler 需开发者实现。 详细描述了请求执行的 7 步流程:请求到达 DispatcherServlet 后,经映射器、适配器找到并执行处理器,再通过视图解析器渲染视图(前后端分离下视图解析可省略)。 介绍了拦截器的使用(实现 HandlerInterceptor 接口 + 配置类)及与过滤器的区别
214 0
|
11月前
|
存储 前端开发 调度
Flux 与传统的 MVC 架构模式区别
Flux是一种用于构建用户界面的架构模式,与传统的MVC架构不同,它采用单向数据流,通过Dispatcher统一管理数据的分发,Store负责存储数据和业务逻辑,View只负责展示数据,使得应用状态更加可预测和易于维护。
|
12月前
|
消息中间件 存储 Java
RocketMQ(一):消息中间件缘起,一览整体架构及核心组件
【10月更文挑战第15天】本文介绍了消息中间件的基本概念和特点,重点解析了RocketMQ的整体架构和核心组件。消息中间件如RocketMQ、RabbitMQ、Kafka等,具备异步通信、持久化、削峰填谷、系统解耦等特点,适用于分布式系统。RocketMQ的架构包括NameServer、Broker、Producer、Consumer等组件,通过这些组件实现消息的生产、存储和消费。文章还提供了Spring Boot快速上手RocketMQ的示例代码,帮助读者快速入门。
|
7月前
|
运维 供应链 前端开发
中小医院云HIS系统源码,系统融合HIS与EMR功能,采用B/S架构与SaaS模式,快速交付并简化运维
这是一套专为中小医院和乡镇卫生院设计的云HIS系统源码,基于云端部署,采用B/S架构与SaaS模式,快速交付并简化运维。系统融合HIS与EMR功能,涵盖门诊挂号、预约管理、一体化电子病历、医生护士工作站、收费财务、药品进销存及统计分析等模块。技术栈包括前端Angular+Nginx,后端Java+Spring系列框架,数据库使用MySQL+MyCat。该系统实现患者管理、医嘱处理、费用结算、药品管控等核心业务全流程数字化,助力医疗机构提升效率和服务质量。
364 4
|
7月前
|
人工智能 前端开发 Java
DDD四层架构和MVC三层架构的个人理解和学习笔记
领域驱动设计(DDD)是一种以业务为核心的设计方法,与传统MVC架构不同,DDD将业务逻辑拆分为应用层和领域层,更关注业务领域而非数据库设计。其四层架构包括:Interface(接口层)、Application(应用层)、Domain(领域层)和Infrastructure(基础层)。各层职责分明,避免跨层调用,确保业务逻辑清晰。代码实现中,通过DTO、Entity、DO等对象的转换,结合ProtoBuf协议,完成请求与响应的处理流程。为提高复用性,实际项目中可增加Common层存放公共依赖。DDD强调从业务出发设计软件,适应复杂业务场景,是微服务架构的重要设计思想。
|
7月前
|
消息中间件 安全 NoSQL
布谷直播系统源码开发实战:从架构设计到性能优化
作为山东布谷科技的一名技术研发人员,我参与了多个直播系统平台从0到1的开发和搭建,也见证了直播行业从萌芽到爆发的全过程。今天,我想从研发角度,分享一些直播系统软件开发的经验和心得,希望能对大家有所帮助。
|
9月前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
316 7

热门文章

最新文章