Files
rikako-note/spring/Spring core/SpringMVC.md
wu xiangkai bc069d1211 日常提交
2022-11-18 11:05:50 +08:00

94 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SpringMVC
## SpringMVC简介
SpringMVC是一款基于Servlet API的web框架并基于前端控制器的模式被设计。前端控制器有一个中央的控制器DispatcherServlet通过一个共享的算法来集中分发请求请求实际是通过可配置的委托组件@Controller类)来处理的。
> Spring Boot遵循不同的初始化流程。相较于hooking到servlet容器的生命周期中Spring Boot使用Spring配置来启动其自身和内置servlet容器。filter和servlet声明在在spring配置中被找到并且被注入到容器中。
## DispatcherServlet
### Context层次结构
DispatcherServlet需要一个WebApplicationContextApplicationContext的拓展类Spirng容器来进行配置。WebApplicationContext拥有一个指向ServletContext和与ServletContext关联Servlet的链接。
**同样的也可以通过ServeltContext来获取关联的ApplicationContext可以通过RequestContextUtils中的静态方法来获取ServletContext关联的ApplicationContext。**
#### WebApplicationContext的继承关系
对大多数应用含有一个WebApplicationContext就足够了。也可以存在一个Root WebApplicationContext在多个DispatcherServlet实例之间共享同时DispatcherServlet实例也含有自己的WebApplicationContext。
通常被共享的root WebApplicationContext含有repository或service的bean对象这些bean对象可以被多个DispatcherServlet实例的子WebApplicationContext共享。同时子WebApplicationContext在继承root WebApplicationContext中bean对象的同时还能对root WebApplicationContext中的bean对象进行覆盖。
> #### WebApplicationContext继承机制
> 只有当Servlet私有的子WebApplicationContext中没有找到bean对象时才会从root WebApplicationContext中查找bean对象此行为即是对root WebApplicationContext的继承
### Spring MVC中特殊的bean类型
DispatcherServlet将处理请求和渲染返回的工作委托给特定的bean对象。Spring MVC中核心的bean类型如下。
#### HandlerMapping
将请求映射到handler和一系列用于pre/post处理的拦截器。
#### HandlerAdapter
HandlerAdapter主要是用于帮助DispatcherServlet调用request请求映射到的handler对象。
通常在调用含有注解的controller时需要对注解进行解析而HandlerAdapter可以向DispatcherServlet隐藏这些细节DispatcherServlet不必关心handler是如何被调用的。
#### HandlerExceptionResolver
解析异常的策略可能将异常映射到某个handler或是映射到html error页面。
#### ViewResolver
将handler返回的基于字符串的view名称映射到一个特定的view并通过view来渲染返回的响应。
### Web MVC Config
在应用中可以定义上小节中包含的特殊类型bean对象。DispatcherServlet会检查WebApplicationContext中存在的特殊类型bean对象如果某特殊类型的bean对象在容器中不存在那么会存在一个回滚机制使用DispatcherServlet.properties中默认的bean类型来创造bean对象例如DispatcherServlet.properties中指定的默认HandlerMapping类型是 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping和org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.)。
### Servlet Config
在Servlet环境中可以选择通过java代码的方式或者web.xml的方式来配置servlet容器。
配置Servlet的详细方式参照Spring MVC文档。
### 请求处理过程
DispatcherServlet按照如下方式来处理Http请求
1. 首先会找到WebApplicationContext并且将其绑定到请求中此后controller和其他元素在请求处理的过程中可以使用该WebApplicationContext。**默认情况下WebApplicationContext被绑定到DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE属性中**
2. locale resolver被绑定到请求中在请求处理过程中可以被其他元素使用
3. theme resolver被绑定到请求中在请求处理过程中可以被其他元素使用
4. 如果指定了multipart file resolver请求会被检查是否存在multipart。如果multipart被找到该请求会被包装在一个MultipartHttpServletRequest中并等待对其进行进一步的处理
5. 一个合适的handler将会被找到并且和该handler相关联的execution chainpre/post/Controller)会被执行返回一个model用于渲染。
6. 如果model被返回那么返回的model会被渲染。如果model没有返回那么没有view会被渲染。
在WebApplicationContext中声明的HandlerExceptionResolver会用于解析处理请求中抛出的异常。
### 路径匹配
Servlet API将完整的请求路径暴露为requestURI并且进一步划分requestURI为如下部分contextPathservletPathpathInfo。
> #### contextPath, servletPath, pathInfo区别
> - contextPathcontextPath为应用被访问的路径是整个应用的根路径。默认情况下SpringBoot的contextPath为"/"。可以通过server.servlet.context-path="/demo"来改变应用的根路径。
> - servletPathservletPath代表main DispatcherServlet的路径。默认情况下servletPath的值仍为"/"。可以通过spring.mvc.servlet.path来自定义该值。
### Interception
所有HandlerMapping的实现类都支持handler interceptor当想要为特定请求执行指定逻辑时会相当有用。拦截器必须要实现HandlerInterceptor该接口提供了三个方法
- preHandle在实际handler处理之前
- postHandle在 实际handler处理之后
- afterCompletion在请求完成之后
#### preHandle
preHandle方法会返回一个boolean值可以通过指定该方法的返回值来阻止执行链继续执行。当preHandle的返回值是true时后续执行链会继续执行当返回值是false时DispatcherServlet会假设该拦截器本身已经处理了请求并不会继续执行execution chain中的其他拦截器和实际handler。
#### postHandle
对于@ResponseBody或返回值为ResponseEntity的方法postHandle不起作用这些方法在HandlerAdapter中已经写入且提交了返回响应时间位于postHandle之前。到postHandle方法执行时已经无法再对响应做任何修改如添加header也不再被允许。对于这些场景可以**实现ResponseBodyAdvice或者声明一个ControllerAdvice**。
#### afterCompletion
调用时机位于DispaterServlet渲染view之后。
### Exceptions
如果异常在request mapping过程中被抛出或者从request handler中被抛出DispatcherServlet会将改异常委托给HandlerExceptionResolver chain来处理通常是返回一个异常响应。
如下是可选的HandlerExceptionResolver实现类
1. SimpleMappingExceptionResolver一个从exception class name到error view name的映射用于渲染错误页面
2. DefaultHandlerExceptionResolver解析Spring MVC抛出的异常并且将它们映射为Http状态码
3. ResponseStatusExceptionResolver通过@ResponseStatus注解来指定异常的状态码并且将异常映射为Http状态码状态码的值为@ResponseStatus注解指定的值
4. ExceptionHandlerExceptionResolver通过@Controller类内@ExceptionHandler方法或@ControllerAdvice类来解析异常
#### Resolver Chain
可以声明多个HandlerExceptionResolver bean对象来声明一个Exception Resolver链并可以通过指定order属性来指定resolver chain中的顺序order越大resolver在链中的顺序越靠后。
#### exception resolver的返回规范
HandlerExceptionResolver返回值可以按照如下规范返回
- 一个指向ModelAndView的error view
- 一个空的ModelAndView代表异常已经在该Resolver中被处理
- null代表该exception仍未被解析resolver chain中后续的resolver会继续尝试处理该exception如果exception在chain的末尾仍然存在该异常会被冒泡到servlet container中
#### container error page
如果exception直到resolver chain的最后都没有被解析或者response code被设置为错误的状态码如4xx,5xx)servlet container会渲染一个默认的error html page。
### 视图解析
#### 处理
类似于Exception Resolver也可以声明一个view resolver chain并且可以通过设置order属性来设置view resolver在resolver chain中的顺序。
view resolver返回null时代表该view无法被找到。
#### 重定向
以“redirect”前缀开头的view name允许执行重定向redirect之后指定的是重定向的url。
```shell
# 重定向实例如下
# 1. 基于servlet context重定向
redirect:/myapp/some/resource
# 2. 基于绝对路径进行重定向
redirect:https://myhost.com/some/arbitrary/path
```
> 如果controller的方法用@ResponseStatus注解标识该注解值的优先级**高于**RedirectView返回的response status。
#### 转发
以“forward”前缀开头的view name会被转发。