为什么不用 HttpServlet
- 只能一个类处理一个请求
- 请求处理比较繁琐
- 视图响应不统一
SpringMVC流程
响应视图,JSP视图解析器是基于转发的机制
文字版介绍
核心请求总控器(DispatcherServlet 中央调度器)
SpringMVC的核心控制器 负责拦截所有请求,并把请求转发给 HandlerMapping 去找到对应的 Controller,但是不能直接调用所以使用 HandleAdaptor 调用 Controller,Controller 执行后返回 ModelAndView 对象给 ViewReslver 解析成 View 对象,最后把 View 返回给浏览器。
DispatcherServlet 中的模板方法,负责创建 servlet
/**
* 初始化servlet使用的策略对象。
* <p>可能在子类中被重写,以便初始化更多的策略对象。
*/
protected void initStrategies(ApplicationContext context) {
// 初始化该类使用的MultipartResolver。
// 如果在这个命名空间的BeanFactory中没有使用给定的名称定义bean,则不提供多部分处理
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
HandlerMapping 和 HandlerAdapter
HandlerMapping:负责解析带着 @ReqeustMapping
注解的方法以及类信息
接收请求时解析并判断是否有对应的 @ReqeustMapping
注解的方法,如果有返回到 DispatcherServlet
由它
当xml配置了
或者配置类中配置了 @EnableWebMvc
注解时,spring会自动装配RequestMappingHandlerMapping(请求映射处理器)RequestMappingHandlerAdapter(请求处理适配器)这两个类。RequestMappingHandlerMapping:负责解析带有@ReqeustMapping注解的方法以及类信息,并在请求到达时找到相应的HandlerMethod(一个JavaBean,封装了请求处理方法、参数信息、类信息以及IOC容器等重要的内容)。当找到相应的HandlerMethod后,如果程序中有定义拦截器,那么就会将这个HandlerMethod封装到HandlerExecutionChain的类中,这个类包含了一个拦截器的集合和一个HandlerMethod的对象。最后将这个chain返回给DispatcherServlet。DispatcherServlet从这个HandlerExecutionChain中取出HandlerMethod来匹配相应的HandlerAdapter,找到合适的可以调用HandlerMathod的请求处理适配器。接着DispatcherServlet负责调用HandlerExecutionChain中的所有拦截器中的预处理方法,如果预处理方法没有任何问题,那么就将HandlerMethod交给HandlerAdapter去调用。
RequestMappingHandlerAdapter:DispatcherServlet将HandlerMethod传递给HandlerAdapter,由它负责调用HandlerMethod(也就是目标控制器的方法)。调用时还会使用具体的MethodArgumentResolver(方法参数解析器,RequestMappingHandlerAdapter内部会初始化一系列默认的HandlerMethodArgumentResolver)将请求中的参数解析为请求处理方法所需要的具体类型参数。最后将Controller方法返回的ModelAndView一并返回到DispatcherServlet中。接着DispatcherServlet会继续执行所有拦截器中的后置处理方法。
ViewResolver
springmvc内部提供了许多视图解析器用于解析不同的视图对象,最长见的有InternalResourceViewResolver(内部资源视图解析器)、FreeMarkerViewResolver(模板引擎视图解析器)等。
InternalResourceViewResolver:在DispatcherServlet接收到HandlerAdapter返回的ModelAndView之后,DispatcherServlet将这个ModelAndView交给指定InternalResourceViewResolver来进行视图解析,InternalResourceViewResolver会根据ModelAndView的视图名称来创建一个InternalResourceView的视图对象返回到DispatcherServlet。由DispatcherServlet去调用视图对象的渲染方法来响应视图。在渲染完视图之后,DispatcherServlet会执行所有拦截器中的after方法。
View
视图对象是由相应的视图解析器解析出来的,Spring也提供了不同的视图对象来完成不同的视图响应工作,常见的有的InternalResourceView(内部资源转发视图)等。
InternalResourceView:这个视图对象会将ModeAndView中而外带的数据放入请求作用域,以及获取到拼接好的转发地址。并提供一个renderMergedOutputModel渲染方法由DispatcherServlet调用,这个方法就是负责具体的url转发工作。
配置
maven依赖
<dependencies>
<!-- springmvc依赖,会将spring的核心包一并依赖进来 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.23</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- war插件,用于导出war包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<!-- 设置web.xml的位置 -->
<configuration>
<warSourceDirectory>web</warSourceDirectory>
<webXml>web/WEB-INF/web.xml</webXml>
</configuration>
</plugin>
</plugins>
</build>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 核心请求总控器(DispatcherServlet 中央调度器),负责接收所有的请求,并根据映射的url地址将请求分发给具体控制器的方法来处理-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- springmvc默认会从WEB-INF目录下查找
名为[servletName(自定义)]-servlet.xml的
配置文件,这是spring官方默认的约定命名。
如果想要自定义文件名并且想存放在其他目录下
则需要通过contextConfigLocation初始化参数来配置,
例如:自定义一个springmvc.xml配置文件放在resources
目录下
-->
<!--<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>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
[servletName(自定义)]-servlet.xml
<?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: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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 启用注解扫描-->
<context:component-scan base-package="项目包"/>
<!-- 启用mvc注解处理器。这个注解驱动注册了RequestMappingHandlerMapping(请求映射处理器)和一个RequestMappingHandlerAdapter(请求处理适配器),同时提供了@ReqeustBody、@ResponseBody注解支持、数据绑定等支持 -->
<mvc:annotation-driven/>
<!-- 配置视图解析器,springmvc支持多种视图,不同的视图由不同的视图解析器来解析。
例如:想要使用JSP作为视图,那么就需要配置 InternalResourceViewResolver这个试图解析器,用于解析内部的JSP资源-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置jsp资源的前缀,用于指定jsp存放的目录 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 设置jsp资源的后缀名,以".jsp"结尾的文件-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
请求注解
@RequestMapping
使用的前提是处理器被 Spring容器 管理
在方法上
使用方式:@RequestMapping("/请求")
value 属性为请求,method 属性为请求方式 支持数组@RequestMapping(value = "/请求",method = RequestMethod.请求方式)
@RequestMapping(value = "/请求",method = {RequestMethod.POST,RequestMethod.GET})
在类上
@RequestMapping("/命名空间")
用法是在有多个相同的子请求是用于区分不同的请求,请求格式为(/命名空间/请求
)
接收数据
@RequestParam("")
vaule属性 指定接收数据名字
SpringMVC 4.0提供的子注解(@GetMapping和@PostMapping)
从springmvc4.0开始,提供了新的子注解来替换@ReqeustMapping
不能指定请求方式,可以指定请求路径
因为里面指定了请求方式
响应注解
@ResponseBody
表示将方法返回值,以输出流的方式写回客户端,这样 springmvc 就会将序列化好的 json 数据放入响应体中并写回
@RestController
这个注解是在 spring4.0 后新加入的一个注解,同样用于标注为控制器的组件,如果当前 Controller 中所有请求方法都需要使用 @RestController 注解来响应,那么就可以使用它标注在类上,而不需要在每一个方法上标注 @ResponseBody
静态资源的处理(访问jsp只能转发)
Servlet容器(Tomcat):
DefavltServlet(默认):静态文件的处理
JspServlet:JSP的引擎
自定义Servlet(继承HttpServlet):处理 Http 请求
为什么需要配置静态资源,因为核心控制器(使用/
或者/*
的情况)对所有请求(静态资源)进行了拦截
而核心控制器并没有对静态资源进行解析,对 DefavltServlet 进行了覆盖
自定义Servlet 优先级最高,自定义Servlet 又没有处理静态资源
两种解决方式
- 将静态资源交由给容器的默认Servlet来处理,SpringMVC不参与解析,常见的 Servlet 的容器如Tomcat、Jetty等都会有一个自带的DefaultServlet了处理这些静态资源
<mvc:default-servlet-handler/>
- 静态资源由 SpringMVC 自己来处理
mapping 属性:用于映射静态资源的虚拟url
location 属性:用于指定静态资源的本地相对路径
例如:下面的配置中,当以page为开头的所有请求,都会映射到 static 这个目录中去查找相应的静态资源文件<mvc:resources mapping="/page/**" location="/static/"/>
笔记
视图响应