什么是SpringMVC?
SpringMVC是什么?
SpringMVC可以帮助我们完成那些功能?
SpringMVC快速开始
Idea环境快速搭建请参考:blog.csdn.net/m0_50370837…
所需要的Maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
HelloWorld
1、创建Controller
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(){
System.out.println("hello 请求被请求到了...");
return "/pages/success.jsp";
}
}
2、配置spring的配置类
<?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"
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">
<!--配置包扫描-->
<context:component-scan base-package="com.myspringmvc"></context:component-scan>
</beans>
3、配置web.xml
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!--
/ 拦截所有的请求 不包含jsp页面
/* 拦截所有的请求 包含jsp页面
要知道处理 *.jsp是tomcat做的事,所有的小web.xml 都是要继承大的web.xml
大web.xml文件中的defaultServlet是处理静态资源的,
这个时候如果我们在springMVC中的web.xml再次写 /的时候就相当于重写了 大web.xml中的 / ,
这个时候我们就不能访问到一些静态资源
-->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--init-param 设置SpringMVC 初始化参数 -->
<init-param>
<!-- param-name 指定springMVC配置文件的位置 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
servlet启动加载 Servlet原本是启动的时候加载
load-on-startup 服务启动的时候创建对象,设置的值越小,优先级越高
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!--
/* 和 / 都是拦截所有请求
/ 拦截所有的请求,但是不会拦截jsp页面
/* 拦截的范围更广 还会拦截.jsp页面
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
4、写页面
5、测试
可以看到Controller里面的返回字符写着比较麻烦,接下来可以在Spring的配置文件中做一些配置,可以简化写法:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
修改Controller里面的请求
执行测试
@RequestMapping注解
@RequestMapping标注的位置
@RequestMapping标注在类上面:设置映射请求的请求路径的初始请求路径信息
@RequestMapping(value = "/method")
public class ClassName{}
@RequestMapping标注在方法上面:设置映射请求请求路径的具体信息
@RequestMapping("/method")
public String methodName(){}
@RequestMapping可选属性
value属性: 规定请求的路径
@RequestMapping(value = "/method")
method属性: 规定请求的方法
@RequestMapping(value = "/method",method = RequestMethod.GET)
params属性: 规定请求的参数信息
@RequestMapping注解的params属性通过请求的请求参数匹配请求映射
@RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系
"param":要求请求映射所匹配的请求必须携带param请求参数
"!param":要求请求映射所匹配的请求必须不能携带param请求参数
"param=value":要求请求映射所匹配的请求必须携带param请求参数且param=value
"param!=value":要求请求映射所匹配的请求必须携带param请求参数但是param!=value
params支持一些表达式
@RequestMapping(value = "/method",method = RequestMethod.GET,params = {"参数规则"})
headers属性: 规定请求的头部信息
@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射
@RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系
"header":要求请求映射所匹配的请求必须携带header请求头信息
"!header":要求请求映射所匹配的请求必须不能携带header请求头信息
"header=value":要求请求映射所匹配的请求必须携带header请求头信息且header=value
"header!=value":要求请求映射所匹配的请求必须携带header请求头信息且header!=value
若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面显示404错误,即资源未找到
@RequestMapping(headers = {"请求头规则"})
SpringMVC支持ant风格的路径
?:表示任意的单个字符
*:表示任意的0个或多个字符,和一层的路径
**:表示任意的一层或多层目录
注意:在使用时,只能使用//xxx的方式
MVC获取请求路径上面的参数
@RequestParam注解
案例演示:
1、准备一个新的Controller
@Controller
@RequestMapping("/requestParam")
public class RequestParamController {
@RequestMapping("requestParamHello")
public String requestParam(@RequestParam("name")String name){
System.out.println("RequestParam:" + name);
return "success";
}
}
2、前端JSP页面
<%--
Created by IntelliJ IDEA.
User: niuxiaocong
Date: 2022/4/28
Time: 11:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--演示RequestParams--%>
<a href="requestParam/requestParamHello?name=niuxiaoniu">requestParamHello</a>
</body>
</html>
3、测试演示
注意点:
如果说没有传递这个参数会报400的错误.
@RequestParam是将请求参数和控制器方法的形参创建映射关系
@RequestParam注解一共有三个属性:
value:指定为形参赋值的请求参数的参数名
required:设置是否必须传输此请求参数,默认值为true
若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter 'xxx' is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null
defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时,则使用默认值为形参赋值
@RequestHeader,@CookieValue这两个注解的使用方式和@RequestParam一样
@PathVariable注解
案例演示:
1、准备Controller
@Controller
@RequestMapping("/pathVariableController")
public class PathVariableController {
@RequestMapping("pathVariableControlle/{userId}")
public String pathVariableController(@PathVariable("userId")String userId){
System.out.println("userId : " + userId);
return "success";
}
}
2、准备前端页面
<%--
Created by IntelliJ IDEA.
User: niuxiaocong
Date: 2022/4/28
Time: 11:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--演示pathVariable--%>
<a href="pathVariableController/pathVariableControlle/2204017228">pathVariable</a>
</body>
</html>
执行结果:
可以看到这个注解的几个可选值。和 @RequestParam 是相同的,他们的作用也大同小异。
@RequestHeader注解
案例演示:
1、 准备一个Controller
@RequestMapping("/header")
@Controller
public class RequestHeaderController {
@RequestMapping("requestHeaderApp")
public String requestHeaderApp(@RequestHeader("User-Agent") String userAgent){
System.out.println("userAgent"+userAgent);
return "success";
}
}
2、前端请求信息
3、请求测试
RequestHeader注解里面的参数列表,他的作用和以上的两个注解类似,这里就不在多说。
@CookieValue注解
1、准备一个CookieServlet
@Controller
@RequestMapping("/cookieValue")
public class CookieValueController {
@RequestMapping("cookie")
public String getCookie(@CookieValue("JSESSIONID") String cookieStr){
System.out.println("cookieStr : "+cookieStr);
return "success";
}
}
2、准备一个前端页面
3、准备测试
@CookieValue注解内部的可选参数
解决请求响应乱码问题
GET请求乱码问题解决方案
修改server.xml 在8080端口的位置上添加上URIEncoding="UTF-8"
这个方案是用来解决POST请求乱码问题,这个配置是在Web.xml中的
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--设置解决请求乱码-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--设置解决响应乱码-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
REST 风格的请求方式
REST风格是什么?
REST:即 Representational State Transfer。 (资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用
资源(Resources ) :网络上的一个实体,或者说是网络上的一个具体信息。 它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。 可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。 获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。
表现层(Representation ) :把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
状态转化(State Transfer ) :每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET 、POST 、PUT 、DELETE 。 它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
案例演示:
准备一个RestController
@RequestMapping("/restOpr")
@Controller
public class RestController {
@DeleteMapping("delOpr")
public String delOpr(){
System.out.println("执行了删除操作~~~");
return "success";
}
@PutMapping("putOpr")
public String putOpr(){
System.out.println("执行了更新操作~~~");
return "success";
}
@GetMapping("getOpr")
public String queryOpr(){
System.out.println("执行了查询操作~~~");
return "success";
}
@PostMapping("addOpr")
public String addOpr(){
System.out.println("执行了添加操作~~~");
return "success";
}
}
2、准备前端页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="hello">请求HelloWorld</a>
<br>
<%--演示RequestParams--%>
<a href="requestParam/requestParamHello">requestParamHello</a>
<br>
<%--演示pathVariable--%>
<a href="pathVariableController/pathVariableControlle/2204017228">pathVariable</a>
<br>
<%--演示Rest风格的请求方式--%>
<a href="restOpr/getOpr">查询</a>
<form action="restOpr/addOpr" method="post">
<input type="submit" value="添加">
</form>
<form action="restOpr/delOpr" method="post">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="删除">
</form>
<form action="restOpr/putOpr" method="post">
<input type="hidden" name="_method" value="put">
<input type="submit" value="更新">
</form>
</body>
</html>
请求测试:
注意因为浏览器只可以发送get 和 Post 请求,如果想要认识其他类型的请求,需要在web.xml中做以下的配置。
<!--用来处理除了get 和 post 以外的请求方式-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
同时在页面上要使用如下的方式。
在HiddenHttpMethodFilter源码中可以看到如下内容
数据输出
Model
Map
ModelMap
视图解析器
数据绑定
数据校验
拦截器
SpringMVC 提供了拦截器机制,允许在目标方法之前及逆行一些拦截工作,或者目标方法运行之后进行一些其他的处理。拦截器的接口名字是HandlerInterceptor
这个接口下面主要有三个方法、preHandle、postHandle、afterCompletion
演示案例:创建一个maven工程springmvc-02
1、配置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">
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--init-param 设置SpringMVC 初始化参数 -->
<init-param>
<!-- param-name 指定springMVC配置文件的位置 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2、配置spring的配置
<?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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="com.intercepter"></context:component-scan>
<!--配置视图解析器-->
<bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:interceptors>
<!--配置某个拦截器:默认是拦截所有的请求-->
<!--<bean class="com.intercepter.mvc.FirestIntercepter"></bean>-->
<!--配置拦截器更详细的信息-->
<mvc:interceptor>
<mvc:mapping path="/hello-intercepter"></mvc:mapping>
<bean class="com.intercepter.mvc.FirestIntercepter"></bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
3、实现拦截器
public class FirestIntercepter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle execuate.....");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle execuate.....");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion execuate.....");
}
}
4、写一个测试页面
5、写一个测试请求
@Controller
public class IntercepterHelloController {
@RequestMapping("/hello-intercepter")
public String HelloIntercepter(){
System.out.println("请求方法执行了");
return "success";
}
}
6、执行这个请求
根据这个执行结果可以知道
preHandle: 执行在目标方法之前,这个方法有一个返回值,如果返回false证明不放行,返回true则放行拦截器。
postHandle:执行在目标方法之后
afterHandle:在页面加载之后执行,只要preHandle放行这个方法总会执行。
多个拦截器的执行流程
重新创建一个TwoIntercepter拦截器并进行注册
public class TwoIntercepter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle Two execuate.....");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle Two execuate.....");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion Two execuate.....");
}
}
注册第二个拦截器
执行结果
遇到的一个bug
报错信息:
cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'mvc:annotation-driven' 的声明
解决方案:添加如下的头部信息
<?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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
</beans>
异常处理
创建一个新的model用来做异常的演示。创建的过程和上面过程类似。
局部异常处理
1、创建出来一个异常的演示类
@Controller
public class ExceptionTest {
@RequestMapping(value = "/handlerException")
public String exceptionHello(){
int i = 10/0;
System.out.println("执行了这个方法");
return "success";
}
@ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
public ModelAndView handlerException(Exception ex){
System.out.println("执行了异常处理器......");
ModelAndView mv = new ModelAndView("error");
mv.addObject("ex",ex);
return mv;
}
}
2、创建异常的页面
3、执行测试
全局异常处理
1、创建全局异常的处理类
//一定要添加@ControllerAdvice这个注解
@ControllerAdvice
public class MyComponentException {
@ExceptionHandler(value = {ArithmeticException.class})
public ModelAndView handlerException(Exception exception){
System.out.println(exception);
System.out.println("执行了全局算数异常处理器......");
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("ex",exception);
return modelAndView;
}
@ExceptionHandler(value = {NullPointerException.class})
public ModelAndView handlerNullPointerException(Exception exception){
System.out.println(exception);
System.out.println("执行了全局空指针异常处理器......");
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("ex",exception);
return modelAndView;
}
}
2、添加一个空指针的方法
@Controller
public class ExceptionTest {
@RequestMapping(value = "/handlerException")
public String exceptionHello(){
int i = 10/0;
System.out.println("执行了这个方法");
return "success";
}
@RequestMapping(value = "/handlerNullPointException")
public String exceptionNullPoint(){
Integer i = null;
i.equals(1);
System.out.println("执行了这个方法");
return "success";
}
}
3、运行测试
要注意哦:在局部异常和全局一异常同时存在的情况下,首先执行局部的异常哦
文件上传下载
DispatServlet 请求流程分析
关系继承树
DispatServlet 核心源码
@SuppressWarnings("deprecation")
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//1、检查是否是文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//2、根据当前的请求找到那个处理器可以处理当前的请求
mappedHandler = getHandler(processedRequest);
//3、如果没有找到那个请求可以处理,就抛404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 4、拿到能执行这个类的所有方法的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//5、使用适配器执行目标方法,将目标方法执行完成后的返回值作为视图名,保存在ModelAndView中
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
1、所有请求过来的DispatchServlet收到请求。
2、调用doDispatch()方法进行处理
2.1、getHandler():根据当前的请求地址找到能够处理这个请求的目标处理器类。
2.2、getHandlerAdapter():根据当前处理器类获取到能执行这个处理器方法的适配器。
2.3、使用方才获取到的适配器执行目标方法。
2.4、在目标方法执行完毕以后会返回一个ModelAndView
2.5、根据ModelAndView的信息转发到具体的页面,并可以在请求域中取出ModelAndView中的模型数据。
getHandler细节:
返回目标方法的处理器类的执行链
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
getHandlerAdapter()细节:
找到能够处理目标处理器的适配器,要拿适配器才去执行目标方法。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
执行流程小总结:
1. 用户通过浏览器发起 HttpRequest 请求到前端控制器 (DispatcherServlet)。
2. DispatcherServlet 将用户请求发送给处理器映射器 (HandlerMapping)。
3. 处理器映射器 (HandlerMapping)会根据请求,找到负责处理该请求的处理器,并将其封装为处理器执行链 返回 (HandlerExecutionChain) 给 DispatcherServlet
4. DispatcherServlet 会根据 处理器执行链 中的处理器,找到能够执行该处理器的处理器适配器(HandlerAdaptor) --注,处理器适配器有多个
5. 处理器适配器 (HandlerAdaptoer) 会调用对应的具体的 Controller
6. Controller 将处理结果及要跳转的视图封装到一个对象 ModelAndView 中并将其返回给处理器适配器 (HandlerAdaptor)
7. HandlerAdaptor 直接将 ModelAndView 交给 DispatcherServlet ,至此,业务处理完毕
8. 业务处理完毕后,我们需要将处理结果展示给用户。于是DisptcherServlet 调用 ViewResolver,将 ModelAndView 中的视图名称封装为视图对象
9. ViewResolver 将封装好的视图 (View) 对象返回给 DIspatcherServlet
10. DispatcherServlet 调用视图对象,让其自己 (View) 进行渲染(将模型数据填充至视图中),形成响应对象 (HttpResponse)
11. 前端控制器 (DispatcherServlet) 响应 (HttpResponse) 给浏览器,展示在页面上。
九个组件
九个组件在SprinMVC3.2.20版本中九个组件的初始化都是通过反射来进行获取的
待更新......