文章目录
Spring MVC
MVC 介绍
MVC :(Model View Controlelr)是一种提供给web应用的软件设计的框架模式,采用模型(model)-视图(view)-控制器(controller)的方法把业务逻辑、数据与界面显示分离。
简而言之:
MVC就是把数据处理、数据展示(界面)和程序/用户的交互三者分离开来的一种编程模式。
MVC是一种复合模式。核心部件分别是:
1、Model(模型):用户数据、状态以及程序逻辑,独立于视图和控制器
2、View(视图):呈现模型,类似于web程序中的界面,视图会从模型中拿到要展现的状态以及数据,对于相同的数据可以有多种不同的显示形式(视图)。
3、Controller(控制器):负责获取用户的输入信息,进行解析并反馈给模型,通常情况下一个视图具有一个控制器。
基于servlet的MVC模式的具体实现:
模型:一个或多个JavaBean对象,用于存储数据和处理业务逻辑。
视图:一个或多个jsp页面,向控制器提交数据和为模型提供数据显示,jsp页面主要使用html标记和JavaBean标记来显示数据。
控制器:一个或多个servlet对象,根据视图提交的请求进行控制,即将请求转发给处理业务逻辑的JavaBean,并将处理结果存放到实体模型JavaBean中,输出给视图显示。
基于servlet的MVC模式流程:
MVC 特点
- 清晰的角色划分。
控制器(controller)、验证器(validator)、命令对象(command obect)、表单对象(form object)、模型对象(model object)、
Servlet分发器(DispatcherServlet)、处理器映射(handler mapping)、试图解析器(view resoler)等等。每一个角色都可
以由一个专门的对象来实现。
- 灵活而强大的配置功能
将框架类和应用程序类都能作为JavaBean配置,支持跨多个context的引用,例如,在web控制器中对业务对象和验证器validator)的引用。
- 基于组件技术
- 面向接口编程
- 能够完美结合spring
MVC 工作原理
请求流程(也叫spring MVC的生命周期):
原理详述:
1.用户在客户端向DispatcherServlet发送请求。
2.DispatcherServlet接受到请求后调用处理器映射器映射对应的Controller。
3.处理器映射器返回映射到的Controller给DispatcherServlet。
4.DispatcherServlet通过得到的Controller来调用处理器。
5.Controller根据请求调用相应的业务逻辑Service。
6.Service调用数据访问层。
7.Service抽取数据模型。
8.Service把数据模型返回给Controller。
9.Controller包装数据返回给DispatcherServlet一个ModelAndView。
10.DispatcherServlet根据得到的ModelAndView调用视图解析器。
11.视图解析器返回一个指定格式的视图。
12.DispatcherServlet把得到的视图forward到JSP页面。
13.JSP页面响应用户的请求并显示到客户端。
DispatcherServlet
介绍
是一个servlet。被称作前置控制器,配置在web.xml文件中。拦截匹配的请求,自定义拦截规则,即拦截什么样的请求,依据某某规则分发到目标Controller来处理。
实例描述
实例1:
可以配置多个DispatcherServlet,通过名字来区分。
每一个DispatcherServlet有自己的WebApplicationContext上下文对象。同时保存的ServletContext中和Request对象中,关于key,以后说明。
在DispatcherServlet的初始化过程中,框架会在web应用的 WEB-INF文件夹下寻找名为[servlet-name]-servlet.xml 的配置文件,生成文件中定义的bean。
<web-app>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup> //启动顺序,
</servlet>
<servlet-mapping>
//servlet的名字example。
<servlet-name>example</servlet-name>
//自定义的拦截规则,即拦截以*.form结尾的请求
<url-pattern>*.form</url-pattern>
</servlet-mapping>
</web-app>
实例2:
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
指明了配置文件的文件名,不使用默认配置文件名,而使用springMVC.xml配置文件。
其中< param-value>**.xml< /param-value> 这里可以使用多种写法
1、不写,使用默认值:/WEB-INF/< servlet-name>-servlet.xml
2、< param-value >/WEB-INF/classes/springMVC.xml< /param-value>
3、< param-value >classpath*:springMVC-mvc.xml< /param-value>
4、多个值用逗号分隔
父子上下文(WebApplicationContext)
Struts2+Spring+Hibernate的项目中都是使用listener监听器的。
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
spring会创建一个WebApplicationContext上下文,成为父上下文(父容器)保存在servletContext中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。
可以使用Spring提供的工具类取出上下文对象:
WebApplicationContextUtils.getWebApplicationContext(ServletContext);
DispatcherServlet是一个Servlet,可以同时配置多个,每个 DispatcherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文中的内容,但父上下文不能访问子上下文中的内容。 它也保存在 ServletContext中,key是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。当一个Request对象产生时,会把这个子上下文对象(WebApplicationContext)保存在Request对象中,key是DispatcherServlet.class.getName() + “.CONTEXT”。
可以使用工具类取出上下文对象:
RequestContextUtils.getWebApplicationContext(request);
注:
spring并没有限制必须要使用父子上下文,我们可以自己决定如何使用。
MVC的配置文件讲解
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- 自动扫描的包名 -->
<context:component-scan base-package="com.app,com.core,JUnit4" ></context:component-scan>
<!-- 默认的注解映射的支持 -->
<mvc:annotation-driven />
<!-- 视图解释类 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/><!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑 -->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
</bean>
<!-- 拦截器 -->
<mvc:interceptors>
<bean class="com.core.mvc.MyInteceptor" />
</mvc:interceptors>
<!-- 对静态资源文件的访问 方案一 (二选一) -->
<mvc:default-servlet-handler/>
<!-- 对静态资源文件的访问 方案二 (二选一)-->
<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>
<mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>
<mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"/>
</beans>
- < context:component-scan/> 扫描指定的包中的类上的注解,常用的注解有:
@Controller 声明Action组件
@Service 声明Service组件 @Service(“myMovieLister”)
@Repository 声明Dao组件
@Component 泛指组件, 当不好归类时.
@RequestMapping("/menu") 请求映射
@Resource 用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name=“beanName”)
@Autowired 用于注入,(srping提供的) 默认按类型装配
@Transactional( rollbackFor={Exception.class}) 事务管理
@ResponseBody 将Java对象转换格式,一般是转换成json或者xml格式
@Scope(“prototype”) 设定bean的作用域
-
< mvc:annotation-driven/ >是一种简写形式。完全可以手动配置替代这种简写形式,简写形式可以让初学者快速应用默认配置方案。< mvc:annotation-driven >会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter两个bean,是spring MVC为@Controller分发请求所必须的。
并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。
后面,我们处理响应ajax请求时,就使用到了对json的支持。
后面,对action写JUnit单元测试时,要从spring IOC容器中取DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,来完成测试,取的时候要知道是<mvc:annotation-driven />这一句注册的这两个bean。 -
**< mvc:interceptors/ > 是一种简写形式。**通过看前面的大图,知道,我们可以配置多个HandlerMapping。mvc:interceptors/会为每一个HandlerMapping,注入一个拦截器。其实我们也可以手动配置为每个HandlerMapping注入一个拦截器。
-
< mvc:default-servlet-handler/ > 使用默认的Servlet来响应静态文件。
-
< mvc:resources mapping="/images/✳✳" location="/images/" cache-period=“31556926”/ > 匹配URL /images/✳✳ 的URL被当做静态资源,由Spring读出到内存中再响应http。
Spring MVC和Spring的区别
spring是IOC和AOP的容器框架,spring MVC是基于spring功能之上添加的Web框架,想用spring MVC必须要依赖于spring。可以将spring MVC类比于struts2。
spring可以说是一个管理bean的容器,也可以说是包括很多开源项目的总成;spring MVC是其中的一个开源项目,所以简单走个流程的话,http请求一到,由容器(如tomcat)解析http弄成一个request,通过映射关系(路径,方法,参数) 被spring MVC的一个分发器分发到可以处理这个请求的bean,就是从spring管理的bean的池子里面找到,处理完了就把响应返回。
spring MVC是一个MVC模式的Web开发框架。
spring是一个通用解决方案,最大的用处就是通过IOC/AOP解耦,降低软件复杂性,所以spring可以结合spring MVC等很多其他解决方案一起使用。
Spring MVC和Struts2的区别
- 底层实现不同
spring MVC采用servlet实现。Struts2采用的是Filter实现。
Filter是在容器启动之后即初始化,服务停止以后销毁,晚于servlet。servlet是在调用时初始化,先于filter,服务停止后销毁。
- 拦截机制不同
spring MVC是方法级别的拦截。一个方法对应一个request上下文,所以方法基本上是独立的,独享request、response数据。
而每个方法同时又和一个url对应,参数的传递是直接注入到方法中的,是方法独有的。处理结果通过ModelMap返回给MVC框架。
spring整合时,spring MVC的Controller bean默认是单例模式singleton,所以默认对所有的请求只会创建一个Controller。
又因为没有共享的属性,所以是线程安全的,如果药改变默认的作用域,可以添加@Scope注解修改。
struts2是类级别的拦截。每次请求就会创建一个action,和spring整合时struts2的ActionBean注入作用域是原型模式property,然后通过setter、getter把request数据注入到属性。struts2中一个action对应一个request,request上下文在接收参数时可以通过属性接收,这说明属性参数是让多个方法共享的。struts2中action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了,只能设计为多例。
- 配置
spring MVC和spring是无缝的,因为spring MVC是基于spring功能之上的Web框架,想用spring MVC必须依赖于spring。从整个项目的管理和安全上也比struts2高。
- 性能
struts2是类级别的拦截,每次请求对应实例一个新的action,需要加载所有的属性值注入。spring MVC实现了零配置,由于spring MVC基于方法拦截,有加载一次单例模式bean注入。所以spring MVC开发效率和性能高于struts2。
拦截器与过滤器的区别
- 拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
- 拦截器不依赖于servlet容器,过滤器依赖于servlet容器。
- 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
- 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
- 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
快问快答
1、请求如何给前端控制器?
在web.xml中进行部署描述。
2、前端控制器如何根据请求信息选择页面控制器进行功能处理?
配置HandlerMapping进行映射。
3、如何支持多种页面控制器?
配置HandlerAdapter从而支持多种类型的页面控制器。
4、页面控制器如何使用业务对象?
spring IoC容器的依赖注入功能。
5、页面控制器如何返回模型数据?
使用ModelAndView对象。
6、前端控制器如何根据页面控制器返回的逻辑视图名选择具体的视图进行渲染?
使用ViewResolver进行解析。
7、不同的试图技术如何使用相应的模型数据?
因为Model是一个Map数据结构,很容易支持其他视图技术。