BEGIN
看过上一篇关于Spring框架的介绍后(点击查看Spring介绍),相信对于Spring已经有了整体的认知,接下来的文章我会对他的主要家族成员逐一做些介绍。
本文介绍的对象是–SpringMvc,仔细回想下这个框架的组成,不难发现它有专门的一块内容是来整合Web组件(右上角),它就在这里面,让我们来一起看下吧。
1、MVC
老生常谈的一个东西了,它的出现就摒弃原来一个jsp页面搞定所有事(UI、业务逻辑、数据交互等)的状况,做到各个层级分工协作,各司其职。View层处理前端UI展示,Model层用来处理业务逻辑,Control层则是用来协调和调度M和V,使得用户界面和业务处理分开,让我们的编码更加灵活、代码/模块的复用性也大大的提高、同时降低耦合提升整体应用程序的可维护性。
SpringMvc就是基于Mvc的一套前端web框架,他具有MVC的特征又得益于Spring的加持,所以它注定是一个优秀的框架。
如上图,是整个SpringMVC的一个模式总览,这里面占C位的就是我们的DispatcherServlet,负责来协调和调用不同组件进行工作,从而响应前端的请求。M位的由我们的后端控制器承担,处理业务/事务,V通过ViewResolver来定位解析视图。
讲到MVC一定会联想到struct2,struct2同样作为一个历史悠久的MVC框架,又有像SSH等框架的实际应用,它的地位不言而喻。那么它和SpringMVC有什么区别呢?
- 基于的对象不一样。struts2是类级别开发的,一个类对应一个request上下文,而SpringMvc是基于方法级别的,一个方法对应一个request上下文。
- 由于Spring的“零”配置特性,SpringMvc只要少量的配置
- SpringMvc的效率会稍优
2、核心组件
DispatcherServlet
作用:框架的核心,前端控制器负责接收和响应用户的请求以及协调各个模块组件,降低组件之间的耦合度
配置:web.xml中配置,在系统启动时进行加载
HandlerMapping
作用:根据用户访问或请求的 URL去查找的Handler对象
实现:在spring-mvc.xml中进行配置
方式:框架提供多种的映射处理器来实现不同的映射:XML配置(配置繁杂)、实现接口、注解等
HandlerExecutionChain
作用:Handler执行链象,包括 Handler对象、拦截器等,用来处理和拦截相应的内容。
实现:无需配置,DispatcherServlet中会进行获取和遍历。如需拦截器进行相应拦截器的配置即可
HandlerAdapter
作用:让固定的Servlet来进行灵活的Handler的调用。就是将二者进行适配
实现:在spring-mvc.xml中进行配置
Handler
作用:主要是负责处理用户请求,当然其中还包括了像数据持久化的操作等等
实现:就是我们平常编写的Controller类
方式:最常用的方法就是添加@Controller的注解
ModelAndView、View
作用:逻辑视图和具体的实体对象,前者携带逻辑视图名,后者为具体的视图对象,前者通过渲染将逻辑参数填充到模板中,生成View再响应给用户
实现:View可以是jsp、pdf、freemarker、excel对象等等
ViewResolver
作用:进行视图解析,将逻辑视图名解析到具体的View
实现:在spring-mvc.xml中进行配置
3、核心流程
如上图,让我们来分析下整个的请求与响应流程
1、终端用户发起请求(浏览网站、请求数据等),请求会由核心控制器(DispatchServlet)接受
2、核心控制器(DispatchServlet)会调用处理器映射器(HandlerMapping)进行Url映射
3、处理器映射器(HandlerMapping)找出相应的处理执行链(HandlerExecutionChain)返回给控制器(DispatchServlet),链中包含有具体处理器、拦截器等
4、核心控制器(DispatchServlet)继续调用处理器适配器(HandlerAdapter)
5、处理器适配器(HandlerAdapter)进行处理器的适配后调用具体的处理器(Handler/Controller)
6、处理器(Handler、Controller)执行完后会返回模型视图(ModelAndView)对象给到适配器
7、处理器适配器(HandlerAdapter)将模型视图(ModelAndView)进一步传递返回给核心控制器(DispatchServlet)
8、核心控制器(DispatchServlet)将模型视图(ModelAndView)交给视图解析器(ViewResolver)请求进一步的解析
9、视图解析器(ViewReslover)解析后返回具体视图(View)给核心控制器(DispatchServlet)
10、核心控制器再对视图(View)进行进一步的渲染,将模型数据填充到页面或模板中,得到最终的视图对象
11、渲染后的视图(View)会响应给终端的用户完成整个的请求过程
上面这个整套的流程相信大家都应该看过不止一遍,因为毕竟我也是站在这么多巨人的肩膀上而进行文章的编写,所以不管是哪里的博文,只要是涉及到SpringMvc的原理都会有类似的图呈现出来, 而接下来我们再来看看他的部分核心源码以加深理解吧。
4、核心源码
既然占着C位的是DispatchServlet那么,我们就来简单地分析下它的源码吧
显然作为起源来说它来自HttpServlet,中间的两层HttpServletBean和FrameworkServlet是针对Servlet的基础上做了一些的初始化的操作。
HttpServletBean中通过init()初始化一些init-param标签中配置的参数
FrameworkServlet中通过initServletBean()初始化上下文的内容
再到DispatchServlet,首先它也会进行初始化的操作如下图所示,当触发刷新时将会执行以下初始化的工作
除了这些组件外它还会进行像:配置文件、扫描并实例化Bean到IoC容器中等等。
初始化完成应用程序启动后,当Servlet接收到请求后那么首先肯定会调用到我们的doGet或doPost方法了,这两个方法在FrameworkServlet中会将具体的逻辑交由doService来进行处理,如下图:
doService的方法在DispatchServlet中又得到了进一步的重写进而调用doDispatch方法
那么重点来了,doDispatch 就是我们要特别关注的重点,整个的SpringMvc的任务分发都是在这边完成的,如下图:
核心的三步曲已经被我框出来了,HandlerExecutionChain的获取以及通过适配器进行逻辑视图对象的获取,再到最后的视图的解析构成这幅艺术家的画卷
有兴趣了解各个方法内部实现的可以到相应的方法内部进行查看!
5、关键配置
我贴出一些我平时用到的关于Spring的关键配置,一个是方便自己后续索引,再来就是为广大的Developer分享。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>smvc</display-name>
<listener>
<description>spring日志监听器</description>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<description>spring监听器</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<description>request监听器</description>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<description>系统初始化监听器</description>
<listener-class>org.jeecgframework.web.system.listener.InitListener</listener-class>
</listener>
<!-- 核心控制器 -->
<servlet>
<description>spring mvc servlet</description>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<description>spring mvc 配置文件</description>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!-- restUrl风格配置 -->
<servlet>
<servlet-name>restSpringMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<description>spring mvc 配置文件</description>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>restSpringMvc</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
spring-mvc.xml的部分配置:
<!-- 自动扫描controller包下的所有类 -->
<context:component-scan base-package="com.*.*">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
<!-- IE执行AJAX时配置 -->
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>text/json;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- 注册RequestMappingHandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!-- 默认的视图解析器- -->
<bean id="defaultViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:order="3">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="contentType" value="text/html" />
<property name="prefix" value="/webpage/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="UTF-8">
<property name="maxUploadSize">
<value>104857600</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
<!-- Bean解析器 -->
<bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="0" />
6、常用注解
- @Controller 控制器类
- @RequestMapping 指定URL请求的路径,以供映射器检索
- @RequestBody 读取Request请求的body部分数据
- @ResponseBody 写入到Response对象的body数据区
- @ModelAttribute 在参数上则自动注入到相应的ModelMap中,用在方法上则是在调用方法前,将返回值加入到ModelAndMap中
- @RequestParam 请求的参数匹配到方法的入参中
- @ExceptionHandler 异常时要执行的处理器
- @ControllerAdvice 拦截异常并统一处理
- @PathVariable 绑定 URL 占位符到入参,完成RESTFul风格。
@RequestMapping(value="/user/{id}",method=RequestMethod.POST)
public String post(@PathVariable("id") Integer id){
// do something here
}
THE END
好了,以上就是对于SpringMvc整体框架的介绍,这里我并没有给出一个完整的应用程序,因为我觉得这些内容才能够帮助我们更好的去理解整个框架,而单独的对于SpringMvc使用来讲还是相对比较简单的。我会在其他的博文中给出基于它的一个实际应用,还希望各位小伙伴持续关注哦~
当然以上只是个人的一些看法,如果有写的不好的或者是有问题的地方还希望您能与我联系,关注网站http://missxhh.com,获得更多有关于我的信息吧!
谢谢阅读,您的关注就是对我最大的动力!!!