【1】什么是MVC
MVC是一种软件架构的思想,将软件按照**模型(Model)、视图(View)、控制器(Controller)**来划分。
Model模型
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
- 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
- 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
View视图层
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
Controller控制层
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC的工作流程
用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器。
【2】SpringMVC
① 概述
官网文档:https://docs.spring.io/spring-framework/docs/5.3.10-SNAPSHOT/reference/html/web.html#mvc
Spring Web MVC 是最初建立在 Servlet API 之上的 Web 框架,从一开始就包含在 Spring Framework
中。正式名称“Spring Web MVC
”来自其源模块的名称 ( spring-webmvc
),但通常称为“Spring MVC
”。
与 Spring Web MVC 并行,Spring Framework 5.0 引入了一个反应式堆栈 Web 框架,其名称“Spring WebFlux”也基于其源模块 ( spring-webflux)。
也就是说SpringMVC是Spring的一个后续产品,是Spring的一个子项目。SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
SpringMVC优点
- Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
- 基于原生的
Servlet
,通过了功能强大的前端控制器DispatcherServlet
,对请求和响应进行统一处理 - 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
- 代码清新简洁,大幅度提升开发效率
- 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
- 性能卓著,尤其适合现代大型、超大型互联网项目要求
② springmvc中DispatcherServlet配置
DispatcherServlet配置有两种方式:使用类配置或者在web.xml中配置。
类配置实例如下:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
web.xml配置实例如下
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
【3】Struts2
与SpringMVC
使用DispatchServlet
作为核心控制器不同之外,Struts2
是一个使用StrutsPrepareAndExecuteFilter
Filter
作为控制器的 MVC框架。
Struts2 VS Struts1
- 在体系结构方面更优秀:类更少, 更高效: 在
Struts2
中无需使用 “ActionForm
” 来封装请求参数. - 扩展更容易:
Struts2
通过拦截器完成了框架的大部分工作. 在Struts2
中插入一个拦截器对象相当简便易行. - 更容易测试:即使不使用浏览器也可以对基于
Struts2
的应用进行测试
Struts2 从本质上讲已不是从 Struts1 扩展而来的, 说它是一个换了品牌标签的 WebWork 更合适。
从 Struts1 升级到 Struts2:
- Struts1 里使用
ActionServlet
作为控制器; Struts2 使用了一个过滤器作为控制器 - Struts1 中每个 HTML 表单都对应一个
ActionForm
实例. Struts2 中, HTML 表单将被直接映射到一个 POJO. - Struts1 的验证逻辑编写在
ActionForm
中;Struts2
中的验证逻辑编写在Action
中. - Struts1 中, Action 类必须继承
org.apache.struts.action.Action
类; Struts2 中任何一个 POJO 都可以是一个 Action 类. - Struts2 在页面里使用
OGNL
来显示各种对象模型, 可以不再使用EL 和 JSTL
Struts2运行流程概述
- 请求发送给
StrutsPrepareAndExecuteFilter
StrutsPrepareAndExecuteFilter
询问ActionMapper
: 该请求是否是一个Struts2
请求(即是否返回一个非空的ActionMapping
对象)- 若
ActionMapper
认为该请求是一个 Struts2 请求,则StrutsPrepareAndExecuteFilter
把请求的处理交给ActionProxy
ActionProxy
通过Configuration Manager
询问框架的配置文件,确定需要调用的Action
类及Action
方法ActionProxy
创建一个ActionInvocation
的实例,并进行初始化ActionInvocation
实例在调用Action
的过程前后,涉及到相关拦截器(Intercepter
)的调用。Action
执行完毕,ActionInvocation
负责根据struts.xml
中的配置找到对应的返回结果。调用结果的execute
方法,渲染结果。在渲染的过程中可以使用Struts2
框架中的标签。- 执行各个拦截器
invocation.invoke()
之后的代码 - 把结果发送到客户端
【4】SpringMVC与Struts2对比
① 级别
Struts2是类级别的拦截, 一个类对应一个request上下文。SpringMVC是方法级别的拦截,一个方法对应一个request上下文。而方法同时又跟一个url对应,所以说从架构本身上SpringMVC就容易实现restful url
,而struts2
的架构实现起来要费劲。因为Struts2中Action
的一个方法可以对应一个url
,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。
② 变量独立与共享
SpringMVC的方法之间基本上独立的,独享request
response
数据,请求数据通过参数获取,处理结果通过ModelMap
交回给框架,方法之间不共享变量。而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量
是共享的,这不会影响程序运行,却给我们编码读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
③ 内存使用
由于Struts2需要针对每个request
进行封装,把request
,session
等servlet生命
周期的变量封装成一个一个Map
,供给每个Action
使用,并保证线程安全,所以在原则上,是比较耗费内存的。
④ 配置文件
拦截器实现机制上,Struts2
有自己的interceptor
机制,SpringMVC
用的是独立的AOP
方式,这样导致Struts2
的配置文件量还是比SpringMVC
大。
SpringMVC可以认为已经能够做到100%零配置。
⑤ servlet与filter
SpringMVC
的入口是servlet
,而Struts2
是filter
,这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。
servlet
servlet是一种运行服务器端的java应用程序,具有独立于平台和协议的特性,并且可以动态的生成web页面,它工作在客户端请求与服务器响应的中间层
。
servlet的生命周期始于它被装入web服务器的内存时,并在web服务器终止或重新装入servlet时结束。servlet一旦被装入web服务器,一般不会从web服务器内存中删除,直至web服务器关闭或重新结束。
- 装入:启动服务器时加载Servlet的实例;
- 初始化:web服务器启动时或web服务器接收到请求时,或者两者之间的某个时刻启动。初始化工作有
init()
方法负责执行完成; - 调用:从第一次到以后的多次访问,都是只调用doGet()或doPost()方法;
- 销毁:停止服务器时调用
destroy()
方法,销毁实例。
filter
filter是一个可以复用的代码片段,可以用来转换HTTP请求、响应和头信息。Filter不像Servlet,它不能产生一个请求或者响应
,它只是修改对某一资源的请求,或者修改从某一的响应。
filter(一定要实现javax.servlet包的Filter接口的三个方法init()、doFilter()、destroy(),空实现也行)
服务器启动的时候,web服务器创建Filter的实例对象,并调用其init方法,完成对象的初始化功能。filter对象只会创建一次,init方法也只会执行一次。
其生命周期如下:
- 启动服务器时加载过滤器的实例,并调用
init()
方法来初始化实例; - 每一次请求时都只调用方法
doFilter()
进行处理; - 停止服务器时调用
destroy()
方法,销毁实例。
⑥ 扩展配置与支持
SpringMVC验证支持JSR303
,处理起来相对更加灵活方便,而Struts2
验证比较繁琐,感觉太烦乱。
Spring MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高(当然Struts2也可以通过不同的目录结构和相关配置做到SpringMVC一样的效果,但是需要xml配置的地方不少)。
设计思想上,Struts2
更加符合OOP
的编程思想, SpringMVC
就比较谨慎,在servlet
上扩展。
SpringMVC开发效率和性能高于Struts2。