目录
1 springmvc概述
SpringMvc介绍
Spring MVC是一个基于MVC架构的用来简化web应用程序开发的应用开发框架,它是Spring的一部分,它和Struts2一样都属于表现层的框架。
MVC(Model模型 View 视图 Controller 控制器):这是一种软件架构思想,是一种开发模式,将软件划分为三种不同类型的模块,分别是模型,视图,和控制器。
模型:用于封装业务逻辑处理(java类);
视图:用于数据展现和操作界面(Servlet);
控制器:用于协调视图和模型(jsp);
处理流程:视图将请求发送给控制器,由控制器选择对应的模型来处理;模型将处理结果交给控制器,控制器选择合适的视图来展现处理结果;
springmvc优势
- 清晰的角色划分:控制器(controller)、验证器(validator)、命令对象(command obect)、表单对象(form object)、模型对象(model object)、Servlet分发器(DispatcherServlet)、处理器映射(handler mapping)、试图解析器(view resoler)等等。每一个角色都可以由一个专门的对象来实现。
- 强大而直接的配置方式:将框架类和应用程序累都能作为JavaBean配置,支持跨多个context的引用,例如,在web控制器中对业务对象和验证器validator)的引用。
- 可适配、非侵入:可以根据不同的应用场景,选择何事的控制器子类(simple型、command型、from型、wizard型、multi-action型或者自定义),而不是一个单一控制器(比如Action/ActionForm)继承。
- 可重用的业务代码:可以使用现有的业务对象作为命令或表单对象,而不需要去扩展某个特定框架的基类。
- 可定制的绑定(binding)和验证(validation):比如将类型不匹配作为应用级的验证错误,这可以保证错误的值。再比如本地化的日期和数字绑定等等。在其他某些框架中,你只能使用字符串表单对象,需要手动解析它并转换到业务对象。
- 可定制的handler mapping和view resolution:spring提供从最简单的URL映射,到复杂的、专用的定制策略。与某些web MVC框架强制开发人员使用单一特定技术相比,Spring显得更加灵活。
- 灵活的model转换:在Springweb框架中,使用基于Map的键/值对来达到轻易的与各种视图技术集成。
- 可定制的本地化和主题(theme)解析:支持在JSP中可选择地使用Spring标签库、支持JSTL、支持Velocity(不需要额外的中间层)等等。
- 简单而强大的JSP标签库(Spring Tag Library):支持包括诸如数据绑定和主题(theme)之类的许多功能。他提供在标记方面的最大灵活性。
- JSP表单标签库:在Spring2.0中引入的表单标签库,使用在JSP编写表单更加容易。
- Spring Bean的生命周期可以被限制在当前的HTTp Request或者HTTp Session。准确的说,这并非Spring MVC框架本身特性,而应归属于Spring MVC使用的WebApplicationContext容器。
还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。
2 springmvc运行原理
详细流程:
1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图
8. 将渲染结果返回给客户端。
3 Spring MVC和Struts2对比
1).拦截的级别
Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上SpringMVC 就容易实现restful url
2).方法/参数
SpringMVC的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量,而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码、读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。 参数封装struts2:基于属性封装 springmvc:基于方法进行封装
3). 内存
由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。
4)、 拦截器实现机制
拦截器实现机制上,Struts2有以自己的interceptor机制,SpringMVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比SpringMVC大。
5)、底层实现机制
struts2:filter,springmvc:servlet,filter和servlet是不同的,这就导致了二者的机制不同
6). Ajax集成
SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。
7). 运行效率
springmvc可以单例开发,struts2只能是多例开发,struts2参数基于属性封装,如果配置单例,会出现线程安全问题,所以配置多例 。
4 入门案例
4.1 创建工程导入相关jar包
4.2 web.xml配置 前端控制器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<!-- 定义Spring MVC的前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 让SpringMVC的前端控制器拦截所有以.do结尾请求 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
4.3 配置springmvc的核心配置文件
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- spring可以自动去扫描base-pack下面的包或者子包下面的java文件,
如果扫描到有Spring的相关注解的类,则把这些类注册为Spring的bean -->
<context:component-scan base-package="org.springmvc.controller"/>
<!-- 配置处理映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 配置处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置逻辑视图前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 配置逻辑视图后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
注解驱动<mvc:annotation-driven>的作用:
1. 自动创建处理器映射器 RequestMappingHandlerMapping
2. 自动创建处理器适配器 RequestMappingHandlerAdapter
3. 支持所有注解
4. 支持json格式数据
4.4 实现controller
package org.springmvc.controller;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* HelloController是一个基于注解的控制器,
* 可以同时处理多个请求动作,并且无须实现任何接口。
*/
@Controller
public class HelloController{
private static final Log logger = LogFactory.getLog(HelloController.class);
//RequestMapping注解用来映射请求的的URL和请求的方法等。本例用来映射"/hello"
@RequestMapping(value="/hello")
public ModelAndView hello(){
logger.info("hello方法 被调用");
//ModelAndView对象通常包含了返回视图的路径、模型的名称以及模型对象
ModelAndView mv = new ModelAndView();
//添加模型数据 可以是任意的POJO对象
mv.addObject("message", "Hello World!");
//modelAndView.setViewName("/WEB-INF/jsp/hello.jsp");//物理视图
modelAndView.setViewName("hello");//设置逻辑视图
return mv;
}
}