SpringMVC的开发及原理流程框图分析
1 SpringMVC概述
- JavaEE体系结构包括四层,从上到下分别是应用层、Web层、业务层、持久层。Struts和SpringMVC是Web层的框架,Spring是业务层的框架,Hibernate和MyBatis是持久层的框架。
- 很多应用程序的问题在于处理业务数据的对象和显示业务数据的视图之间存在紧密耦合,通常,更新业务对象的命令都是从视图本身发起的,使视图对任何业务对象更改都有高度敏感性。而且,当多个视图依赖于同一个业务对象时是没有灵活性的。
- SpringMVC是一种基于Java,实现了Web MVC设计模式,请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将Web层进行职责解耦。基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,SpringMVC也是要简化我们日常Web开发
2 MVC设计模式
-
MVC设计模式的任务是将包含业务数据的模块与显示模块的视图解耦。这是怎样发生的?在模型和视图之间引入重定向层可以解决问题。此重定向层是控制器,控制器将接收请求,执行更新模型的操作,然后通知视图关于模型更改的消息。
-
传统的MVC架构
-
传统MVC架构的改进
3 SpringMVC框架的执行流程
-
SpringMVC是Spring的一部分,如图:
-
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是
BeanFactory
,它是工厂模式的实现。BeanFactory
使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。 - Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是
-
SpringMVC的核心架构:
-
SpringMVC的核心流程分析:
DispatcherServlet:相当于中央调度器,各个组件之间都和前端控制器进行交互,降低了各个组件之间的耦合度:::这里所说的Handler可以理解为Controller或者Action
-
第一步:用户发起Request请求,请求至DispatcherServlet前端控制器
-
第二步:DispatvherServlet前端控制器请求HandlerMappering处理器映射器查找Handler
-
第三步:HandlerMappering处理器映射器,根据url及一些配置规则(xml,注解配置)查找Handler,
并将Handler返还给DispatcherServlet前端控制器 -
第四步:DispatcherServlet前端控制器调度适配器执行Handler,有了适配器通过适配器去扩展对不同的
Handler执行方法(比如:原始servlet开发,注解开发)。 -
第五步:执行Handler,Handler是后端控制器,当成是模型
-
第六步:Handler执行完之后返回ModelAndView
ModelAndView:是SpringMVC的一个对象,对Model和View的封装 -
第七步:适配器将ModelAndView返回给DispatcherServlet前端控制器
-
第八步:DispatcherServlet前端控制器调用视图解析器进行视图解析,解析后生成View
视图解析器根据逻辑视图名解析出真正的视图
View:视图封装对象,提供了很多的view,jsp、freemarker、pdf、excel… -
第九步:ViewResolver视图解析器给前端控制器返回View
-
第十步:DispatcherServlet调用view的渲染视图的方法,将数据模型填充到resquest域中
-
第十一步:DispatcherServlet前端控制器向用户响应结果(jsp页面、json数据等)
-
4 非注解的入门程序(更好的理解SpringMVC)
-
需求实现查询商品的列表
-
导入jar包
-
配置前端控制器
<!-- 前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 加载SpringMVC的配置 --> <init-param> <!-- 配置文件的地址 如果不配置contextConfigLocation, 默认查找classpath下的配置文件的名称是:servlet名称+"-servlet.xml",本文即:springmvc-servlet.xml --> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 不可以配置 /* 如果配置 /* ,返回jsp也由springmvc解析 可以配置 / , 此工程中的所有请求全部由springmvc解析,此种方式可以实现RESTful方式,需要特殊处理对静态资源的解析不能由springmvc解析 可以配置 *.do,*.action,所有请求的url扩展名为 *.do 和 *.action都由springmvc解析 --> <url-pattern>*.action</url-pattern> </servlet-mapping>
-
编写springmvc.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd "> <!-- 配置Handler ========================= --> <bean name="/itemList.action" class="com.syj.springmvc.ItemController1"> </bean> <!-- 处理器映射器========================= --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" > </bean> <!-- 处理器适配器========================= --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"> </bean> <!-- 视图解析器 ============================ --> <!-- 要求将jstl的包加到classpath下面 ViewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> </bean> </beans>
-
springmvc中配置的处理器映射器HandlerMappering:BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping: 根据请求url(XXXX.action)匹配spring容器bean(Handler)的 name
找到对应的bean(程序编写的Handler)
所有处理器映射器都实现HandlerMapping接口。
<!-- 处理器映射器========================= --> <!-- springmvc框架根据HandlerMapping接口判断是否是处理器映射器 --> <!-- 根据bean的name进行查找Handler 将action的url配置在bean的name中 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" > </bean>
-
所有的适配器都是实现了HandlerAdapter接口。
<!-- 处理器适配器========================= --> <!-- springmvc框架根据HandlerAdapter接口判断是否是处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"> </bean>
程序编写Handler根据适配器的要求编写。
SimpleControllerHandlerAdapter适配器要求:
通过supports方法知道Handler必须要实现哪个接口:
-
Handler编写(即编写Controller)
public class ItemController1 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 使用静态数据将商品信息列表显示在jsp页面
// 商品列表
List<Items> itemsList = new ArrayList<Items>();
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setCreatetime(new Date());
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setCreatetime(new Date());
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
ModelAndView modelAndView = new ModelAndView();
// 将数据填充到request域中
// request.setAttribute("itemsList", itemsList);//等同于下方
modelAndView.addObject("itemsList", itemsList);
modelAndView.setViewName("/WEB-INF/jsp/itemsList.jsp");
return modelAndView;
}
}
-
在Springmvc中配置Handler
<!-- 配置Handler ========================= --> <!-- 由于使用了BeanNameUrlHandlerMapping处理映射器,name配置为url --> <bean name="/itemList.action" class="com.syj.springmvc.ItemController1"> </bean>
-
配置视图解析器ViewResolver
<!-- 视图解析器 ============================ --> <!-- 要求将jstl的包加到classpath下面 ViewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> </bean>
-
测试
5 其它非注解处理器映射器和适配器
-
BeanNameUrlHandlerMapping(映射器)
根据请求url(XXXX.action)匹配spring容器bean的 name
找到对应的bean(程序编写的Handler)
-
SimpleUrlHandlerMapping(映射器)
注意:在springmvc.xml配置了多个处理器映射器,多个处理器映射器可以共存。
-
SimpleControllerHandlerAdapter(适配器)
要求程序编写的Handler(Controller)需要实现Controller接口。
-
HttpRequestHandlerAdapter(适配器)
在springmvc.xml配置:HttpRequestHandlerAdapter
要求Handler 实现HttpRequestHandler接口
6DispatcherServlet.properties
- DispatcherServlet前端控制器加载 DispatcherServlet.properoties 配置文件,从而默认加载各各组件,
- 如果在springmvc.xml中配置了处理器映射器和适配器,以sprintmvc.xml中配置的为准
7 注解映射器和适配器
-
spring3.1之前默认加载映射器是org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping,3.1之后要使用:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
在springmvc.xml中配置RequestMappingHandlerMapping:
使用RequestMappingHandlerMapping需要在Handler 中使用**@Controller标识此类是一个控制器,使用@RequestMapping**指定Handler方法所对应的url。
-
spring3.1之前默认加载映射器是
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter,3.1之后要使用:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
RequestMappingHandlerAdapter,不要求Handler实现任何接口,它需要和RequestMappingHandlerMapping注解映射器配对使用,主要解析Handler方法中的形参。
-
配置视图解析器
-
编写Handler(Controller)
@Controller public class ItemController3 { @RequestMapping("qureyItem") public ModelAndView qureyItem() { // 使用静态数据将商品信息列表显示在jsp页面 // 商品列表 List<Items> itemsList = new ArrayList<Items>(); Items items_1 = new Items(); items_1.setName("联想笔记本"); items_1.setPrice(6000f); items_1.setCreatetime(new Date()); items_1.setDetail("ThinkPad T430 联想笔记本电脑!"); Items items_2 = new Items(); items_2.setName("苹果手机"); items_2.setPrice(5000f); items_2.setCreatetime(new Date()); items_2.setDetail("iphone6苹果手机!"); itemsList.add(items_1); itemsList.add(items_2); ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("itemsList", itemsList); // modelAndView.setViewName("/WEB-INF/jsp/itemsList.jsp"); // 指定逻辑视图 modelAndView.setViewName("itemsList"); return modelAndView; } }
-
使用Spring的组件扫描,对Controller进行简化配置
<!-- 2、包扫描配置 --> <!-- 不再逐个配置Handler --> <!-- <bean class="com.syj.springmvc.controller.ItemController3" /> --> <context:component-scan base-package="com.syj.springmvc.controller" />
-
组件扫描可以扫描@Controller、@Service、@component、@Repsitory
-
其中我们还可以使用配置注解驱动
相当于同时使用最新处理器映射跟处理器适配器,对json数据响应提供支持
<!-- 配置处理器映射器 --> <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> --> <!-- 配置处理器适配器--> <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> --> <!-- 配置注解驱动,相当于同时使用最新处理器映射跟处理器适配器,对json数据响应提供支持 --> <mvc:annotation-driven />
8 源码的简单分析
DispatcherServlet:前端控制器,相当于中央调度器,可以降低组件之间的耦合度。
HandlerMapping:处理器映射器,负责根据url查找Handler
HandlerAdapter:处理器适配器,负责根据适配器要求的规则去执行处理器。可以通过扩展适配器支持不同类型的Handler。
viewResolver:视图解析器,根据逻辑视图名解析成真正的视图,真正视图地址==前缀+逻辑视图名+后缀
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
- DispatcherServlet通过HandlerMapping查找Handler
- DispatcherServlet通过适配器去执行Handler,得到ModelAndview
- 视图解析完成得到一个view:
4.进行视图渲染
将Model中的数据填充到request域。
完整的springmvc的配置
- 我们可以寻找到Springmvc配置的发展
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 配置Handler ========================= -->
<!--1、单个配置
由于使用了BeanNameUrlHandlerMapping处理映射器,name配置为url
-->
<bean id="itemController1" name="/itemList.action"
class="com.syj.springmvc.controller.ItemController1">
</bean>
<bean id="itemController2" class="com.syj.springmvc.controller.ItemController2">
</bean>
<!-- 2、包扫描配置 -->
<!-- 不再逐个配置Handler -->
<!-- <bean class="com.syj.springmvc.controller.ItemController3" /> -->
<context:component-scan base-package="com.syj.springmvc.controller" />
<!-- 处理器映射器 ========================= -->
<!-- 1、配置 BeanNameUrlHandlerMapping 处理器映射器
配置处理器映射器 springmvc框架根据HandlerMapping接口判断是否是处理器映射器 -->
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
</bean>
<!--2、配置SimpleUrlHandlerMapping处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
<property name="mappings">
<props>
<prop key="/TestitemList1.action" >itemController1</prop>
<prop key="/TestitemList2.action" >itemController2</prop>
</props>
</property>
</bean>
<!-- 3、配置注解RequestMappingHandlerMapping映射器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean> -->
<!-- ================使用最多最广的==================== -->
<!-- 配置处理器映射器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> -->
<!-- 配置处理器适配器-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> -->
<!-- 配置注解驱动,相当于同时使用最新处理器映射跟处理器适配器,对json数据响应提供支持 -->
<mvc:annotation-driven />
<!-- 视图解析器不变-->
<!-- ==================================== -->
<!-- 处理器适配器 ========================= -->
<!--
1、SimpleControllerHandlerAdapter适配器 Controller需要实现Controller
springmvc框架根据HandlerAdapter接口判断是否是处理器适配器
-->
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
</bean>
<!-- 2、HttpRequestHandlerAdapter适配器 Controller需要实现HttpRequestHandler接口 -->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
</bean>
<!-- 3、配置RequestMappingHandlerAdapter适配器 Controller不需要实现什么接口 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
</bean> -->
<!-- 视图解析器 ============================ -->
<!-- 1、要求将jstl的包加到classpath下面 ViewResolver -->
<!-- <bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean> -->
<!-- 2、注解实现 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>