Spring MVC
1 基本概念
MVC模式
1 用户请求通过http请求到达前段控制器
2 前端发给真正的控制器Controller
3 将处理之后的数据以model的格式进行返回
4 前端控制器将model发送给View template(视图模板)来进行解析和展示
概念解析:
前端控制器
MVC的本质:将业务数据抽取和业务数据呈现相分离
2 MVC
1 View 视图层
为用户提供UI,重点关注于数据的呈现
2 Model 模型层
业务数据的信息标示,关注支撑业务的信息构成,通常为多个业务实体的组合。
例如VO PO这些东西
3 Controller 控制层
调用业务逻辑产生合适的model,传递数据给视图层用于呈现
3 Spring MVC的静态基本概念
1 DispatcherServlet
DispatcherServlet即是前端控制器
2 Controller
就是调用业务逻辑的地方
@RequestMapping这个参数可以用在Controller类上和方法上,定义url访问到的类,或者精确到类当中的方法
如果需要在url当中添加参数,可以有@RequestParam
需要在url当中添加参数可以使用@RequestParam和@PathVariable两种方法
传统的servlet请求的形式
@Controller的参数传递
@RequestMapping 声明访问的URL。类和方法上均可使用
@RequestParam 形如xx/xxx?xx=xx的参数
@PathVariable 形如xx/xx/{xxxx}的参数
springMVC传递参数的三种方式:
1)使用参数注解@RequestParam
url形式:http://host:8080/courses/view?courseID=123
controller参数中传入:@RequestParam("courseID") Integer courseID
2)使用路径变量注解@PathVariable
url形式:http://host:8080/courses/view2/{courseID}方法的requestMapping:@RequestMapping(value="/view2/{courseID}",method=RequestMethod.GET)
controller参数中传入:@PathVariable("courseID") Integer courseID
3)使用传统的从HttpServletRequest获取参数
url形式:http://host:8080/courses/view3?courseID=123
controller参数中传入HttpServletRequest,使用request.getParameter("key")来获取参数值。
3 HandlerAdapter
HandlerAdapter相当于Controller 与DispatcherServle之间的桥梁。DispatcherServle调用HandlerAdapter来实现任务分发给相关的业务逻辑
4 HandlerInterceptor接口
拦截器,主要工作是在Handler调用之前,之后,以及view呈现后做一些事情
5 HandlerMapping
HandlerMapping主要用于确认DispatcherServlet和Controller之间的映射的类,主要是配置并告知DispatcherServlet由哪个Controller来响应
6 其他概念
HandlerExecutionChain
ModelAndView
ViewResolver:帮助DispatcherServlet找到对应的view
各个基本类的互相之间调用
4 Maven简答介绍
5 Spring MVC配置文件
1.web.xml:web项目的最基本的配置文件,所有框架监听器、servlet都在此配置
1.1.web.xml是maven自动生成的使用的是2.3.dtd的标准,该标准默认关闭EL表达式,如果想使用EL表达式可以使用2.4及以上的标准
<?xml version="1.0" encoding="UTF-8"?>
多个DispatcherServlet的情况,服务不同群体的请求的分发
1 web.xml
<?xml version="1.0"
encoding="UTF-8"?>
<!--使用2.4版本-->
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring MVC Study</display-name>
<!-- Spring应用上下文, 理解层次化的ApplicationContext
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/configs/spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!--在针对如果要区分处理不同的用户群体时。可以使用多个DispatcherServlet-->
<!-- DispatcherServlet, Spring MVC的核心 -->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
DispatcherServlet对应的上下文配置, 默认为/WEB-INF/$servlet-name$-servlet.xml
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/configs/spring/mvc-dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<!--
mvc-dispatcher拦截所有的请求-->
<!--指定不同的url的来源的划分依据-->
<url-pattern>/</url-pattern>
<!--例如可以定义其他的划分-->
<!--<url-pattern>/ws</url-pattern>-->
</servlet-mapping>
</web-app>
2 mvc-dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--spring-mvc配置文件-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 本配置文件是供名为mvc-dispatcher的DispatcherServlet使用, 提供其相关的Spring MVC配置 -->
<!-- 启用Spring基于annotation的DI, 使用户可以在Spring MVC中使用Spring的强大功能。 激活 @Required
@Autowired,JSR 250's @PostConstruct, @PreDestroy and @Resource 等标注 -->
<context:annotation-config />
<!-- DispatcherServlet上下文, 只管理@Controller类型的bean, 忽略其他型的bean, 如@Service -->
<context:component-scan base-package="com.imooc.mvcdemo">
<!--在本上下文当中,只对Controller这个注解的类进行加载-->
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!-- HandlerMapping, 无需配置, Spring MVC可以默认启动。 DefaultAnnotationHandlerMapping
annotation-driven HandlerMapping -->
<!-- 扩充了注解驱动,可以将请求参数绑定到控制器参数 -->
<mvc:annotation-driven />
<!-- 静态资源处理, css, js, imgs -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!--一个DispatcherServlet当中可以配置多个ViewResolver,可以使用order来排序-->
<!-- 配置ViewResolver。 可以用多个ViewResolver。 使用order属性排序。 InternalResourceViewResolver放在最后。 -->
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
<entry key="htm" value="text/html" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsps/" />
<property name="suffix" value=".jsp" />
</bean>
<!--200*1024*1024即200M resolveLazily属性启用是为了推迟文件解析,以便捕获文件大小异常 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="209715200" />
<property name="defaultEncoding" value="UTF-8" />
<property name="resolveLazily" value="true" />
</bean>
</beans>
配置解析JSON
引入依赖 jackson
在mvc-dispatcher-servlet当中添加jackson的配置
3 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--单纯的spring的配置文件-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--此处加载的是spring的上下文,采用注解的方式进行上下文当中内容的注入-->
<!--激活注入的方式来进行service的注入-->
<context:annotation-config />
<context:component-scan base-package="com.imooc.mvcdemo">
<!--过滤掉Controller类型注解,告诉Spring的上下文管理不必管理被Controller注解的类了-->
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
</beans>
4 项目的文件夹结构
6 在intellij上构建SpringMVC
1 项目的生成
首先选择maven项目,之后在下拉表中勾选 apcahe的 webapp
填写maven项目的GroupId以及ArtifactId
之后修改pom,在里边添加SpringMVC项目一般常用的maven依赖
一个pom.xml例子,主要的依赖有:
<!--针对普通的springMVC项目需要的jar-->
<!--servlet 核心的servlet引擎-->
<!--jsp 处理jsp的-->
<!--jstl 处理js的-->
<!--mysql-->
<!--spring-web-->
<!--spring-webmvc-->
如果需要其他依赖,则可以自行添加
2 各个文件的配置
7 总结
1 Spring MVC的基本概念
1 DispatcherServlet:前端控制器
2 Controller:调用业务逻辑生成model的地方
3 HandlerAdapter:DispatcherServlet通过HandlerAdapter调用controller。在HandlerMapping返回处理请求的Controller实例后,需要一个帮助定位具体请求方法的处理类,这个类就是HandlerAdapter,HandlerAdapter是处理器适配器,Spring MVC通过HandlerAdapter来实际调用处理函数。例如Spring MVC自动注册的AnnotationMethodHandlerAdpater,HandlerAdapter定义了如何处理请求的策略,通过请求url、请求Method和处理器的requestMapping定义,最终确定使用处理类的哪个方法来处理请求,并检查处理类相应处理方法的参数以及相关的Annotation配置,确定如何转换需要的参数传入调用方法,并最终调用返回ModelAndView。DispatcherServlet中根据HandlerMapping找到对应的handler method后,首先检查当前工程中注册的所有可用的handlerAdapter,根据handlerAdapter中的supports方法找到可以使用的handlerAdapter。通过调用handlerAdapter中的handler方法来处理及准备handler method的参数及annotation(这就是spring mvc如何将request中的参数变成handle method中的输入参数的地方),最终调用实际的handler method。
4 HandlerMapping:DispatcherServlet与Handler映射关系的类,在Spring3.0以后这个mapping默认可以不配置即采用annotation来扫描所有被@Controller关键字注解了的类。HandlerMapping
5 HandlerInterception:拦截器,主要是提供preHandle postHandle after三个方法,在调用controller前后使用
6 HandlerExecutionChain:preHandle->Controller method->postHandle->afterCompletion的执行链
7 ModelAndView:model的具体表现
8 ViewResolver:视图解析器,决定采用那个视图进行呈现
9 View:界面
具体时序图
时序图的解析
1 用户向服务器发送http请求,此时请求被前端控制器DispatcherServlet捕获
2 DispatcherServlet对请求的URL进行解析,获得请求资源的标识符URI。根据URI,调用HandlerMapping获得到Handler配置相关的所有对象(主要包括了Handler对象以及Handler对象的拦截器),最后以HandlerExecutionChain对象的形式返回
3 DispatcherServlet根据获得的Handler,选择合适的HanlerAdapter。(如果获取到HandlerAdapter之后,将开始执行拦截器preHandler()方法)
4 提取Request中的数据模型,填充Handler入参,开始执行Handle(Controller)。此时根据配置,Spring的额外动作:
1) HttpMessageConveter:将请求消息json、xml等转换为一个对象,将对象转换为指定的相应信息
2) 数据转换:对请求消息进行数据转换,例如将String转换为Integer、Double等
3) 数据格式化:对请求消息进行数据格式化,将字符串转换为格式化数字或者格式化日期
4) 数据验证:验证数据的有效性(长度、格式),验证结果存储到BindingResult或Error
5 Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象
6 根据返回的ModelAndView,DispatcherServlet选择合适的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)
7 ViewResolver结合Model和View来渲染视图
8 将渲染结果返回给客户端
Spring工作流程描述
为什么Spring只使用一个Servlet(DispatcherServlet)来处理所有请求?
详细见J2EE设计模式-前端控制模式
Spring为什么要结合使用HandlerMapping以及HandlerAdapter来处理Handler?
符合面向对象中的单一职责原则,代码架构清晰,便于维护,最重要的是代码可复用性高。如HandlerAdapter可能会被用于处理多种Handler。
2 概念澄清
2.1 Handler和Contoller
Handler不等于Controller,Handler包含Controller,原因是@Controller注解是在Spring3.0 之后引入的。
2.2 RequestMapping和HandlerMapping
HandlerMapping是用来找Handler(Controller)的,其默认去扫@Controller注解
而RequestMapping对应于将uri和Controller类及其中的方法对应。
3 DispatcherServlet上下文中的bean
HandlerMapping
处理器映射。它会根据某些规则将进入容器的请求映射到具体的处理器以及一系列前处理器和后处理器(即处理器拦截器)上。具体的规则视 HandlerMapping 类的实现不同而有所不同。其最常用的一个实现支持你在控制器上添加注解,配置请求路径。当然,也存在其他的实现。
HandlerAdapter
处理器适配器。拿到请求所对应的处理器后,适配器将负责去调用该处理器,这使得 DispatcherServlet 无需关心具体的调用细节。比方说,要调用的是一个基于注解配置的控制器,那么调用前还需要从许多注解中解析出一些相应的信息。因此, HandlerAdapter 的主要任务就是对 DispatcherServlet 屏蔽这些具体的细节。
HandlerExceptionResolver
处理器异常解析器。它负责将捕获的异常映射到不同的视图上去,此外还支持更复杂的异常处理代码。
ViewResolver
视图解析器。它负责将一个代表逻辑视图名的字符串(String)映射到实际的视图类型 View 上。
LocaleResolver &LocaleContextResolver
地区解析器 和 地区上下文解析器。它们负责解析客户端所在的地区信息甚至时区信息,为国际化的视图定制提供了支持。
ThemeResolver
主题解析器。它负责解析你web应用中可用的主题,比如,提供一些个性化定制的布局等。
MultipartResolver
解析multi-part的传输请求,比如支持通过HTML表单进行的文件上传等。