Spring MVC的请求处理流程,配置文件中字段说明,示例演示说明@Controller和@RequestMapping注解的使用。
1.Spring MVC请求处理流程图
(图片及步骤来自:)
第一步:用户发送请求到前端控制器(DispatcherServlet)。
第二步:前端控制器请求 HandlerMapping 查找 Handler,可以根据 xml 配置、注解进行查找。
第三步: 处理器映射器 HandlerMapping 向前端控制器返回 Handler
第四步:前端控制器调用处理器适配器去执行 Handler
第五步:处理器适配器执行 Handler
第六步:Handler 执行完成后给适配器返回 ModelAndView
第七步:处理器适配器向前端控制器返回 ModelAndView
ModelAndView 是SpringMVC 框架的一个底层对象,包括 Model 和 View
第八步:前端控制器请求试图解析器去进行视图解析
根据逻辑视图名来解析真正的视图。
第九步:试图解析器向前端控制器返回 view
第十步:前端控制器进行视图渲染
就是将模型数据(在 ModelAndView 对象中)填充到 request 域
第十一步:前端控制器向用户响应结果
上图中一些组件的解释:
1)前端控制器DispatcherServlet(不需要程序员开发)。
作用:接收请求,响应结果,相当于转发器,中央处理器。有了DispatcherServlet减少了其它组件之间的耦合度。
2)处理器映射器HandlerMapping(不需要程序员开发)。
作用:根据请求的url查找Handler。
3)处理器适配器HandlerAdapter(不需要程序员开发)。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler。
4)处理器Handler(或者Controller,需要程序员开发)。
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
5)视图解析器ViewResolver(不需要程序员开发)。
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
6)视图View(需要程序员开发jsp)。
注意:View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
ps:不需要程序员开发的,做一下配置即可,相关配置如下。
2. Spring MVC相关组件的配置
1).配置web.xml中的前端控制器(DispatcherServlet)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>DisposalSludgeSystem</display-name>
<!-- 配置前端控制器DispatcherServlet -->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--如果不配置 contextConfigLocation,那么默认加载的是/WEB-INF/<servlet-name>-servlet.xml,在这里即为mvc-dispatcher-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-*.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<!--第一种配置:*.do,还可以写*.action等等,表示以.do结尾的或者以.action结尾的URL都由前端控制器DispatcherServlet来解析。
第二种配置:/,表示所有访问的URL都由DispatcherServlet来解析-->
<url-pattern>*.do</url-pattern> <!--或者配置成 <url-pattern>/</url-pattern>-->
</servlet-mapping>
</web-app>
2).配置spring-web.xml(或springmvc.xml)中的 处理器适配器(HandlerAdapter)(本例中没有配置)
<!-- 配置处理器适配器第一种方法,所有适配器都得实现 HandlerAdapter接口 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<!-- 配置处理器适配器第二种方法,所有适配器都得实现 HandlerAdapter接口 ,这样配置所有Handler都得实现 HttpRequestHandler接口-->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
3).配置spring-web.xml(或springmvc.xml)中的处理器映射器(HandlerMapping)(本例中没有配置)
第一种方法:
<!-- 配置Handler -->
<bean name="/Anmy.do" class="com.ys.controller.HelloController2" />
<!-- 配置处理器映射器,将bean的name作为url进行查找,需要在配置Handler时指定bean name(就是url)-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
这样配置的话,那么请求的 URL,必须为 http://localhost:8080/项目名/Anmy.do
第二种方法:
<!-- 配置Handler -->
<bean id="Anmy1" class="com.ys.controller.HelloController" />
<bean id="Anmy2" class="com.ys.controller.HelloController" />
<!-- 第二种方法:简单URL配置处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/Anmy1.do">Anmy1</prop>
<prop key="/Anmy2.do">Anmy2</prop>
</props>
</property>
</bean>
这种配置请求的 URL可以为 http://localhost:8080/项目名/Anmy1.do,或者http://localhost:8080/项目名/Anmy2.do
4).Spring-web.xml中配置视图解析器(ViewResolver)
<!-- 定义视图解析器 进行jsp解析,默认使用jstl标签,classpath下得有jstl的包-->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--返回视图页面的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--返回页面的后缀,veiw层由jsp实现 -->
<property name="suffix" value=".jsp"/>
</bean>
若采用这种方式配置:在 Handler 中只需要返回在 view 文件夹下的jsp 页面名就可以了。无需返回 路径+名称+’.jsp’
- Spring-web.xml配置详解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!--静态资源默认servlet配置,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。
功能:(1)加入对静态资源的处理:js,gif,png,css等 (2)允许使用"/"做整体映射(web.xml中serverlet-mapping部分的url-pattern是"/") -->
<mvc:default-servlet-handler />
<!-- 定义视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--返回视图页面的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!--返回页面的后缀,veiw层由jsp实现 -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 注解处理器映射器-->
<!-- <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> -->
<!-- 注解处理器适配器-->
<!-- <bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> -->
<!-- 使用<mvc:annotation-driven/>可以代替上面的映射器和适配器;会自动注册RequestMappingHandlerMapping和 RequestMappingHandlerAdapter两个bean,这是SpringMVC为@Controllers分发请求所必须的,并提供了数据绑定支持、@NumberFormatannotation支持、@DateTimeFormat支持、@valid支持、读写XML的支持(JAXB)和JSON的支持(默认jackson)等功能。-->
<mvc:annotation-driven />
<!--单个配置Handler -->
<!-- <bean class="com.ys.controller.HelloController"></bean> —>
<!-- 自动扫描controller包中基于注解类型实现的类,根据类自动生成bean,而不用在xml中手动d单个配置bean。即:批量配置Handler,指定扫描的包全称,不用再单个配置Handler -->
<context:component-scan base-package="factory" />
</beans>
注:如果配置中少了上面一些配置,在 SpringMVC 运行之前,会首先加载 DispatcherServlet.properties(位置及内容如下)文件里面的内容
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback(后备) when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver, org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
从上面可以看出,如果我们不手动进行各种配置,DispatcherServlet.properties中也有会默认的配置。
- 处理器适配器默认:org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
- 处理器映射器默认:org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping(将bean的name作为url进行查找,需要在配置Handler时指定bean name(即是url))
- 视图解析器默认:org.springframework.web.servlet.view.InternalResourceViewResolver
3.示例解析
package factory.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Created by ZhangAnmy on 18/9/25.
*/
//使用@Controller注解表示这个类是一个Handler
@Controller
public class AnmyTestController {
//@RequestMapping注解括号里面的内容表示访问的URL
@RequestMapping("Anmy")
public ModelAndView Anmy(){
ModelAndView modelView = new ModelAndView();
modelView.addObject("name","ZhangAnmy");//设置需要返回的值
//配置返回的视图名,由于在spring-web.xml中配置了前缀和后缀,这里直接写视图名即可
modelView.setViewName("index");
//modelView.setViewName("/WEB-INF/jsp/index.jsp");
return modelView;
}
}
index.jsp内容(/WEB-INF/jsp/index.jsp)
<%--
Created by IntelliJ IDEA.
User: ZhangAnmy
Date: 18/9/25
Time: 16:54
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Anmy test page</title>
</head>
<body>
Welcome, ${name} ^_^^_^
</body>
</html>
启动项目,在浏览器中输入“localhost:8080/项目名/Anmy” 即可看到Handler中设置的name值
以下为启动日志信息:红色部分可以看出系统的初始化过程及加载顺序
--------------------------------------------------------------------------------------------------
[2018-09-25 07:52:49,982] Artifact DisposalSludgeSystem:war exploded: Artifact is being deployed, please wait...
25-Sep-2018 19:52:55.018 信息 [RMI TCP Connection(2)-127.0.0.1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
[2018-09-25 07:52:55,250] Artifact DisposalSludgeSystem:war exploded: Artifact is deployed successfully
[2018-09-25 07:52:55,250] Artifact DisposalSludgeSystem:war exploded: Deploy took 5,268 milliseconds
25-Sep-2018 19:52:56.377 信息 [http-nio-8080-exec-1] org.springframework.web.servlet.DispatcherServlet.initServletBean FrameworkServlet 'mvc-dispatcher': initialization started
25-Sep-2018 19:52:56.414 信息 [http-nio-8080-exec-1] org.springframework.web.context.support.XmlWebApplicationContext.prepareRefresh Refreshing WebApplicationContext for namespace 'mvc-dispatcher-servlet': startup date [Tue Sep 25 19:52:56 CST 2018]; root of context hierarchy
25-Sep-2018 19:52:56.486 信息 [http-nio-8080-exec-1] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions Loading XML bean definitions from file [/Users/macbook/Documents/.../DisposalSludgeSystem/WEB-INF/classes/spring/spring-dao.xml] //spring-dao.xml中引入了database.properties,database.properties中配置了c3p0连接池及其相关属性
25-Sep-2018 19:52:57.038 信息 [http-nio-8080-exec-1] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions Loading XML bean definitions from file [/Users/macbook/Documents/.../DisposalSludgeSystem/WEB-INF/classes/spring/spring-service.xml]
25-Sep-2018 19:52:57.212 信息 [http-nio-8080-exec-1] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions Loading XML bean definitions from file [/Users/macbook/Documents/.../DisposalSludgeSystem/WEB-INF/classes/spring/spring-web.xml]
25-Sep-2018 19:52:58.368 信息 [http-nio-8080-exec-1] org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.loadProperties Loading properties file from class path resource [spring/database.properties]
25-Sep-2018 19:52:58.500 信息 [http-nio-8080-exec-1] com.mchange.v2.log.MLog.<clinit> MLog clients using java 1.4+ standard logging.
25-Sep-2018 19:52:58.546 信息 [http-nio-8080-exec-1] com.mchange.v2.c3p0.C3P0Registry.banner Initializing c3p0-0.9.1.2 [built 21-May-2007 15:04:56; debug? true; trace: 10]
25-Sep-2018 19:52:59.553 信息 [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/Users/macbook/.../apache-tomcat-9.0.8/webapps/manager]
25-Sep-2018 19:52:59.598 信息 [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/macbook/.../apache-tomcat-9.0.8/webapps/manager] has finished in [43] ms
...
25-Sep-2018 19:53:11.723 信息 [http-nio-8080-exec-1] org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod Mapped "{[/Anmy]}" onto public org.springframework.web.servlet.ModelAndView factory.controller.AnmyTestController.Anmy()
...
25-Sep-2018 19:53:34.781 信息 [http-nio-8080-exec-1] org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.initControllerAdviceCache Looking for @ControllerAdvice: WebApplicationContext for namespace 'mvc-dispatcher-servlet': startup date [Tue Sep 25 19:52:56 CST 2018]; root of context hierarchy
25-Sep-2018 19:53:40.359 信息 [http-nio-8080-exec-1] org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.initControllerAdviceCache Looking for @ControllerAdvice: WebApplicationContext for namespace 'mvc-dispatcher-servlet': startup date [Tue Sep 25 19:52:56 CST 2018]; root of context hierarchy
25-Sep-2018 19:53:47.789 信息 [http-nio-8080-exec-1] org.springframework.web.servlet.handler.SimpleUrlHandlerMapping.registerHandler Mapped URL path [/**] onto handler 'org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0'
25-Sep-2018 19:54:06.301 信息 [http-nio-8080-exec-1] org.springframework.web.servlet.DispatcherServlet.initServletBean FrameworkServlet 'mvc-dispatcher': initialization completed in 69923 ms
--------------------------------------------------------------------------------------------------
类DispatcherServlet继承自类FrameworkServlet,FrameworkServlet类中有initServletBean()方法进行初始化,加载配置文件等。源码如下图:
源码部分还待仔细研究分析,待后续补充完善,今天就到这吧^_^^_^